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