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