1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56#include <linux/module.h>
57
58#include <linux/fd.h>
59#include <linux/hdreg.h>
60#include <linux/delay.h>
61#include <linux/init.h>
62#include <linux/amifdreg.h>
63#include <linux/amifd.h>
64#include <linux/buffer_head.h>
65#include <linux/blkdev.h>
66#include <linux/elevator.h>
67#include <linux/interrupt.h>
68
69#include <asm/setup.h>
70#include <asm/uaccess.h>
71#include <asm/amigahw.h>
72#include <asm/amigaints.h>
73#include <asm/irq.h>
74
75#undef DEBUG
76
77#define RAW_IOCTL
78#ifdef RAW_IOCTL
79#define IOCTL_RAW_TRACK 0x5254524B
80#endif
81
82
83
84
85
86
87
88
89#define FD_OK 0
90#define FD_ERROR -1
91#define FD_NOUNIT 1
92#define FD_UNITBUSY 2
93#define FD_NOTACTIVE 3
94#define FD_NOTREADY 4
95
96#define MFM_NOSYNC 1
97#define MFM_HEADER 2
98#define MFM_DATA 3
99#define MFM_TRACK 4
100
101
102
103
104#define FD_NODRIVE 0x00000000
105#define FD_DD_3 0xffffffff
106#define FD_HD_3 0x55555555
107#define FD_DD_5 0xaaaaaaaa
108
109static unsigned long int fd_def_df0 = FD_DD_3;
110
111module_param(fd_def_df0, ulong, 0);
112MODULE_LICENSE("GPL");
113
114static struct request_queue *floppy_queue;
115#define QUEUE (floppy_queue)
116#define CURRENT elv_next_request(floppy_queue)
117
118
119
120
121#define MOTOR_ON (ciab.prb &= ~DSKMOTOR)
122#define MOTOR_OFF (ciab.prb |= DSKMOTOR)
123#define SELECT(mask) (ciab.prb &= ~mask)
124#define DESELECT(mask) (ciab.prb |= mask)
125#define SELMASK(drive) (1 << (3 + (drive & 3)))
126
127static struct fd_drive_type drive_types[] = {
128
129
130{ FD_DD_3, "DD 3.5", 80, 2, 14716, 13630, 1, 80,161, 3, 18, 1},
131{ FD_HD_3, "HD 3.5", 80, 2, 28344, 27258, 2, 80,161, 3, 18, 1},
132{ FD_DD_5, "DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
133{ FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
134};
135static int num_dr_types = ARRAY_SIZE(drive_types);
136
137static int amiga_read(int), dos_read(int);
138static void amiga_write(int), dos_write(int);
139static struct fd_data_type data_types[] = {
140 { "Amiga", 11 , amiga_read, amiga_write},
141 { "MS-Dos", 9, dos_read, dos_write}
142};
143
144
145static struct amiga_floppy_struct unit[FD_MAX_UNITS];
146
147static struct timer_list flush_track_timer[FD_MAX_UNITS];
148static struct timer_list post_write_timer;
149static struct timer_list motor_on_timer;
150static struct timer_list motor_off_timer[FD_MAX_UNITS];
151static int on_attempts;
152
153
154
155static volatile int fdc_busy = -1;
156static volatile int fdc_nested;
157static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
158
159static DECLARE_WAIT_QUEUE_HEAD(motor_wait);
160
161static volatile int selected = -1;
162
163static int writepending;
164static int writefromint;
165static char *raw_buf;
166
167static DEFINE_SPINLOCK(amiflop_lock);
168
169#define RAW_BUF_SIZE 30000
170
171
172
173
174
175
176static volatile char block_flag;
177static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block);
178
179
180static unsigned char mfmencode[16]={
181 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
182 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
183};
184static unsigned char mfmdecode[128];
185
186
187static volatile int ms_busy = -1;
188static DECLARE_WAIT_QUEUE_HEAD(ms_wait);
189#define MS_TICKS ((amiga_eclock+50)/1000)
190
191
192
193
194
195
196#define MAX_ERRORS 12
197
198#define custom amiga_custom
199
200
201static int fd_ref[4] = { 0,0,0,0 };
202static int fd_device[4] = { 0, 0, 0, 0 };
203
204
205
206
207
208
209
210
211
212static irqreturn_t ms_isr(int irq, void *dummy)
213{
214 ms_busy = -1;
215 wake_up(&ms_wait);
216 return IRQ_HANDLED;
217}
218
219
220
221static void ms_delay(int ms)
222{
223 unsigned long flags;
224 int ticks;
225 if (ms > 0) {
226 local_irq_save(flags);
227 while (ms_busy == 0)
228 sleep_on(&ms_wait);
229 ms_busy = 0;
230 local_irq_restore(flags);
231 ticks = MS_TICKS*ms-1;
232 ciaa.tblo=ticks%256;
233 ciaa.tbhi=ticks/256;
234 ciaa.crb=0x19;
235 sleep_on(&ms_wait);
236 }
237}
238
239
240
241
242static inline int try_fdc(int drive)
243{
244 drive &= 3;
245 return ((fdc_busy < 0) || (fdc_busy == drive));
246}
247
248static void get_fdc(int drive)
249{
250 unsigned long flags;
251
252 drive &= 3;
253#ifdef DEBUG
254 printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested);
255#endif
256 local_irq_save(flags);
257 while (!try_fdc(drive))
258 sleep_on(&fdc_wait);
259 fdc_busy = drive;
260 fdc_nested++;
261 local_irq_restore(flags);
262}
263
264static inline void rel_fdc(void)
265{
266#ifdef DEBUG
267 if (fdc_nested == 0)
268 printk("fd: unmatched rel_fdc\n");
269 printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);
270#endif
271 fdc_nested--;
272 if (fdc_nested == 0) {
273 fdc_busy = -1;
274 wake_up(&fdc_wait);
275 }
276}
277
278static void fd_select (int drive)
279{
280 unsigned char prb = ~0;
281
282 drive&=3;
283#ifdef DEBUG
284 printk("selecting %d\n",drive);
285#endif
286 if (drive == selected)
287 return;
288 get_fdc(drive);
289 selected = drive;
290
291 if (unit[drive].track % 2 != 0)
292 prb &= ~DSKSIDE;
293 if (unit[drive].motor == 1)
294 prb &= ~DSKMOTOR;
295 ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
296 ciab.prb = prb;
297 prb &= ~SELMASK(drive);
298 ciab.prb = prb;
299 rel_fdc();
300}
301
302static void fd_deselect (int drive)
303{
304 unsigned char prb;
305 unsigned long flags;
306
307 drive&=3;
308#ifdef DEBUG
309 printk("deselecting %d\n",drive);
310#endif
311 if (drive != selected) {
312 printk(KERN_WARNING "Deselecting drive %d while %d was selected!\n",drive,selected);
313 return;
314 }
315
316 get_fdc(drive);
317 local_irq_save(flags);
318
319 selected = -1;
320
321 prb = ciab.prb;
322 prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));
323 ciab.prb = prb;
324
325 local_irq_restore (flags);
326 rel_fdc();
327
328}
329
330static void motor_on_callback(unsigned long nr)
331{
332 if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {
333 wake_up (&motor_wait);
334 } else {
335 motor_on_timer.expires = jiffies + HZ/10;
336 add_timer(&motor_on_timer);
337 }
338}
339
340static int fd_motor_on(int nr)
341{
342 nr &= 3;
343
344 del_timer(motor_off_timer + nr);
345
346 if (!unit[nr].motor) {
347 unit[nr].motor = 1;
348 fd_select(nr);
349
350 motor_on_timer.data = nr;
351 mod_timer(&motor_on_timer, jiffies + HZ/2);
352
353 on_attempts = 10;
354 sleep_on (&motor_wait);
355 fd_deselect(nr);
356 }
357
358 if (on_attempts == 0) {
359 on_attempts = -1;
360#if 0
361 printk (KERN_ERR "motor_on failed, turning motor off\n");
362 fd_motor_off (nr);
363 return 0;
364#else
365 printk (KERN_WARNING "DSKRDY not set after 1.5 seconds - assuming drive is spinning notwithstanding\n");
366#endif
367 }
368
369 return 1;
370}
371
372static void fd_motor_off(unsigned long drive)
373{
374 long calledfromint;
375#ifdef MODULE
376 long decusecount;
377
378 decusecount = drive & 0x40000000;
379#endif
380 calledfromint = drive & 0x80000000;
381 drive&=3;
382 if (calledfromint && !try_fdc(drive)) {
383
384 motor_off_timer[drive].expires = jiffies + 1;
385 add_timer(motor_off_timer + drive);
386 return;
387 }
388 unit[drive].motor = 0;
389 fd_select(drive);
390 udelay (1);
391 fd_deselect(drive);
392}
393
394static void floppy_off (unsigned int nr)
395{
396 int drive;
397
398 drive = nr & 3;
399
400 motor_off_timer[drive].data = nr | 0x80000000;
401 mod_timer(motor_off_timer + drive, jiffies + 3*HZ);
402}
403
404static int fd_calibrate(int drive)
405{
406 unsigned char prb;
407 int n;
408
409 drive &= 3;
410 get_fdc(drive);
411 if (!fd_motor_on (drive))
412 return 0;
413 fd_select (drive);
414 prb = ciab.prb;
415 prb |= DSKSIDE;
416 prb &= ~DSKDIREC;
417 ciab.prb = prb;
418 for (n = unit[drive].type->tracks/2; n != 0; --n) {
419 if (ciaa.pra & DSKTRACK0)
420 break;
421 prb &= ~DSKSTEP;
422 ciab.prb = prb;
423 prb |= DSKSTEP;
424 udelay (2);
425 ciab.prb = prb;
426 ms_delay(unit[drive].type->step_delay);
427 }
428 ms_delay (unit[drive].type->settle_time);
429 prb |= DSKDIREC;
430 n = unit[drive].type->tracks + 20;
431 for (;;) {
432 prb &= ~DSKSTEP;
433 ciab.prb = prb;
434 prb |= DSKSTEP;
435 udelay (2);
436 ciab.prb = prb;
437 ms_delay(unit[drive].type->step_delay + 1);
438 if ((ciaa.pra & DSKTRACK0) == 0)
439 break;
440 if (--n == 0) {
441 printk (KERN_ERR "fd%d: calibrate failed, turning motor off\n", drive);
442 fd_motor_off (drive);
443 unit[drive].track = -1;
444 rel_fdc();
445 return 0;
446 }
447 }
448 unit[drive].track = 0;
449 ms_delay(unit[drive].type->settle_time);
450
451 rel_fdc();
452 fd_deselect(drive);
453 return 1;
454}
455
456static int fd_seek(int drive, int track)
457{
458 unsigned char prb;
459 int cnt;
460
461#ifdef DEBUG
462 printk("seeking drive %d to track %d\n",drive,track);
463#endif
464 drive &= 3;
465 get_fdc(drive);
466 if (unit[drive].track == track) {
467 rel_fdc();
468 return 1;
469 }
470 if (!fd_motor_on(drive)) {
471 rel_fdc();
472 return 0;
473 }
474 if (unit[drive].track < 0 && !fd_calibrate(drive)) {
475 rel_fdc();
476 return 0;
477 }
478
479 fd_select (drive);
480 cnt = unit[drive].track/2 - track/2;
481 prb = ciab.prb;
482 prb |= DSKSIDE | DSKDIREC;
483 if (track % 2 != 0)
484 prb &= ~DSKSIDE;
485 if (cnt < 0) {
486 cnt = - cnt;
487 prb &= ~DSKDIREC;
488 }
489 ciab.prb = prb;
490 if (track % 2 != unit[drive].track % 2)
491 ms_delay (unit[drive].type->side_time);
492 unit[drive].track = track;
493 if (cnt == 0) {
494 rel_fdc();
495 fd_deselect(drive);
496 return 1;
497 }
498 do {
499 prb &= ~DSKSTEP;
500 ciab.prb = prb;
501 prb |= DSKSTEP;
502 udelay (1);
503 ciab.prb = prb;
504 ms_delay (unit[drive].type->step_delay);
505 } while (--cnt != 0);
506 ms_delay (unit[drive].type->settle_time);
507
508 rel_fdc();
509 fd_deselect(drive);
510 return 1;
511}
512
513static unsigned long fd_get_drive_id(int drive)
514{
515 int i;
516 ulong id = 0;
517
518 drive&=3;
519 get_fdc(drive);
520
521 MOTOR_ON;
522 udelay(2);
523 SELECT(SELMASK(drive));
524 udelay(2);
525 DESELECT(SELMASK(drive));
526 udelay(2);
527 MOTOR_OFF;
528 udelay(2);
529 SELECT(SELMASK(drive));
530 udelay(2);
531 DESELECT(SELMASK(drive));
532 udelay(2);
533
534
535 for (i=0; i<32; i++) {
536 SELECT(SELMASK(drive));
537 udelay(2);
538
539
540 id <<= 1;
541 id |= (ciaa.pra & DSKRDY) ? 0 : 1;
542
543 DESELECT(SELMASK(drive));
544 }
545
546 rel_fdc();
547
548
549
550
551
552
553
554 if(drive == 0 && id == FD_NODRIVE)
555 {
556 id = fd_def_df0;
557 printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0);
558 }
559
560 return (id);
561}
562
563static irqreturn_t fd_block_done(int irq, void *dummy)
564{
565 if (block_flag)
566 custom.dsklen = 0x4000;
567
568 if (block_flag == 2) {
569 writepending = 2;
570 post_write_timer.expires = jiffies + 1;
571 post_write_timer.data = selected;
572 add_timer(&post_write_timer);
573 }
574 else {
575 block_flag = 0;
576 wake_up (&wait_fd_block);
577 }
578 return IRQ_HANDLED;
579}
580
581static void raw_read(int drive)
582{
583 drive&=3;
584 get_fdc(drive);
585 while (block_flag)
586 sleep_on(&wait_fd_block);
587 fd_select(drive);
588
589 custom.adkcon = ADK_MSBSYNC;
590 custom.adkcon = ADK_SETCLR|ADK_WORDSYNC|ADK_FAST;
591
592 custom.dsksync = MFM_SYNC;
593
594 custom.dsklen = 0;
595 custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
596 custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
597 custom.dsklen = unit[drive].type->read_size/sizeof(short) | DSKLEN_DMAEN;
598
599 block_flag = 1;
600
601 while (block_flag)
602 sleep_on (&wait_fd_block);
603
604 custom.dsklen = 0;
605 fd_deselect(drive);
606 rel_fdc();
607}
608
609static int raw_write(int drive)
610{
611 ushort adk;
612
613 drive&=3;
614 get_fdc(drive);
615 if ((ciaa.pra & DSKPROT) == 0) {
616 rel_fdc();
617 return 0;
618 }
619 while (block_flag)
620 sleep_on(&wait_fd_block);
621 fd_select(drive);
622
623 custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC;
624
625 adk = ADK_SETCLR|ADK_FAST;
626 if ((ulong)unit[drive].track >= unit[drive].type->precomp2)
627 adk |= ADK_PRECOMP1;
628 else if ((ulong)unit[drive].track >= unit[drive].type->precomp1)
629 adk |= ADK_PRECOMP0;
630 custom.adkcon = adk;
631
632 custom.dsklen = DSKLEN_WRITE;
633 custom.dskptr = (u_char *)ZTWO_PADDR((u_char *)raw_buf);
634 custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
635 custom.dsklen = unit[drive].type->write_size/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
636
637 block_flag = 2;
638 return 1;
639}
640
641
642
643
644
645static void post_write (unsigned long drive)
646{
647#ifdef DEBUG
648 printk("post_write for drive %ld\n",drive);
649#endif
650 drive &= 3;
651 custom.dsklen = 0;
652 block_flag = 0;
653 writepending = 0;
654 writefromint = 0;
655 unit[drive].dirty = 0;
656 wake_up(&wait_fd_block);
657 fd_deselect(drive);
658 rel_fdc();
659}
660
661
662
663
664
665
666
667
668static unsigned long scan_sync(unsigned long raw, unsigned long end)
669{
670 ushort *ptr = (ushort *)raw, *endp = (ushort *)end;
671
672 while (ptr < endp && *ptr++ != 0x4489)
673 ;
674 if (ptr < endp) {
675 while (*ptr == 0x4489 && ptr < endp)
676 ptr++;
677 return (ulong)ptr;
678 }
679 return 0;
680}
681
682static inline unsigned long checksum(unsigned long *addr, int len)
683{
684 unsigned long csum = 0;
685
686 len /= sizeof(*addr);
687 while (len-- > 0)
688 csum ^= *addr++;
689 csum = ((csum>>1) & 0x55555555) ^ (csum & 0x55555555);
690
691 return csum;
692}
693
694static unsigned long decode (unsigned long *data, unsigned long *raw,
695 int len)
696{
697 ulong *odd, *even;
698
699
700 len >>= 2;
701 odd = raw;
702 even = odd + len;
703
704
705 raw += len * 2;
706
707 do {
708 *data++ = ((*odd++ & 0x55555555) << 1) | (*even++ & 0x55555555);
709 } while (--len != 0);
710
711 return (ulong)raw;
712}
713
714struct header {
715 unsigned char magic;
716 unsigned char track;
717 unsigned char sect;
718 unsigned char ord;
719 unsigned char labels[16];
720 unsigned long hdrchk;
721 unsigned long datachk;
722};
723
724static int amiga_read(int drive)
725{
726 unsigned long raw;
727 unsigned long end;
728 int scnt;
729 unsigned long csum;
730 struct header hdr;
731
732 drive&=3;
733 raw = (long) raw_buf;
734 end = raw + unit[drive].type->read_size;
735
736 for (scnt = 0;scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
737 if (!(raw = scan_sync(raw, end))) {
738 printk (KERN_INFO "can't find sync for sector %d\n", scnt);
739 return MFM_NOSYNC;
740 }
741
742 raw = decode ((ulong *)&hdr.magic, (ulong *)raw, 4);
743 raw = decode ((ulong *)&hdr.labels, (ulong *)raw, 16);
744 raw = decode ((ulong *)&hdr.hdrchk, (ulong *)raw, 4);
745 raw = decode ((ulong *)&hdr.datachk, (ulong *)raw, 4);
746 csum = checksum((ulong *)&hdr,
747 (char *)&hdr.hdrchk-(char *)&hdr);
748
749#ifdef DEBUG
750 printk ("(%x,%d,%d,%d) (%lx,%lx,%lx,%lx) %lx %lx\n",
751 hdr.magic, hdr.track, hdr.sect, hdr.ord,
752 *(ulong *)&hdr.labels[0], *(ulong *)&hdr.labels[4],
753 *(ulong *)&hdr.labels[8], *(ulong *)&hdr.labels[12],
754 hdr.hdrchk, hdr.datachk);
755#endif
756
757 if (hdr.hdrchk != csum) {
758 printk(KERN_INFO "MFM_HEADER: %08lx,%08lx\n", hdr.hdrchk, csum);
759 return MFM_HEADER;
760 }
761
762
763 if (hdr.track != unit[drive].track) {
764 printk(KERN_INFO "MFM_TRACK: %d, %d\n", hdr.track, unit[drive].track);
765 return MFM_TRACK;
766 }
767
768 raw = decode ((ulong *)(unit[drive].trackbuf + hdr.sect*512),
769 (ulong *)raw, 512);
770 csum = checksum((ulong *)(unit[drive].trackbuf + hdr.sect*512), 512);
771
772 if (hdr.datachk != csum) {
773 printk(KERN_INFO "MFM_DATA: (%x:%d:%d:%d) sc=%d %lx, %lx\n",
774 hdr.magic, hdr.track, hdr.sect, hdr.ord, scnt,
775 hdr.datachk, csum);
776 printk (KERN_INFO "data=(%lx,%lx,%lx,%lx)\n",
777 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[0],
778 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[1],
779 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[2],
780 ((ulong *)(unit[drive].trackbuf+hdr.sect*512))[3]);
781 return MFM_DATA;
782 }
783 }
784
785 return 0;
786}
787
788static void encode(unsigned long data, unsigned long *dest)
789{
790 unsigned long data2;
791
792 data &= 0x55555555;
793 data2 = data ^ 0x55555555;
794 data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
795
796 if (*(dest - 1) & 0x00000001)
797 data &= 0x7FFFFFFF;
798
799 *dest = data;
800}
801
802static void encode_block(unsigned long *dest, unsigned long *src, int len)
803{
804 int cnt, to_cnt = 0;
805 unsigned long data;
806
807
808 for (cnt = 0; cnt < len / 4; cnt++) {
809 data = src[cnt] >> 1;
810 encode(data, dest + to_cnt++);
811 }
812
813
814 for (cnt = 0; cnt < len / 4; cnt++) {
815 data = src[cnt];
816 encode(data, dest + to_cnt++);
817 }
818}
819
820static unsigned long *putsec(int disk, unsigned long *raw, int cnt)
821{
822 struct header hdr;
823 int i;
824
825 disk&=3;
826 *raw = (raw[-1]&1) ? 0x2AAAAAAA : 0xAAAAAAAA;
827 raw++;
828 *raw++ = 0x44894489;
829
830 hdr.magic = 0xFF;
831 hdr.track = unit[disk].track;
832 hdr.sect = cnt;
833 hdr.ord = unit[disk].dtype->sects * unit[disk].type->sect_mult - cnt;
834 for (i = 0; i < 16; i++)
835 hdr.labels[i] = 0;
836 hdr.hdrchk = checksum((ulong *)&hdr,
837 (char *)&hdr.hdrchk-(char *)&hdr);
838 hdr.datachk = checksum((ulong *)(unit[disk].trackbuf+cnt*512), 512);
839
840 encode_block(raw, (ulong *)&hdr.magic, 4);
841 raw += 2;
842 encode_block(raw, (ulong *)&hdr.labels, 16);
843 raw += 8;
844 encode_block(raw, (ulong *)&hdr.hdrchk, 4);
845 raw += 2;
846 encode_block(raw, (ulong *)&hdr.datachk, 4);
847 raw += 2;
848 encode_block(raw, (ulong *)(unit[disk].trackbuf+cnt*512), 512);
849 raw += 256;
850
851 return raw;
852}
853
854static void amiga_write(int disk)
855{
856 unsigned int cnt;
857 unsigned long *ptr = (unsigned long *)raw_buf;
858
859 disk&=3;
860
861 for (cnt = 0; cnt < 415 * unit[disk].type->sect_mult; cnt++)
862 *ptr++ = 0xaaaaaaaa;
863
864
865 for (cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
866 ptr = putsec (disk, ptr, cnt);
867 *(ushort *)ptr = (ptr[-1]&1) ? 0x2AA8 : 0xAAA8;
868}
869
870
871struct dos_header {
872 unsigned char track,
873 side,
874 sec,
875 len_desc;
876 unsigned short crc;
877
878
879
880 unsigned char gap1[22];
881};
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3)
939{
940 static unsigned char CRCTable1[] = {
941 0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
942 0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3,
943 0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5,
944 0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7,
945 0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9,
946 0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab,
947 0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d,
948 0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f,
949 0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60,
950 0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
951 0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44,
952 0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56,
953 0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28,
954 0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a,
955 0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c,
956 0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e
957 };
958
959 static unsigned char CRCTable2[] = {
960 0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
961 0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde,
962 0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d,
963 0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc,
964 0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b,
965 0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a,
966 0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49,
967 0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78,
968 0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67,
969 0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56,
970 0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05,
971 0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34,
972 0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3,
973 0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92,
974 0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1,
975 0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0
976 };
977
978
979 register int i;
980 register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl;
981
982 CRCT1=CRCTable1;
983 CRCT2=CRCTable2;
984 data=data_a3;
985 crcl=data_d1;
986 crch=data_d0;
987 for (i=data_d3; i>=0; i--) {
988 c = (*data++) ^ crch;
989 crch = CRCT1[c] ^ crcl;
990 crcl = CRCT2[c];
991 }
992 return (crch<<8)|crcl;
993}
994
995static inline ushort dos_hdr_crc (struct dos_header *hdr)
996{
997 return dos_crc(&(hdr->track), 0xb2, 0x30, 3);
998}
999
1000static inline ushort dos_data_crc(unsigned char *data)
1001{
1002 return dos_crc(data, 0xe2, 0x95 ,511);
1003}
1004
1005static inline unsigned char dos_decode_byte(ushort word)
1006{
1007 register ushort w2;
1008 register unsigned char byte;
1009 register unsigned char *dec = mfmdecode;
1010
1011 w2=word;
1012 w2>>=8;
1013 w2&=127;
1014 byte = dec[w2];
1015 byte <<= 4;
1016 w2 = word & 127;
1017 byte |= dec[w2];
1018 return byte;
1019}
1020
1021static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len)
1022{
1023 int i;
1024
1025 for (i = 0; i < len; i++)
1026 *data++=dos_decode_byte(*raw++);
1027 return ((ulong)raw);
1028}
1029
1030#ifdef DEBUG
1031static void dbg(unsigned long ptr)
1032{
1033 printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n", ptr,
1034 ((ulong *)ptr)[0], ((ulong *)ptr)[1],
1035 ((ulong *)ptr)[2], ((ulong *)ptr)[3]);
1036}
1037#endif
1038
1039static int dos_read(int drive)
1040{
1041 unsigned long end;
1042 unsigned long raw;
1043 int scnt;
1044 unsigned short crc,data_crc[2];
1045 struct dos_header hdr;
1046
1047 drive&=3;
1048 raw = (long) raw_buf;
1049 end = raw + unit[drive].type->read_size;
1050
1051 for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
1052 do {
1053 if (!(raw = scan_sync (raw, end))) {
1054 printk(KERN_INFO "dos_read: no hdr sync on "
1055 "track %d, unit %d for sector %d\n",
1056 unit[drive].track,drive,scnt);
1057 return MFM_NOSYNC;
1058 }
1059#ifdef DEBUG
1060 dbg(raw);
1061#endif
1062 } while (*((ushort *)raw)!=0x5554);
1063 raw+=2;
1064 raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8);
1065 crc = dos_hdr_crc(&hdr);
1066
1067#ifdef DEBUG
1068 printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side,
1069 hdr.sec, hdr.len_desc, hdr.crc);
1070#endif
1071
1072 if (crc != hdr.crc) {
1073 printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n",
1074 hdr.crc, crc);
1075 return MFM_HEADER;
1076 }
1077 if (hdr.track != unit[drive].track/unit[drive].type->heads) {
1078 printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n",
1079 hdr.track,
1080 unit[drive].track/unit[drive].type->heads);
1081 return MFM_TRACK;
1082 }
1083
1084 if (hdr.side != unit[drive].track%unit[drive].type->heads) {
1085 printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n",
1086 hdr.side,
1087 unit[drive].track%unit[drive].type->heads);
1088 return MFM_TRACK;
1089 }
1090
1091 if (hdr.len_desc != 2) {
1092 printk(KERN_INFO "dos_read: unknown sector len "
1093 "descriptor %d\n", hdr.len_desc);
1094 return MFM_DATA;
1095 }
1096#ifdef DEBUG
1097 printk("hdr accepted\n");
1098#endif
1099 if (!(raw = scan_sync (raw, end))) {
1100 printk(KERN_INFO "dos_read: no data sync on track "
1101 "%d, unit %d for sector%d, disk sector %d\n",
1102 unit[drive].track, drive, scnt, hdr.sec);
1103 return MFM_NOSYNC;
1104 }
1105#ifdef DEBUG
1106 dbg(raw);
1107#endif
1108
1109 if (*((ushort *)raw)!=0x5545) {
1110 printk(KERN_INFO "dos_read: no data mark after "
1111 "sync (%d,%d,%d,%d) sc=%d\n",
1112 hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt);
1113 return MFM_NOSYNC;
1114 }
1115
1116 raw+=2;
1117 raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512);
1118 raw = dos_decode((unsigned char *)data_crc,(ushort *) raw,4);
1119 crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512);
1120
1121 if (crc != data_crc[0]) {
1122 printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) "
1123 "sc=%d, %x %x\n", hdr.track, hdr.side,
1124 hdr.sec, hdr.len_desc, scnt,data_crc[0], crc);
1125 printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n",
1126 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0],
1127 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1],
1128 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2],
1129 ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]);
1130 return MFM_DATA;
1131 }
1132 }
1133 return 0;
1134}
1135
1136static inline ushort dos_encode_byte(unsigned char byte)
1137{
1138 register unsigned char *enc, b2, b1;
1139 register ushort word;
1140
1141 enc=mfmencode;
1142 b1=byte;
1143 b2=b1>>4;
1144 b1&=15;
1145 word=enc[b2] <<8 | enc [b1];
1146 return (word|((word&(256|64)) ? 0: 128));
1147}
1148
1149static void dos_encode_block(ushort *dest, unsigned char *src, int len)
1150{
1151 int i;
1152
1153 for (i = 0; i < len; i++) {
1154 *dest=dos_encode_byte(*src++);
1155 *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000;
1156 dest++;
1157 }
1158}
1159
1160static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt)
1161{
1162 static struct dos_header hdr={0,0,0,2,0,
1163 {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
1164 int i;
1165 static ushort crc[2]={0,0x4e4e};
1166
1167 drive&=3;
1168
1169
1170 for(i=0;i<6;i++)
1171 *raw++=0xaaaaaaaa;
1172
1173 *raw++=0x44894489;
1174 *raw++=0x44895554;
1175
1176
1177 hdr.track=unit[drive].track/unit[drive].type->heads;
1178 hdr.side=unit[drive].track%unit[drive].type->heads;
1179 hdr.sec=cnt+1;
1180 hdr.crc=dos_hdr_crc(&hdr);
1181
1182
1183 dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28);
1184 raw+=14;
1185
1186
1187 for(i=0;i<6;i++)
1188 *raw++=0xaaaaaaaa;
1189
1190
1191 *raw++=0x44894489;
1192 *raw++=0x44895545;
1193
1194
1195 dos_encode_block((ushort *)raw,
1196 (unsigned char *)unit[drive].trackbuf+cnt*512,512);
1197 raw+=256;
1198
1199
1200 crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512);
1201 dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
1202 raw+=2;
1203
1204
1205 for(i=0;i<38;i++)
1206 *raw++=0x92549254;
1207
1208 return raw;
1209}
1210
1211static void dos_write(int disk)
1212{
1213 int cnt;
1214 unsigned long raw = (unsigned long) raw_buf;
1215 unsigned long *ptr=(unsigned long *)raw;
1216
1217 disk&=3;
1218
1219 for (cnt=0;cnt<425;cnt++)
1220 *ptr++=0x92549254;
1221
1222
1223 if (unit[disk].type->sect_mult==2)
1224 for(cnt=0;cnt<473;cnt++)
1225 *ptr++=0x92549254;
1226
1227
1228 for (cnt=0;cnt<20;cnt++)
1229 *ptr++=0x92549254;
1230 for (cnt=0;cnt<6;cnt++)
1231 *ptr++=0xaaaaaaaa;
1232 *ptr++=0x52245224;
1233 *ptr++=0x52245552;
1234 for (cnt=0;cnt<20;cnt++)
1235 *ptr++=0x92549254;
1236
1237
1238 for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
1239 ptr=ms_putsec(disk,ptr,cnt);
1240
1241 *(ushort *)ptr = 0xaaa8;
1242}
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254static void flush_track_callback(unsigned long nr)
1255{
1256 nr&=3;
1257 writefromint = 1;
1258 if (!try_fdc(nr)) {
1259
1260 flush_track_timer[nr].expires = jiffies + 1;
1261 add_timer(flush_track_timer + nr);
1262 return;
1263 }
1264 get_fdc(nr);
1265 (*unit[nr].dtype->write_fkt)(nr);
1266 if (!raw_write(nr)) {
1267 printk (KERN_NOTICE "floppy disk write protected\n");
1268 writefromint = 0;
1269 writepending = 0;
1270 }
1271 rel_fdc();
1272}
1273
1274static int non_int_flush_track (unsigned long nr)
1275{
1276 unsigned long flags;
1277
1278 nr&=3;
1279 writefromint = 0;
1280 del_timer(&post_write_timer);
1281 get_fdc(nr);
1282 if (!fd_motor_on(nr)) {
1283 writepending = 0;
1284 rel_fdc();
1285 return 0;
1286 }
1287 local_irq_save(flags);
1288 if (writepending != 2) {
1289 local_irq_restore(flags);
1290 (*unit[nr].dtype->write_fkt)(nr);
1291 if (!raw_write(nr)) {
1292 printk (KERN_NOTICE "floppy disk write protected "
1293 "in write!\n");
1294 writepending = 0;
1295 return 0;
1296 }
1297 while (block_flag == 2)
1298 sleep_on (&wait_fd_block);
1299 }
1300 else {
1301 local_irq_restore(flags);
1302 ms_delay(2);
1303 post_write(nr);
1304 }
1305 rel_fdc();
1306 return 1;
1307}
1308
1309static int get_track(int drive, int track)
1310{
1311 int error, errcnt;
1312
1313 drive&=3;
1314 if (unit[drive].track == track)
1315 return 0;
1316 get_fdc(drive);
1317 if (!fd_motor_on(drive)) {
1318 rel_fdc();
1319 return -1;
1320 }
1321
1322 if (unit[drive].dirty == 1) {
1323 del_timer (flush_track_timer + drive);
1324 non_int_flush_track (drive);
1325 }
1326 errcnt = 0;
1327 while (errcnt < MAX_ERRORS) {
1328 if (!fd_seek(drive, track))
1329 return -1;
1330 raw_read(drive);
1331 error = (*unit[drive].dtype->read_fkt)(drive);
1332 if (error == 0) {
1333 rel_fdc();
1334 return 0;
1335 }
1336
1337 unit[drive].track = -1;
1338 errcnt++;
1339 }
1340 rel_fdc();
1341 return -1;
1342}
1343
1344static void redo_fd_request(void)
1345{
1346 unsigned int cnt, block, track, sector;
1347 int drive;
1348 struct amiga_floppy_struct *floppy;
1349 char *data;
1350 unsigned long flags;
1351
1352 repeat:
1353 if (!CURRENT) {
1354
1355 return;
1356 }
1357
1358 floppy = CURRENT->rq_disk->private_data;
1359 drive = floppy - unit;
1360
1361
1362 for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) {
1363#ifdef DEBUG
1364 printk("fd: sector %ld + %d requested for %s\n",
1365 CURRENT->sector,cnt,
1366 (rq_data_dir(CURRENT) == READ) ? "read" : "write");
1367#endif
1368 block = CURRENT->sector + cnt;
1369 if ((int)block > floppy->blocks) {
1370 end_request(CURRENT, 0);
1371 goto repeat;
1372 }
1373
1374 track = block / (floppy->dtype->sects * floppy->type->sect_mult);
1375 sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
1376 data = CURRENT->buffer + 512 * cnt;
1377#ifdef DEBUG
1378 printk("access to track %d, sector %d, with buffer at "
1379 "0x%08lx\n", track, sector, data);
1380#endif
1381
1382 if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) {
1383 printk(KERN_WARNING "do_fd_request: unknown command\n");
1384 end_request(CURRENT, 0);
1385 goto repeat;
1386 }
1387 if (get_track(drive, track) == -1) {
1388 end_request(CURRENT, 0);
1389 goto repeat;
1390 }
1391
1392 switch (rq_data_dir(CURRENT)) {
1393 case READ:
1394 memcpy(data, floppy->trackbuf + sector * 512, 512);
1395 break;
1396
1397 case WRITE:
1398 memcpy(floppy->trackbuf + sector * 512, data, 512);
1399
1400
1401 if (!fd_motor_on(drive)) {
1402 end_request(CURRENT, 0);
1403 goto repeat;
1404 }
1405
1406
1407
1408
1409 local_irq_save(flags);
1410
1411 floppy->dirty = 1;
1412
1413 mod_timer (flush_track_timer + drive, jiffies + 1);
1414 local_irq_restore(flags);
1415 break;
1416 }
1417 }
1418 CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
1419 CURRENT->sector += CURRENT->current_nr_sectors;
1420
1421 end_request(CURRENT, 1);
1422 goto repeat;
1423}
1424
1425static void do_fd_request(struct request_queue * q)
1426{
1427 redo_fd_request();
1428}
1429
1430static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
1431{
1432 int drive = MINOR(bdev->bd_dev) & 3;
1433
1434 geo->heads = unit[drive].type->heads;
1435 geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult;
1436 geo->cylinders = unit[drive].type->tracks;
1437 return 0;
1438}
1439
1440static int fd_ioctl(struct inode *inode, struct file *filp,
1441 unsigned int cmd, unsigned long param)
1442{
1443 int drive = iminor(inode) & 3;
1444 static struct floppy_struct getprm;
1445 void __user *argp = (void __user *)param;
1446
1447 switch(cmd){
1448 case FDFMTBEG:
1449 get_fdc(drive);
1450 if (fd_ref[drive] > 1) {
1451 rel_fdc();
1452 return -EBUSY;
1453 }
1454 fsync_bdev(inode->i_bdev);
1455 if (fd_motor_on(drive) == 0) {
1456 rel_fdc();
1457 return -ENODEV;
1458 }
1459 if (fd_calibrate(drive) == 0) {
1460 rel_fdc();
1461 return -ENXIO;
1462 }
1463 floppy_off(drive);
1464 rel_fdc();
1465 break;
1466 case FDFMTTRK:
1467 if (param < unit[drive].type->tracks * unit[drive].type->heads)
1468 {
1469 get_fdc(drive);
1470 if (fd_seek(drive,param) != 0){
1471 memset(unit[drive].trackbuf, FD_FILL_BYTE,
1472 unit[drive].dtype->sects * unit[drive].type->sect_mult * 512);
1473 non_int_flush_track(drive);
1474 }
1475 floppy_off(drive);
1476 rel_fdc();
1477 }
1478 else
1479 return -EINVAL;
1480 break;
1481 case FDFMTEND:
1482 floppy_off(drive);
1483 invalidate_bdev(inode->i_bdev);
1484 break;
1485 case FDGETPRM:
1486 memset((void *)&getprm, 0, sizeof (getprm));
1487 getprm.track=unit[drive].type->tracks;
1488 getprm.head=unit[drive].type->heads;
1489 getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult;
1490 getprm.size=unit[drive].blocks;
1491 if (copy_to_user(argp, &getprm, sizeof(struct floppy_struct)))
1492 return -EFAULT;
1493 break;
1494 case FDSETPRM:
1495 case FDDEFPRM:
1496 return -EINVAL;
1497 case FDFLUSH:
1498 del_timer (flush_track_timer + drive);
1499 non_int_flush_track(drive);
1500 break;
1501#ifdef RAW_IOCTL
1502 case IOCTL_RAW_TRACK:
1503 if (copy_to_user(argp, raw_buf, unit[drive].type->read_size))
1504 return -EFAULT;
1505 else
1506 return unit[drive].type->read_size;
1507#endif
1508 default:
1509 printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",
1510 cmd, drive);
1511 return -ENOSYS;
1512 }
1513 return 0;
1514}
1515
1516static void fd_probe(int dev)
1517{
1518 unsigned long code;
1519 int type;
1520 int drive;
1521
1522 drive = dev & 3;
1523 code = fd_get_drive_id(drive);
1524
1525
1526 for (type = 0; type < num_dr_types; type++)
1527 if (drive_types[type].code == code)
1528 break;
1529
1530 if (type >= num_dr_types) {
1531 printk(KERN_WARNING "fd_probe: unsupported drive type "
1532 "%08lx found\n", code);
1533 unit[drive].type = &drive_types[num_dr_types-1];
1534 return;
1535 }
1536
1537 unit[drive].type = drive_types + type;
1538 unit[drive].track = -1;
1539
1540 unit[drive].disk = -1;
1541 unit[drive].motor = 0;
1542 unit[drive].busy = 0;
1543 unit[drive].status = -1;
1544}
1545
1546
1547
1548
1549
1550
1551static int floppy_open(struct inode *inode, struct file *filp)
1552{
1553 int drive = iminor(inode) & 3;
1554 int system = (iminor(inode) & 4) >> 2;
1555 int old_dev;
1556 unsigned long flags;
1557
1558 old_dev = fd_device[drive];
1559
1560 if (fd_ref[drive] && old_dev != system)
1561 return -EBUSY;
1562
1563 if (filp && filp->f_mode & 3) {
1564 check_disk_change(inode->i_bdev);
1565 if (filp->f_mode & 2 ) {
1566 int wrprot;
1567
1568 get_fdc(drive);
1569 fd_select (drive);
1570 wrprot = !(ciaa.pra & DSKPROT);
1571 fd_deselect (drive);
1572 rel_fdc();
1573
1574 if (wrprot)
1575 return -EROFS;
1576 }
1577 }
1578
1579 local_irq_save(flags);
1580 fd_ref[drive]++;
1581 fd_device[drive] = system;
1582 local_irq_restore(flags);
1583
1584 unit[drive].dtype=&data_types[system];
1585 unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
1586 data_types[system].sects*unit[drive].type->sect_mult;
1587 set_capacity(unit[drive].gendisk, unit[drive].blocks);
1588
1589 printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
1590 unit[drive].type->name, data_types[system].name);
1591
1592 return 0;
1593}
1594
1595static int floppy_release(struct inode * inode, struct file * filp)
1596{
1597 int drive = iminor(inode) & 3;
1598
1599 if (unit[drive].dirty == 1) {
1600 del_timer (flush_track_timer + drive);
1601 non_int_flush_track (drive);
1602 }
1603
1604 if (!fd_ref[drive]--) {
1605 printk(KERN_CRIT "floppy_release with fd_ref == 0");
1606 fd_ref[drive] = 0;
1607 }
1608#ifdef MODULE
1609
1610 floppy_off (drive | 0x40000000);
1611#endif
1612 return 0;
1613}
1614
1615
1616
1617
1618
1619
1620
1621static int amiga_floppy_change(struct gendisk *disk)
1622{
1623 struct amiga_floppy_struct *p = disk->private_data;
1624 int drive = p - unit;
1625 int changed;
1626 static int first_time = 1;
1627
1628 if (first_time)
1629 changed = first_time--;
1630 else {
1631 get_fdc(drive);
1632 fd_select (drive);
1633 changed = !(ciaa.pra & DSKCHANGE);
1634 fd_deselect (drive);
1635 rel_fdc();
1636 }
1637
1638 if (changed) {
1639 fd_probe(drive);
1640 p->track = -1;
1641 p->dirty = 0;
1642 writepending = 0;
1643 writefromint = 0;
1644 return 1;
1645 }
1646 return 0;
1647}
1648
1649static struct block_device_operations floppy_fops = {
1650 .owner = THIS_MODULE,
1651 .open = floppy_open,
1652 .release = floppy_release,
1653 .ioctl = fd_ioctl,
1654 .getgeo = fd_getgeo,
1655 .media_changed = amiga_floppy_change,
1656};
1657
1658static int __init fd_probe_drives(void)
1659{
1660 int drive,drives,nomem;
1661
1662 printk(KERN_INFO "FD: probing units\n" KERN_INFO "found ");
1663 drives=0;
1664 nomem=0;
1665 for(drive=0;drive<FD_MAX_UNITS;drive++) {
1666 struct gendisk *disk;
1667 fd_probe(drive);
1668 if (unit[drive].type->code == FD_NODRIVE)
1669 continue;
1670 disk = alloc_disk(1);
1671 if (!disk) {
1672 unit[drive].type->code = FD_NODRIVE;
1673 continue;
1674 }
1675 unit[drive].gendisk = disk;
1676 drives++;
1677 if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
1678 printk("no mem for ");
1679 unit[drive].type = &drive_types[num_dr_types - 1];
1680 drives--;
1681 nomem = 1;
1682 }
1683 printk("fd%d ",drive);
1684 disk->major = FLOPPY_MAJOR;
1685 disk->first_minor = drive;
1686 disk->fops = &floppy_fops;
1687 sprintf(disk->disk_name, "fd%d", drive);
1688 disk->private_data = &unit[drive];
1689 disk->queue = floppy_queue;
1690 set_capacity(disk, 880*2);
1691 add_disk(disk);
1692 }
1693 if ((drives > 0) || (nomem == 0)) {
1694 if (drives == 0)
1695 printk("no drives");
1696 printk("\n");
1697 return drives;
1698 }
1699 printk("\n");
1700 return -ENOMEM;
1701}
1702
1703static struct kobject *floppy_find(dev_t dev, int *part, void *data)
1704{
1705 int drive = *part & 3;
1706 if (unit[drive].type->code == FD_NODRIVE)
1707 return NULL;
1708 *part = 0;
1709 return get_disk(unit[drive].gendisk);
1710}
1711
1712static int __init amiga_floppy_init(void)
1713{
1714 int i, ret;
1715
1716 if (!MACH_IS_AMIGA)
1717 return -ENODEV;
1718
1719 if (!AMIGAHW_PRESENT(AMI_FLOPPY))
1720 return -ENODEV;
1721
1722 if (register_blkdev(FLOPPY_MAJOR,"fd"))
1723 return -EBUSY;
1724
1725
1726
1727
1728
1729 ret = -EBUSY;
1730 if (!request_mem_region(CUSTOM_PHYSADDR+0x20, 8, "amiflop [Paula]")) {
1731 printk("fd: cannot get floppy registers\n");
1732 goto out_blkdev;
1733 }
1734
1735 ret = -ENOMEM;
1736 if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE, "Floppy")) ==
1737 NULL) {
1738 printk("fd: cannot get chip mem buffer\n");
1739 goto out_memregion;
1740 }
1741
1742 ret = -EBUSY;
1743 if (request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) {
1744 printk("fd: cannot get irq for dma\n");
1745 goto out_irq;
1746 }
1747
1748 if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) {
1749 printk("fd: cannot get irq for timer\n");
1750 goto out_irq2;
1751 }
1752
1753 ret = -ENOMEM;
1754 floppy_queue = blk_init_queue(do_fd_request, &amiflop_lock);
1755 if (!floppy_queue)
1756 goto out_queue;
1757
1758 ret = -ENODEV;
1759 if (fd_probe_drives() < 1)
1760 goto out_probe;
1761
1762 blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,
1763 floppy_find, NULL, NULL);
1764
1765
1766 init_timer(&motor_on_timer);
1767 motor_on_timer.expires = 0;
1768 motor_on_timer.data = 0;
1769 motor_on_timer.function = motor_on_callback;
1770 for (i = 0; i < FD_MAX_UNITS; i++) {
1771 init_timer(&motor_off_timer[i]);
1772 motor_off_timer[i].expires = 0;
1773 motor_off_timer[i].data = i|0x80000000;
1774 motor_off_timer[i].function = fd_motor_off;
1775 init_timer(&flush_track_timer[i]);
1776 flush_track_timer[i].expires = 0;
1777 flush_track_timer[i].data = i;
1778 flush_track_timer[i].function = flush_track_callback;
1779
1780 unit[i].track = -1;
1781 }
1782
1783 init_timer(&post_write_timer);
1784 post_write_timer.expires = 0;
1785 post_write_timer.data = 0;
1786 post_write_timer.function = post_write;
1787
1788 for (i = 0; i < 128; i++)
1789 mfmdecode[i]=255;
1790 for (i = 0; i < 16; i++)
1791 mfmdecode[mfmencode[i]]=i;
1792
1793
1794 custom.dmacon = DMAF_SETCLR | DMAF_DISK;
1795
1796
1797 ciaa.crb = 8;
1798 return 0;
1799
1800out_probe:
1801 blk_cleanup_queue(floppy_queue);
1802out_queue:
1803 free_irq(IRQ_AMIGA_CIAA_TB, NULL);
1804out_irq2:
1805 free_irq(IRQ_AMIGA_DSKBLK, NULL);
1806out_irq:
1807 amiga_chip_free(raw_buf);
1808out_memregion:
1809 release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
1810out_blkdev:
1811 unregister_blkdev(FLOPPY_MAJOR,"fd");
1812 return ret;
1813}
1814
1815module_init(amiga_floppy_init);
1816#ifdef MODULE
1817
1818#if 0
1819void cleanup_module(void)
1820{
1821 int i;
1822
1823 for( i = 0; i < FD_MAX_UNITS; i++) {
1824 if (unit[i].type->code != FD_NODRIVE) {
1825 del_gendisk(unit[i].gendisk);
1826 put_disk(unit[i].gendisk);
1827 kfree(unit[i].trackbuf);
1828 }
1829 }
1830 blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
1831 free_irq(IRQ_AMIGA_CIAA_TB, NULL);
1832 free_irq(IRQ_AMIGA_DSKBLK, NULL);
1833 custom.dmacon = DMAF_DISK;
1834 amiga_chip_free(raw_buf);
1835 blk_cleanup_queue(floppy_queue);
1836 release_mem_region(CUSTOM_PHYSADDR+0x20, 8);
1837 unregister_blkdev(FLOPPY_MAJOR, "fd");
1838}
1839#endif
1840
1841#else
1842static int __init amiga_floppy_setup (char *str)
1843{
1844 int n;
1845 if (!MACH_IS_AMIGA)
1846 return 0;
1847 if (!get_option(&str, &n))
1848 return 0;
1849 printk (KERN_INFO "amiflop: Setting default df0 to %x\n", n);
1850 fd_def_df0 = n;
1851 return 1;
1852}
1853
1854__setup("floppy=", amiga_floppy_setup);
1855#endif
1856