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