This source file includes following definitions.
- floppy_deselect
- 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_on_interrupt
- do_fd_request
- 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 #include <linux/sched.h>
36 #include <linux/fs.h>
37 #include <linux/kernel.h>
38 #include <linux/fdreg.h>
39 #include <asm/system.h>
40 #include <asm/io.h>
41 #include <asm/segment.h>
42
43 #define MAJOR_NR 2
44 #include "blk.h"
45
46 unsigned int changed_floppies = 0;
47
48 static int recalibrate = 0;
49 static int reset = 0;
50 static int seek = 0;
51
52 extern unsigned char current_DOR;
53
54 #define immoutb_p(val,port) \
55 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
56
57 #define TYPE(x) ((x)>>2)
58 #define DRIVE(x) ((x)&0x03)
59
60
61
62
63
64 #define MAX_ERRORS 12
65
66
67
68
69 #define MAX_REPLIES 7
70 static unsigned char reply_buffer[MAX_REPLIES];
71 #define ST0 (reply_buffer[0])
72 #define ST1 (reply_buffer[1])
73 #define ST2 (reply_buffer[2])
74 #define ST3 (reply_buffer[3])
75
76
77
78
79
80
81
82
83
84
85
86 struct floppy_struct {
87 unsigned int size, sect, head, track, stretch;
88 unsigned char gap,rate,spec1;
89 };
90
91 static struct floppy_struct floppy_type[] = {
92 { 0, 0,0, 0,0,0x00,0x00,0x00 },
93 { 720, 9,2,40,0,0x2A,0x02,0xDF },
94 { 2400,15,2,80,0,0x1B,0x00,0xDF },
95 { 720, 9,2,40,1,0x2A,0x02,0xDF },
96 { 1440, 9,2,80,0,0x2A,0x02,0xDF },
97 { 720, 9,2,40,1,0x23,0x01,0xDF },
98 { 1440, 9,2,80,0,0x23,0x01,0xDF },
99 { 2880,18,2,80,0,0x1B,0x00,0xCF },
100 };
101
102
103
104
105
106
107
108
109
110
111 extern void floppy_interrupt(void);
112 extern char tmp_floppy_area[1024];
113 extern char floppy_track_buffer[512*2*18];
114
115
116
117
118
119
120 #define NO_TRACK 255
121
122 static int read_track = 0;
123 static int buffer_track = -1;
124 static int buffer_drive = -1;
125 static int cur_spec1 = -1;
126 static int cur_rate = -1;
127 static struct floppy_struct * floppy = floppy_type;
128 static unsigned char current_drive = 255;
129 static unsigned char sector = 0;
130 static unsigned char head = 0;
131 static unsigned char track = 0;
132 static unsigned char seek_track = 0;
133 static unsigned char current_track = NO_TRACK;
134 static unsigned char command = 0;
135 unsigned char selected = 0;
136 struct task_struct * wait_on_floppy_select = NULL;
137
138 void floppy_deselect(unsigned int nr)
139 {
140 if (nr != (current_DOR & 3))
141 printk("floppy_deselect: drive not selected\n\r");
142 selected = 0;
143 wake_up(&wait_on_floppy_select);
144 }
145
146
147
148
149
150
151
152 int floppy_change(struct buffer_head * bh)
153 {
154 unsigned int mask = 1 << (bh->b_dev & 0x03);
155
156 if (MAJOR(bh->b_dev) != 2) {
157 printk("floppy_changed: not a floppy\n");
158 return 0;
159 }
160 if (changed_floppies & mask) {
161 changed_floppies &= ~mask;
162 recalibrate = 1;
163 return 1;
164 }
165 if (!bh)
166 return 0;
167 if (bh->b_dirt)
168 ll_rw_block(WRITE,bh);
169 else {
170 buffer_track = -1;
171 bh->b_uptodate = 0;
172 ll_rw_block(READ,bh);
173 }
174 cli();
175 while (bh->b_lock)
176 sleep_on(&bh->b_wait);
177 sti();
178 if (changed_floppies & mask) {
179 changed_floppies &= ~mask;
180 recalibrate = 1;
181 return 1;
182 }
183 return 0;
184 }
185
186 #define copy_buffer(from,to) \
187 __asm__("cld ; rep ; movsl" \
188 ::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
189 :"cx","di","si")
190
191 static void setup_DMA(void)
192 {
193 unsigned long addr = (long) CURRENT->buffer;
194 unsigned long count = 1024;
195
196 cli();
197 if (read_track) {
198
199 buffer_drive = buffer_track = -1;
200 count = floppy->sect*2*512;
201 addr = (long) floppy_track_buffer;
202 } else if (addr >= 0x100000) {
203 addr = (long) tmp_floppy_area;
204 if (command == FD_WRITE)
205 copy_buffer(CURRENT->buffer,tmp_floppy_area);
206 }
207
208 immoutb_p(4|2,10);
209
210
211 __asm__("outb %%al,$12\n\tjmp 1f\n1:\tjmp 1f\n1:\t"
212 "outb %%al,$11\n\tjmp 1f\n1:\tjmp 1f\n1:"::
213 "a" ((char) ((command == FD_READ)?DMA_READ:DMA_WRITE)));
214
215 immoutb_p(addr,4);
216 addr >>= 8;
217
218 immoutb_p(addr,4);
219 addr >>= 8;
220
221 immoutb_p(addr,0x81);
222
223 count--;
224 immoutb_p(count,5);
225 count >>= 8;
226
227 immoutb_p(count,5);
228
229 immoutb_p(0|2,10);
230 sti();
231 }
232
233 static void output_byte(char byte)
234 {
235 int counter;
236 unsigned char status;
237
238 if (reset)
239 return;
240 for(counter = 0 ; counter < 10000 ; counter++) {
241 status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR);
242 if (status == STATUS_READY) {
243 outb(byte,FD_DATA);
244 return;
245 }
246 }
247 current_track = NO_TRACK;
248 reset = 1;
249 printk("Unable to send byte to FDC\n\r");
250 }
251
252 static int result(void)
253 {
254 int i = 0, counter, status;
255
256 if (reset)
257 return -1;
258 for (counter = 0 ; counter < 10000 ; counter++) {
259 status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY);
260 if (status == STATUS_READY)
261 return i;
262 if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) {
263 if (i >= MAX_REPLIES)
264 break;
265 reply_buffer[i++] = inb_p(FD_DATA);
266 }
267 }
268 reset = 1;
269 current_track = NO_TRACK;
270 printk("Getstatus times out\n\r");
271 return -1;
272 }
273
274 static void bad_flp_intr(void)
275 {
276 current_track = NO_TRACK;
277 CURRENT->errors++;
278 if (CURRENT->errors > MAX_ERRORS) {
279 floppy_deselect(current_drive);
280 end_request(0);
281 }
282 if (CURRENT->errors > MAX_ERRORS/2)
283 reset = 1;
284 else
285 recalibrate = 1;
286 }
287
288
289
290
291
292 static void rw_interrupt(void)
293 {
294 char * buffer_area;
295
296 if (result() != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73)) {
297 if (ST1 & 0x02) {
298 printk("Drive %d is write protected\n\r",current_drive);
299 floppy_deselect(current_drive);
300 end_request(0);
301 } else
302 bad_flp_intr();
303 do_fd_request();
304 return;
305 }
306 if (read_track) {
307 buffer_track = seek_track;
308 buffer_drive = current_drive;
309 buffer_area = floppy_track_buffer +
310 ((sector-1 + head*floppy->sect)<<9);
311 copy_buffer(buffer_area,CURRENT->buffer);
312 } else if (command == FD_READ &&
313 (unsigned long)(CURRENT->buffer) >= 0x100000)
314 copy_buffer(tmp_floppy_area,CURRENT->buffer);
315 floppy_deselect(current_drive);
316 end_request(1);
317 do_fd_request();
318 }
319
320
321
322
323
324
325
326
327 inline void setup_rw_floppy(void)
328 {
329 setup_DMA();
330 do_floppy = rw_interrupt;
331 output_byte(command);
332 if (read_track) {
333 output_byte(current_drive);
334 output_byte(track);
335 output_byte(0);
336 output_byte(1);
337 } else {
338 output_byte(head<<2 | current_drive);
339 output_byte(track);
340 output_byte(head);
341 output_byte(sector);
342 }
343 output_byte(2);
344 output_byte(floppy->sect);
345 output_byte(floppy->gap);
346 output_byte(0xFF);
347 if (reset)
348 do_fd_request();
349 }
350
351
352
353
354
355
356 static void seek_interrupt(void)
357 {
358
359 output_byte(FD_SENSEI);
360 if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) {
361 recalibrate = 1;
362 bad_flp_intr();
363 do_fd_request();
364 return;
365 }
366 current_track = ST1;
367 setup_rw_floppy();
368 }
369
370
371
372
373
374
375 static void transfer(void)
376 {
377 read_track = (command == FD_READ) && (CURRENT->errors < 4);
378 if (cur_spec1 != floppy->spec1) {
379 cur_spec1 = floppy->spec1;
380 output_byte(FD_SPECIFY);
381 output_byte(cur_spec1);
382 output_byte(6);
383 }
384 if (cur_rate != floppy->rate)
385 outb_p(cur_rate = floppy->rate,FD_DCR);
386 if (reset) {
387 do_fd_request();
388 return;
389 }
390 if (!seek) {
391 setup_rw_floppy();
392 return;
393 }
394 do_floppy = seek_interrupt;
395 output_byte(FD_SEEK);
396 if (read_track)
397 output_byte(current_drive);
398 else
399 output_byte((head<<2) | current_drive);
400 output_byte(seek_track);
401 if (reset)
402 do_fd_request();
403 }
404
405
406
407
408 static void recal_interrupt(void)
409 {
410 output_byte(FD_SENSEI);
411 current_track = NO_TRACK;
412 if (result()!=2 || (ST0 & 0xE0) == 0x60)
413 reset = 1;
414 do_fd_request();
415 }
416
417 void unexpected_floppy_interrupt(void)
418 {
419 current_track = NO_TRACK;
420 output_byte(FD_SENSEI);
421 if (result()!=2 || (ST0 & 0xE0) == 0x60)
422 reset = 1;
423 else
424 recalibrate = 1;
425 }
426
427 static void recalibrate_floppy(void)
428 {
429 recalibrate = 0;
430 current_track = 0;
431 do_floppy = recal_interrupt;
432 output_byte(FD_RECALIBRATE);
433 output_byte(head<<2 | current_drive);
434 if (reset)
435 do_fd_request();
436 }
437
438 static void reset_interrupt(void)
439 {
440 output_byte(FD_SENSEI);
441 (void) result();
442 output_byte(FD_SPECIFY);
443 output_byte(cur_spec1);
444 output_byte(6);
445 do_fd_request();
446 }
447
448
449
450
451 static void reset_floppy(void)
452 {
453 int i;
454
455 do_floppy = reset_interrupt;
456 reset = 0;
457 current_track = NO_TRACK;
458 cur_spec1 = -1;
459 cur_rate = -1;
460 recalibrate = 1;
461 printk("Reset-floppy called\n\r");
462 cli();
463 outb_p(current_DOR & ~0x04,FD_DOR);
464 for (i=0 ; i<1000 ; i++)
465 __asm__("nop");
466 outb(current_DOR,FD_DOR);
467 sti();
468 }
469
470 static void floppy_on_interrupt(void)
471 {
472 if (inb(FD_DIR) & 0x80) {
473 changed_floppies |= 1<<current_drive;
474 buffer_track = -1;
475 }
476 if (reset) {
477 reset_floppy();
478 return;
479 }
480 if (recalibrate) {
481 recalibrate_floppy();
482 return;
483 }
484
485 selected = 1;
486 if (current_drive != (current_DOR & 3)) {
487 seek = 1;
488 current_track = NO_TRACK;
489 current_DOR &= 0xFC;
490 current_DOR |= current_drive;
491 outb(current_DOR,FD_DOR);
492 add_timer(2,&transfer);
493 } else
494 transfer();
495 }
496
497 void do_fd_request(void)
498 {
499 unsigned int block;
500 char * buffer_area;
501
502 INIT_REQUEST;
503 seek = 0;
504 floppy = (MINOR(CURRENT->dev)>>2) + floppy_type;
505 if (current_drive != CURRENT_DEV)
506 current_track = NO_TRACK;
507 current_drive = CURRENT_DEV;
508 block = CURRENT->sector;
509 if (block+2 > floppy->size) {
510 end_request(0);
511 goto repeat;
512 }
513 sector = block % floppy->sect;
514 block /= floppy->sect;
515 head = block % floppy->head;
516 track = block / floppy->head;
517 seek_track = track << floppy->stretch;
518 if (CURRENT->cmd == READ)
519 command = FD_READ;
520 else if (CURRENT->cmd == WRITE)
521 command = FD_WRITE;
522 else {
523 printk("do_fd_request: unknown command\n");
524 end_request(0);
525 goto repeat;
526 }
527 if ((seek_track == buffer_track) &&
528 (current_drive == buffer_drive)) {
529 buffer_area = floppy_track_buffer +
530 ((sector + head*floppy->sect)<<9);
531 if (command == FD_READ) {
532 copy_buffer(buffer_area,CURRENT->buffer);
533 end_request(1);
534 goto repeat;
535 } else
536 copy_buffer(CURRENT->buffer,buffer_area);
537 }
538 if (seek_track != current_track)
539 seek = 1;
540 sector++;
541 add_timer(ticks_to_floppy_on(current_drive),&floppy_on_interrupt);
542 }
543
544 static int floppy_sizes[] ={
545 0, 0, 0, 0,
546 360, 360 ,360, 360,
547 1200,1200,1200,1200,
548 360, 360, 360, 360,
549 720, 720, 720, 720,
550 360, 360, 360, 360,
551 720, 720, 720, 720,
552 1440,1440,1440,1440
553 };
554
555 void floppy_init(void)
556 {
557 outb(current_DOR,FD_DOR);
558 blk_size[MAJOR_NR] = floppy_sizes;
559 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
560 set_intr_gate(0x26,&floppy_interrupt);
561 outb(inb_p(0x21)&~0x40,0x21);
562 }