This source file includes following definitions.
- floppy_deselect
- request_done
- floppy_change
- setup_DMA
- output_byte
- result
- bad_flp_intr
- rw_interrupt
- setup_rw_floppy
- seek_interrupt
- transfer
- recal_interrupt
- unexpected_floppy_interrupt
- recalibrate_floppy
- reset_interrupt
- reset_floppy
- floppy_shutdown
- shake_done
- retry_recal
- shake_zero
- shake_one
- floppy_on_interrupt
- setup_format_params
- redo_fd_request
- do_fd_request
- fd_ioctl
- find_base
- config_types
- floppy_open
- floppy_release
- floppy_init
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 #include <linux/sched.h>
42 #include <linux/fs.h>
43 #include <linux/kernel.h>
44 #include <linux/timer.h>
45 #include <linux/fdreg.h>
46 #include <linux/fd.h>
47 #include <asm/system.h>
48 #include <asm/io.h>
49 #include <asm/segment.h>
50 #include <errno.h>
51
52 #define MAJOR_NR 2
53 #include "blk.h"
54
55 static unsigned int changed_floppies = 0, fake_change = 0;
56
57 static int recalibrate = 0;
58 static int reset = 0;
59 static int recover = 0;
60 static int seek = 0;
61
62 extern unsigned char current_DOR;
63
64 #define immoutb_p(val,port) \
65 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
66
67 #define TYPE(x) ((x)>>2)
68 #define DRIVE(x) ((x)&0x03)
69
70
71
72
73
74 #define MAX_ERRORS 12
75
76
77
78
79
80
81 #define MAX_DISK_SIZE 1440
82
83
84
85
86
87
88 #define MAX_BUFFER_SECTORS 18
89
90
91
92
93 #define MAX_REPLIES 7
94 static unsigned char reply_buffer[MAX_REPLIES];
95 #define ST0 (reply_buffer[0])
96 #define ST1 (reply_buffer[1])
97 #define ST2 (reply_buffer[2])
98 #define ST3 (reply_buffer[3])
99
100
101
102
103
104
105
106
107
108
109
110
111 static struct floppy_struct floppy_type[] = {
112 { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL },
113 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL },
114 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL },
115 { 720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL },
116 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL },
117 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL },
118 { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL },
119 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL },
120 };
121
122
123
124 static struct floppy_struct floppy_types[] = {
125 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" },
126 { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" },
127 { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" },
128 { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" },
129 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },
130 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" },
131 { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" },
132 { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" },
133 };
134
135
136
137 struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL };
138
139
140
141 struct floppy_struct *base_type[4];
142
143
144
145
146 struct floppy_struct user_params[4];
147
148 static int floppy_sizes[] ={
149 MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE,
150 360, 360 ,360, 360,
151 1200,1200,1200,1200,
152 360, 360, 360, 360,
153 720, 720, 720, 720,
154 360, 360, 360, 360,
155 720, 720, 720, 720,
156 1440,1440,1440,1440
157 };
158
159
160
161
162 static int probing = 0;
163
164
165
166
167
168 static int keep_data[4] = { 0,0,0,0 };
169
170
171
172
173 static ftd_msg[4] = { 1,1,1,1 };
174
175
176
177 static volatile int format_status = FORMAT_NONE, fdc_busy = 0;
178 static struct task_struct *fdc_wait = NULL, *format_done = NULL;
179
180
181
182 static int format_errors;
183
184
185
186 static struct format_descr format_req;
187
188
189
190
191 #define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \
192 (CURRENT->dev))
193
194
195
196 #define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \
197 (CURRENT->errors))
198
199
200
201
202
203
204
205
206
207
208 extern void floppy_interrupt(void);
209 extern char tmp_floppy_area[1024];
210 extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS];
211
212 static void redo_fd_request(void);
213
214
215
216
217
218
219 #define NO_TRACK 255
220
221 static int read_track = 0;
222 static int buffer_track = -1;
223 static int buffer_drive = -1;
224 static int cur_spec1 = -1;
225 static int cur_rate = -1;
226 static struct floppy_struct * floppy = floppy_type;
227 static unsigned char current_drive = 255;
228 static unsigned char sector = 0;
229 static unsigned char head = 0;
230 static unsigned char track = 0;
231 static unsigned char seek_track = 0;
232 static unsigned char current_track = NO_TRACK;
233 static unsigned char command = 0;
234 unsigned char selected = 0;
235 struct task_struct * wait_on_floppy_select = NULL;
236
237 void floppy_deselect(unsigned int nr)
238 {
239 if (nr != (current_DOR & 3))
240 printk("floppy_deselect: drive not selected\n\r");
241 selected = 0;
242 wake_up(&wait_on_floppy_select);
243 }
244
245 void request_done(int uptodate)
246 {
247 timer_active &= ~(1 << FLOPPY_TIMER);
248 if (format_status != FORMAT_BUSY) end_request(uptodate);
249 else {
250 format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
251 wake_up(&format_done);
252 }
253 }
254
255
256
257
258
259
260
261 int floppy_change(struct buffer_head * bh)
262 {
263 unsigned int mask = 1 << (bh->b_dev & 0x03);
264
265 if (MAJOR(bh->b_dev) != 2) {
266 printk("floppy_changed: not a floppy\r\n");
267 return 0;
268 }
269 if (fake_change & mask) {
270 fake_change &= ~mask;
271
272 changed_floppies &= ~mask;
273 return 1;
274 }
275 if (changed_floppies & mask) {
276 changed_floppies &= ~mask;
277 recalibrate = 1;
278 return 1;
279 }
280 if (!bh)
281 return 0;
282 if (bh->b_dirt)
283 ll_rw_block(WRITE,bh);
284 else {
285 buffer_track = -1;
286 bh->b_uptodate = 0;
287 ll_rw_block(READ,bh);
288 }
289 cli();
290 while (bh->b_lock)
291 sleep_on(&bh->b_wait);
292 sti();
293 if (changed_floppies & mask) {
294 changed_floppies &= ~mask;
295 recalibrate = 1;
296 return 1;
297 }
298 return 0;
299 }
300
301 #define copy_buffer(from,to) \
302 __asm__("cld ; rep ; movsl" \
303 ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
304 :"cx","di","si")
305
306 static void setup_DMA(void)
307 {
308 unsigned long addr,count;
309
310 if (command == FD_FORMAT) {
311 addr = (long) tmp_floppy_area;
312 count = floppy->sect*4;
313 }
314 else {
315 addr = (long) CURRENT->buffer;
316 count = 1024;
317 }
318 if (read_track) {
319
320 buffer_drive = buffer_track = -1;
321 count = floppy->sect*2*512;
322 addr = (long) floppy_track_buffer;
323 } else if (addr >= 0x100000) {
324 addr = (long) tmp_floppy_area;
325 if (command == FD_WRITE)
326 copy_buffer(CURRENT->buffer,tmp_floppy_area);
327 }
328
329 cli();
330 immoutb_p(4|2,10);
331
332
333 __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
334 "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
335 "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
336
337 immoutb_p(addr,4);
338 addr >>= 8;
339
340 immoutb_p(addr,4);
341 addr >>= 8;
342
343 immoutb_p(addr,0x81);
344
345 count--;
346 immoutb_p(count,5);
347 count >>= 8;
348
349 immoutb_p(count,5);
350
351 immoutb_p(0|2,10);
352 sti();
353 }
354
355 static void output_byte(char byte)
356 {
357 int counter;
358 unsigned char status;
359
360 if (reset)
361 return;
362 for(counter = 0 ; counter < 10000 ; counter++) {
363 status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
364 if (status == STATUS_READY) {
365 outb(byte,FD_DATA);
366 return;
367 }
368 }
369 current_track = NO_TRACK;
370 reset = 1;
371 printk("Unable to send byte to FDC\n\r");
372 }
373
374 static int result(void)
375 {
376 int i = 0, counter, status;
377
378 if (reset)
379 return -1;
380 for (counter = 0 ; counter < 10000 ; counter++) {
381 status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
382 if (status == STATUS_READY)
383 return i;
384 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
385 if (i >= MAX_REPLIES)
386 break;
387 reply_buffer[i++] = inb_p(FD_DATA);
388 }
389 }
390 reset = 1;
391 current_track = NO_TRACK;
392 printk("Getstatus times out\n\r");
393 return -1;
394 }
395
396 static void bad_flp_intr(void)
397 {
398 current_track = NO_TRACK;
399 CURRENT_ERRORS++;
400 if (CURRENT_ERRORS > MAX_ERRORS) {
401 floppy_deselect(current_drive);
402 request_done(0);
403 }
404 if (CURRENT_ERRORS > MAX_ERRORS/2)
405 reset = 1;
406 else
407 recalibrate = 1;
408 }
409
410
411
412
413
414 static void rw_interrupt(void)
415 {
416 char * buffer_area;
417
418 if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
419 if (ST1 & 0x02) {
420 printk("Drive %d is write protected\n\r",current_drive);
421 floppy_deselect(current_drive);
422 request_done(0);
423 } else
424 bad_flp_intr();
425 redo_fd_request();
426 return;
427 }
428 if (probing) {
429 int drive = MINOR(CURRENT->dev);
430
431 if (ftd_msg[drive])
432 printk("Auto-detected floppy type %s in fd%d\r\n",
433 floppy->name,drive);
434 current_type[drive] = floppy;
435 floppy_sizes[drive] = floppy->size >> 1;
436 probing = 0;
437 }
438 if (read_track) {
439 buffer_track = seek_track;
440 buffer_drive = current_drive;
441 buffer_area = floppy_track_buffer +
442 ((sector-1 + head*floppy->sect)<<9);
443 copy_buffer(buffer_area,CURRENT->buffer);
444 } else if (command == FD_READ &&
445 (unsigned long)(CURRENT->buffer) >= 0x100000)
446 copy_buffer(tmp_floppy_area,CURRENT->buffer);
447 floppy_deselect(current_drive);
448 request_done(1);
449 redo_fd_request();
450 }
451
452
453
454
455
456
457
458
459 inline void setup_rw_floppy(void)
460 {
461 setup_DMA();
462 do_floppy = rw_interrupt;
463 output_byte(command);
464 if (command != FD_FORMAT) {
465 if (read_track) {
466 output_byte(current_drive);
467 output_byte(track);
468 output_byte(0);
469 output_byte(1);
470 } else {
471 output_byte(head<<2 | current_drive);
472 output_byte(track);
473 output_byte(head);
474 output_byte(sector);
475 }
476 output_byte(2);
477 output_byte(floppy->sect);
478 output_byte(floppy->gap);
479 output_byte(0xFF);
480 } else {
481 output_byte(head<<2 | current_drive);
482 output_byte(2);
483 output_byte(floppy->sect);
484 output_byte(floppy->fmt_gap);
485 output_byte(FD_FILL_BYTE);
486 }
487 if (reset)
488 redo_fd_request();
489 }
490
491
492
493
494
495
496 static void seek_interrupt(void)
497 {
498
499 output_byte(FD_SENSEI);
500 if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
501 recalibrate = 1;
502 bad_flp_intr();
503 redo_fd_request();
504 return;
505 }
506 current_track = ST1;
507 setup_rw_floppy();
508 }
509
510
511
512
513
514
515 static void transfer(void)
516 {
517 read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
518 (floppy->sect <= MAX_BUFFER_SECTORS);
519 if (cur_spec1 != floppy->spec1) {
520 cur_spec1 = floppy->spec1;
521 output_byte(FD_SPECIFY);
522 output_byte(cur_spec1);
523 output_byte(6);
524 }
525 if (cur_rate != floppy->rate)
526 outb_p(cur_rate = floppy->rate,FD_DCR);
527 if (reset) {
528 redo_fd_request();
529 return;
530 }
531 if (!seek) {
532 setup_rw_floppy();
533 return;
534 }
535 do_floppy = seek_interrupt;
536 output_byte(FD_SEEK);
537 if (read_track)
538 output_byte(current_drive);
539 else
540 output_byte((head<<2) | current_drive);
541 output_byte(seek_track);
542 if (reset)
543 redo_fd_request();
544 }
545
546
547
548
549
550 static void recalibrate_floppy();
551
552 static void recal_interrupt(void)
553 {
554 output_byte(FD_SENSEI);
555 current_track = NO_TRACK;
556 if (result()!=2 || (ST0 & 0xE0) == 0x60)
557 reset = 1;
558
559 if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
560 else redo_fd_request();
561 }
562
563 void unexpected_floppy_interrupt(void)
564 {
565 current_track = NO_TRACK;
566 output_byte(FD_SENSEI);
567 if (result()!=2 || (ST0 & 0xE0) == 0x60)
568 reset = 1;
569 else
570 recalibrate = 1;
571 }
572
573 static void recalibrate_floppy(void)
574 {
575 recalibrate = 0;
576 current_track = 0;
577 do_floppy = recal_interrupt;
578 output_byte(FD_RECALIBRATE);
579 output_byte(head<<2 | current_drive);
580 if (reset)
581 redo_fd_request();
582 }
583
584 static void reset_interrupt(void)
585 {
586 output_byte(FD_SENSEI);
587 (void) result();
588 output_byte(FD_SPECIFY);
589 output_byte(cur_spec1);
590 output_byte(6);
591 if (!recover) redo_fd_request();
592 else {
593 recalibrate_floppy();
594 recover = 0;
595 }
596 }
597
598
599
600
601 static void reset_floppy(void)
602 {
603 int i;
604
605 do_floppy = reset_interrupt;
606 reset = 0;
607 current_track = NO_TRACK;
608 cur_spec1 = -1;
609 cur_rate = -1;
610 recalibrate = 1;
611 printk("Reset-floppy called\n\r");
612 cli();
613 outb_p(current_DOR & ~0x04,FD_DOR);
614 for (i=0 ; i<1000 ; i++)
615 __asm__("nop");
616 outb(current_DOR,FD_DOR);
617 sti();
618 }
619
620 static void floppy_shutdown(void)
621 {
622 cli();
623 request_done(0);
624 recover = 1;
625 reset_floppy();
626 sti();
627 }
628
629 static void shake_done(void)
630 {
631 current_track = NO_TRACK;
632 if (inb(FD_DIR) & 0x80) request_done(0);
633 redo_fd_request();
634 }
635
636 static int retry_recal(void (*proc)(void))
637 {
638 output_byte(FD_SENSEI);
639 if (result() == 2 && (ST0 & 0x10) != 0x10) return 0;
640 do_floppy = proc;
641 output_byte(FD_RECALIBRATE);
642 output_byte(head<<2 | current_drive);
643 return 1;
644 }
645
646 static void shake_zero(void)
647 {
648 if (!retry_recal(shake_zero)) shake_done();
649 }
650
651 static void shake_one(void)
652 {
653 if (retry_recal(shake_one)) return;
654 do_floppy = shake_done;
655 output_byte(FD_SEEK);
656 output_byte(head << 2 | current_drive);
657 output_byte(1);
658 }
659
660 static void floppy_on_interrupt(void)
661 {
662 if (inb(FD_DIR) & 0x80) {
663 changed_floppies |= 1<<current_drive;
664 buffer_track = -1;
665 if (keep_data[current_drive]) {
666 if (keep_data[current_drive] > 0)
667 keep_data[current_drive]--;
668 }
669 else {
670 if (ftd_msg[current_drive] && current_type[
671 current_drive] != NULL)
672 printk("Disk type is undefined after disk "
673 "change in fd%d\r\n",current_drive);
674 current_type[current_drive] = NULL;
675 floppy_sizes[current_drive] = MAX_DISK_SIZE;
676 }
677
678
679 if (!reset && !recalibrate) {
680 do_floppy = (current_track && current_track != NO_TRACK)
681 ? shake_zero : shake_one;
682 output_byte(FD_RECALIBRATE);
683 output_byte(head<<2 | current_drive);
684 return;
685 }
686 }
687 if (reset) {
688 reset_floppy();
689 return;
690 }
691 if (recalibrate) {
692 recalibrate_floppy();
693 return;
694 }
695
696 selected = 1;
697 if (current_drive != (current_DOR & 3)) {
698 seek = 1;
699 current_track = NO_TRACK;
700 current_DOR &= 0xFC;
701 current_DOR |= current_drive;
702 outb(current_DOR,FD_DOR);
703 add_timer(2,&transfer);
704 } else
705 transfer();
706 }
707
708 static void setup_format_params(void)
709 {
710 unsigned char *here = (unsigned char *) tmp_floppy_area;
711 int count;
712
713 for (count = 1; count <= floppy->sect; count++) {
714 *here++ = track;
715 *here++ = head;
716 *here++ = count;
717 *here++ = 2;
718 }
719 }
720
721 static void redo_fd_request(void)
722 {
723 unsigned int block;
724 char * buffer_area;
725 int device;
726
727 repeat:
728 if (format_status == FORMAT_WAIT) format_status = FORMAT_BUSY;
729 if (format_status != FORMAT_BUSY) {
730 if (!CURRENT) {
731 if (!fdc_busy) panic("FDC access conflict");
732 fdc_busy = 0;
733 wake_up(&fdc_wait);
734 CLEAR_INTR;
735 return;
736 }
737 if (MAJOR(CURRENT->dev) != MAJOR_NR)
738 panic(DEVICE_NAME ": request list destroyed"); \
739 if (CURRENT->bh) {
740 if (!CURRENT->bh->b_lock)
741 panic(DEVICE_NAME ": block not locked");
742 }
743 }
744 seek = 0;
745 probing = 0;
746 device = MINOR(CURRENT_DEVICE);
747 if (device > 3)
748 floppy = (device >> 2) + floppy_type;
749 else {
750 if ((floppy = current_type[device & 3]) == NULL) {
751 probing = 1;
752 if ((floppy = base_type[device & 3]) ==
753 NULL) {
754 request_done(0);
755 goto repeat;
756 }
757 floppy += CURRENT_ERRORS & 1;
758 }
759 }
760 if (format_status != FORMAT_BUSY) {
761 if (current_drive != CURRENT_DEV)
762 current_track = NO_TRACK;
763 current_drive = CURRENT_DEV;
764 block = CURRENT->sector;
765 if (block+2 > floppy->size) {
766 request_done(0);
767 goto repeat;
768 }
769 sector = block % floppy->sect;
770 block /= floppy->sect;
771 head = block % floppy->head;
772 track = block / floppy->head;
773 seek_track = track << floppy->stretch;
774 if (CURRENT->cmd == READ)
775 command = FD_READ;
776 else if (CURRENT->cmd == WRITE)
777 command = FD_WRITE;
778 else {
779 printk("do_fd_request: unknown command\n");
780 request_done(0);
781 goto repeat;
782 }
783 }
784 else {
785 if (current_drive != (format_req.device & 3))
786 current_track = NO_TRACK;
787 current_drive = format_req.device & 3;
788 if (format_req.track < 0 || format_req.track >= floppy->track ||
789 (format_req.head & 0xfffe) || probing) {
790 request_done(0);
791 goto repeat;
792 }
793 head = format_req.head;
794 track = format_req.track;
795 seek_track = track << floppy->stretch;
796 if (seek_track == buffer_track) buffer_track = -1;
797 command = FD_FORMAT;
798 setup_format_params();
799 }
800 timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
801 timer_active |= 1 << FLOPPY_TIMER;
802 if ((seek_track == buffer_track) &&
803 (current_drive == buffer_drive)) {
804 buffer_area = floppy_track_buffer +
805 ((sector + head*floppy->sect)<<9);
806 if (command == FD_READ) {
807 copy_buffer(buffer_area,CURRENT->buffer);
808 request_done(1);
809 goto repeat;
810 } else if (command == FD_WRITE)
811 copy_buffer(CURRENT->buffer,buffer_area);
812 }
813 if (seek_track != current_track)
814 seek = 1;
815 sector++;
816 add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
817 }
818
819 void do_fd_request(void)
820 {
821 cli();
822 while (fdc_busy) sleep_on(&fdc_wait);
823 fdc_busy = 1;
824 sti();
825 redo_fd_request();
826 }
827
828 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
829 unsigned int param)
830 {
831 int drive,cnt,okay;
832 struct floppy_struct *this;
833
834 if (!suser()) return -EPERM;
835 drive = MINOR(inode->i_rdev);
836 switch (cmd) {
837 case FDFMTBEG:
838 return 0;
839 case FDFMTEND:
840 cli();
841 fake_change |= 1 << (drive & 3);
842 sti();
843 drive &= 3;
844 cmd = FDCLRPRM;
845 break;
846 case FDGETPRM:
847 if (drive > 3) this = &floppy_type[drive >> 2];
848 else if ((this = current_type[drive & 3]) == NULL)
849 return -ENODEV;
850 verify_area((void *) param,sizeof(struct floppy_struct));
851 for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
852 put_fs_byte(((char *) this)[cnt],
853 (char *) param+cnt);
854 return 0;
855 case FDFMTTRK:
856 cli();
857 while (format_status != FORMAT_NONE)
858 sleep_on(&format_done);
859 for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
860 ((char *) &format_req)[cnt] = get_fs_byte(
861 (char *) param+cnt);
862 format_req.device = drive;
863 format_status = FORMAT_WAIT;
864 format_errors = 0;
865 while (format_status != FORMAT_OKAY && format_status !=
866 FORMAT_ERROR) {
867 if (fdc_busy) sleep_on(&fdc_wait);
868 else {
869 fdc_busy = 1;
870 redo_fd_request();
871 }
872 }
873 while (format_status != FORMAT_OKAY && format_status !=
874 FORMAT_ERROR)
875 sleep_on(&format_done);
876 sti();
877 okay = format_status == FORMAT_OKAY;
878 format_status = FORMAT_NONE;
879 wake_up(&format_done);
880 return okay ? 0 : -EIO;
881 }
882 if (drive < 0 || drive > 3) return -EINVAL;
883 switch (cmd) {
884 case FDCLRPRM:
885 current_type[drive] = NULL;
886 floppy_sizes[drive] = MAX_DISK_SIZE;
887 keep_data[drive] = 0;
888 break;
889 case FDSETPRM:
890 case FDDEFPRM:
891 for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
892 ((char *) &user_params[drive])[cnt] =
893 get_fs_byte((char *) param+cnt);
894 current_type[drive] = &user_params[drive];
895 floppy_sizes[drive] = user_params[drive].size >> 1;
896 if (cmd == FDDEFPRM) keep_data[drive] = -1;
897 else {
898 cli();
899 while (fdc_busy) sleep_on(&fdc_wait);
900 fdc_busy = 1;
901 sti();
902 outb_p((current_DOR & 0xfc) | drive |
903 (0x10 << drive),FD_DOR);
904 for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
905 keep_data[drive] = (inb(FD_DIR) & 0x80) ? 1 : 0;
906 outb_p(current_DOR,FD_DOR);
907 fdc_busy = 0;
908 wake_up(&fdc_wait);
909 }
910 break;
911 case FDMSGON:
912 ftd_msg[drive] = 1;
913 break;
914 case FDMSGOFF:
915 ftd_msg[drive] = 0;
916 break;
917 default:
918 return -EINVAL;
919 }
920 return 0;
921 }
922
923 #define CMOS_READ(addr) ({ \
924 outb_p(0x80|addr,0x70); \
925 inb_p(0x71); \
926 })
927
928 static struct floppy_struct *find_base(int drive,int code)
929 {
930 struct floppy_struct *base;
931
932 if (code > 0 && code < 5) {
933 base = &floppy_types[(code-1)*2];
934 printk("fd%d is %s",drive,base->name);
935 return base;
936 }
937 printk("fd%d is unknown type %d",drive,code);
938 return NULL;
939 }
940
941 static void config_types(void)
942 {
943 printk("Floppy drive(s): ");
944 base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
945 if (((CMOS_READ(0x14) >> 6) & 1) == 0) base_type[0] = NULL;
946 else {
947 printk(", ");
948 base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
949 }
950 base_type[2] = base_type[3] = NULL;
951 printk("\r\n");
952 }
953
954 static int floppy_open(struct inode * inode, struct file * filp)
955 {
956 if (filp->f_mode)
957 check_disk_change(inode->i_rdev);
958 return 0;
959 }
960
961 static void floppy_release(struct inode * inode, struct file * filp)
962 {
963 sync_dev(inode->i_rdev);
964 }
965
966 static struct file_operations floppy_fops = {
967 NULL,
968 block_read,
969 block_write,
970 NULL,
971 NULL,
972 fd_ioctl,
973 floppy_open,
974 floppy_release
975 };
976
977 void floppy_init(void)
978 {
979 outb(current_DOR,FD_DOR);
980 blk_size[MAJOR_NR] = floppy_sizes;
981 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
982 blkdev_fops[MAJOR_NR] = &floppy_fops;
983 timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
984 timer_active &= ~(1 << FLOPPY_TIMER);
985 config_types();
986 set_intr_gate(0x26,&floppy_interrupt);
987 outb(inb_p(0x21)&~0x40,0x21);
988 }