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