4 * The floppy driver but now seems can't work correctly
6 * Aleaxander (C) 2007-2008
16 #include <asm/system.h>
21 extern unsigned long count_down
;
30 #define immoutb_p(val,port) \
31 __asm__("outb %0,%1\n\tjmp 1f\n1:\tjmp 1f\n1:"::"a" ((char) (val)),"i" (port))
34 /* these are globals used by get_result() */
36 static unsigned char reply_buffer
[MAX_REPLIES
];
37 #define ST0 (reply_buffer[0])
38 #define ST1 (reply_buffer[1])
39 #define ST2 (reply_buffer[2])
40 #define ST3 (reply_buffer[3])
43 static struct floppy_struct
{
44 unsigned int size
, sector
, head
, track
, stretch
;
45 unsigned char gap
,rate
,spec1
;
48 0x1b,0x00,0xCF /* 1.44MB diskette */
52 /* Store the return vaule of get_result, we need it to do some check */
55 static int done
= FALSE
;
56 static int motoron
= FALSE
;
57 static int changed
= FALSE
;
58 static unsigned char sr0
;
59 static unsigned char fdc_track
= 255;
65 * send a byte to FD_DATA register
66 * @param: byte is the byte that needed to send to the FD_DATA
69 static void send_byte(unsigned char byte
)
74 //LOG("send_byte() called ...\n");
76 for (counter
= 0; counter
< 1000; counter
++) {
77 sleep(1); /* delay 10s */
78 msr
= inb_p(FD_STATUS
) & (STATUS_READY
| STATUS_DIR
);
79 if (msr
== STATUS_READY
) {
84 LOG("Unable to send byte to FDC\n");
87 * get *ONE* byte of results from FD_DATA register then return what
88 * it get, or retrun -1 if faile.
95 //LOG("get_byte() called ...\n");
97 for (counter
= 0; counter
< 1000; counter
++) {
98 sleep(1); /* delay 10ms */
99 msr
= inb_p(FD_STATUS
) & (STATUS_DIR
|STATUS_READY
|STATUS_BUSY
);
100 if (msr
== (STATUS_DIR
|STATUS_READY
|STATUS_BUSY
))
101 return inb_p(FD_DATA
);
103 LOG("get_byte: get status times out!\n");
108 * get *ALL* the results from the FD_DATA register then store
109 * it in the global fileds reply_buffer. that's the only
110 * diffrence between get_byte() and get_result().
113 * @return: the number of reply chars
116 static int get_result(void)
118 int i
= 0, counter
, msr
;
120 //LOG("get_result() called ...\n");
122 for (counter
= 0; counter
< 1000; counter
++) {
123 sleep(1); /* delay 10ms */
124 msr
= inb_p(FD_STATUS
) & (STATUS_DIR
|STATUS_READY
|STATUS_BUSY
);
125 //LOG("msr %d: %x\n", i, msr);
126 if (msr
== STATUS_READY
)
128 if (msr
== (STATUS_DIR
|STATUS_READY
|STATUS_BUSY
)) {
129 if ( i
>= MAX_REPLIES
)
131 reply_buffer
[i
++] = inb_p(FD_DATA
);
134 LOG("get_result:get status times out!\n");
141 * This waits for FDC command to complete
144 * @return: if successfull then returns TRUE, or FALSE
147 static int wait_fdc(int sensei
)
150 count_down
= 1000; /* set count_down init. value to 2 second */
152 /* wait for FLOPPY_INTERRUPT hander to signal command finished */
153 while (!done
&& count_down
)
155 time_out
= count_down
;
158 printk("time_out:%d\n",time_out
);
159 printk("done: %d\n",done
);
161 res
= get_result(); /* get the result of the command */
165 * we use get_byte() but NOT get_result() here, because i don't
166 * know where the error happened. or maybe get_byte() is better
167 * than get_result(), it just come from the test
175 memset(reply_buffer
, 0, sizeof(reply_buffer
));
178 hexdump(reply_buffer
, sizeof(reply_buffer
));
182 /* send a "sense interrupt status" command */
183 send_byte(FD_SENSEI
);
185 fdc_track
= get_byte();
188 LOG("time left: %d\t done: %d\n", time_out
, done
);
198 * Converts liner sector address to head/track/sector
200 * @param: sector is the liner sector we wanna convert.
201 * @param: *head, save the head number to head
202 * @param: *track, save the track number to track
203 * @param: *sector, save the sector number to sector
205 * we return all the info. by the POINTER args
208 static void lba_to_chs(int line_sector
, int *head
, int *track
, int *sector
)
210 //LOG("sector_to_hts() called ...\n");
211 *sector
= line_sector
% floppy
.sector
;
214 line_sector
/= floppy
.sector
;
216 *head
= line_sector
% floppy
.head
;
217 *track
= line_sector
/ floppy
.head
;
221 /* test whether the motor is on or not */
222 static inline int is_motor_on()
224 //LOG("is_motor_on() called ...\n");
230 /* Turns the motor on if not */
231 static void motor_on(void)
233 //LOG("motor_on() called ...\n");
234 if ( !is_motor_on()) {
236 sleep(100); /* delay 1 second for motor on */
242 /* Truns the motor off if on */
243 static void motor_off (void)
245 //LOG("motor_off() called ...\n");
246 if (is_motor_on() ) {
247 count_down
= 200; /* start motor kill countdown: about 2s */
256 /* recalibrate the drive */
257 static void recalibrate(void)
260 //LOG("recalibrate() called ...\n");
262 /*turn the motor on first */
265 /* send actual command bytes */
266 send_byte(FD_RECALIBRATE
);
269 /* wait until seek finished */
276 static int seek(int track
, int head
)
278 //LOG("seek() called ...\n");
282 LOG("RECALIBRATE...\n");
288 if (fdc_track
== track
)
289 return TRUE
; /* already there*/
291 /* send actual command bytes */
293 send_byte(head
<< 2);
296 /* wait until seek finished */
297 if ( !wait_fdc(TRUE
) )
298 ;//return FALSE; /* time out */
300 LOG("ST0: %x\t ST1: %x\n", sr0
, fdc_track
);
301 if ( ((sr0
& 0xF8) != 0x20) || (fdc_track
!= track
)) {
302 LOG("Seek track#: %d failed\n", track
);
305 LOG("Seek track#: %d OK ...\n", track
);
316 * The first thing that the driver needs to do is reset the controller.This
317 * will put it in a known state. To reset the primary floppy controller,(in C)
319 * 1.write 0x00 to the DIGITAL_OUTPUT_REG of the desired controller
320 * 2.write 0x0C to the DIGITAL_OUTPUT_REG of the desired controller
321 * 3.wait for an interrupt from the controller
322 * 4.check interrupt status (this is function 0x08 of controllers)
323 * 5.write 0x00 to the CONFIG_CONTROL_REG
324 * 6.configure the drive desired on the controller (function 0x03 of controller)
325 * 7.calibrate the drive (function 0x07 of controller)
330 //LOG("reset() called ...\n");
332 /* stop the motor and disable IRQ/DMA */
335 /* program data rate (500K/s) */
338 /* re-enable interrupts */
341 /* resetting triggered an interrupt - handle it */
345 /* specify drive timings (got these off the BIOS) */
346 send_byte(FD_SPECIFY
);
347 send_byte(0xdf); /* SRT = 3ms, HUT = 240ms */
348 send_byte(0x06); /* HLT = 16ms, ND = 0 */
356 * here we will setup the DMA, then we can use it to transfer data
357 * more efficiently. For now, we just make it transfer one sector's
361 static void setup_DMA(unsigned long addr
, int command
)
363 int cmd
= (command
== FD_READ
) ? DMA_READ
: DMA_WRITE
;
366 cli(); /* we need a safe env. */
368 immoutb_p(4|2,0x0a); /* mask DMA 2 */
370 immoutb_p(0,0x0c); /* clear flip flop */
374 immoutb_p(addr
,4); /* 8 low bits of addr */
377 immoutb_p(addr
,4); /* bits 8-15 of addr */
380 immoutb_p(addr
,0x81); /* bits 16-19 of addr */
382 immoutb_p(count
& 0xff,5); /* low 8 bits of count-1 (1024-1=0x3ff) */
384 immoutb_p(count
>> 8,5); /* high 8 bits of count-1 */
386 immoutb_p(0|2,10); /* activate DMA 2 */
392 * And now, it's time to implenent the read or write function, that's
393 * all the floppy driver mean!
395 * Read/Write one sector once.
397 static int floppy_rw(int sector
, char *buf
, int command
)
400 char *dma_buffer
= buf
;
401 static char tmp_dma_buffer
[512];
403 LOG("TMP dma buffer: %p\n", tmp_dma_buffer
);
405 lba_to_chs(sector
, &head
, &track
, §or
);
406 LOG("head: %d \ttrack: %d \tsector: %d\n", head
, track
, sector
);
408 /* turn it on if not */
411 if (inb_p(FD_DIR
) & 0x80) {
413 seek(1, head
); /* clear "disk change" status */
416 printk("floppy_rw: Disk change detected. You are going to DIE:)\n");
418 pause(); /* just put it in DIE */
421 /* move head to the right track */
422 if (!seek(track
, head
)) {
424 printk("floppy_rw: Error seeking to track#%d\n", track
);
428 if ((unsigned long)buf
>= 0xff000) {
429 dma_buffer
= tmp_dma_buffer
;
430 if (command
== FD_WRITE
)
431 memcpy(dma_buffer
, buf
, 512);
434 setup_DMA((unsigned long)dma_buffer
, command
);
437 send_byte(head
<<2 | 0);
441 send_byte(2); /* sector size = 125 * 2^(2) */
442 send_byte(floppy
.sector
);
444 send_byte(0xFF); /* sector size(only two valid vaules, 0xff when n!=0*/
446 if (!wait_fdc(FALSE
)) {
447 LOG("wait fdc failed!\n");
450 printk("Time out, trying operation again after reset() \n");
452 return floppy_rw(sector, buf, command);
458 if (/*res != 7 || */(ST0
& 0xf8) || (ST1
& 0xbf) || (ST2
& 0x73) ) {
460 printk("Drive is write protected!\n");
462 printk("floppy_rw: bad interrupt!\n");
466 LOG("floppy_rw: OK\n");
467 if ((unsigned long)buf
>= 0xff000 && command
== FD_READ
)
468 memcpy(buf
, dma_buffer
, 512);
474 /* Read ONE sector */
475 void floppy_read(int sector
, void * buf
)
477 floppy_rw(sector
, buf
, FD_READ
);
480 /* Write ONE sector */
481 void floppy_write(int sector
, void * buf
)
483 floppy_rw(sector
, buf
, FD_WRITE
);
487 * The two following function handles multi-sectors reading
490 void floppy_reads(int sector
, void *buf
, unsigned int sectors
)
493 floppy_rw(sector
++, buf
, FD_READ
);
498 void floppy_writes(int sector
, void *buf
, unsigned int sectors
)
501 floppy_rw(sector
++, buf
, FD_WRITE
);
506 static int times
= 0;
508 * The FLOPPY_INTERRUPT handler
510 * FIXME: the current do_floppy seems wouldn't be called after every
511 * interrupt. I have no idea what's wrong with it.
515 //LOG("floppy_interrupt() called ...\n");
517 //LOG("floppy interrupt %d times!\n",times);
518 /* signal operation finished */
520 outb(0x20,0x20); /* EOI */
524 * OK, finally we got our last thing to do. You are right, that's it,
525 * initialing the floppy. As you know, initialization is always easy,
526 * just set the interrupt handler and mask off the bit of corresponding
529 void floppy_init(void)
531 set_trap_gate(0x26, floppy_interrupt
);
532 outb(inb_p(0x21)&~0x40,0x21);
540 LOG("BUF addr: %p\n", buf
);
542 floppy_read(70, buf
);
549 char str
[512 * 10] = "hello word! This is just a floppy writing test";
550 char *buf
= (char *)0x800000;
551 memcpy(buf
, str
, sizeof(str
));
553 LOG("STRING addr: %p\n", str
);
555 floppy_write(0, str
);
556 floppy_writes(0, buf
, 10);
557 LOG("interrupts happens %d times\n", times
);