?? floppy.c
字號:
clear_dma_ff(FLOPPY_DMA); set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE); set_dma_addr(FLOPPY_DMA, addr); set_dma_count(FLOPPY_DMA, count); enable_dma(FLOPPY_DMA); sti();}static void output_byte(char byte){ int counter; unsigned char status; if (reset) return; for(counter = 0 ; counter < 10000 ; counter++) { status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); if (status == STATUS_READY) { outb(byte,FD_DATA); return; } } current_track = NO_TRACK; reset = 1; printk("Unable to send byte to FDC\n");}static int result(void){ int i = 0, counter, status; if (reset) return -1; for (counter = 0 ; counter < 10000 ; counter++) { status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); if (status == STATUS_READY) { return i; } if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { if (i >= MAX_REPLIES) { printk("floppy_stat reply overrun\n"); break; } reply_buffer[i++] = inb_p(FD_DATA); } } reset = 1; current_track = NO_TRACK; printk("Getstatus times out\n"); return -1;}static void bad_flp_intr(void){ int errors; current_track = NO_TRACK; if (format_status == FORMAT_BUSY) errors = ++format_errors; else if (!CURRENT) { printk(DEVICE_NAME ": no current request\n"); reset = recalibrate = 1; return; } else errors = ++CURRENT->errors; if (errors > MAX_ERRORS) { request_done(0); } if (errors > MAX_ERRORS/2) reset = 1; else recalibrate = 1;} /* Set perpendicular mode as required, based on data rate, if supported. * 82077 Untested! 1Mbps data rate only possible with 82077-1. * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries. */static inline void perpendicular_mode(unsigned char rate){ if (fdc_version == FDC_TYPE_82077) { output_byte(FD_PERPENDICULAR); if (rate & 0x40) { unsigned char r = rate & 0x03; if (r == 0) output_byte(2); /* perpendicular, 500 kbps */ else if (r == 3) output_byte(3); /* perpendicular, 1Mbps */ else { printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n"); reset = 1; } } else output_byte(0); /* conventional mode */ } else { if (rate & 0x40) { printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n"); reset = 1; } }} /* perpendicular_mode *//* * This has only been tested for the case fdc_version == FDC_TYPE_STD. * In case you have a 82077 and want to test it, you'll have to compile * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for * recognizing drives with vertical recording support. */static void configure_fdc_mode(void){ if (need_configure && (fdc_version == FDC_TYPE_82077)) { /* Enhanced version with FIFO & vertical recording. */ output_byte(FD_CONFIGURE); output_byte(0); output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */ output_byte(0); /* precompensation from track 0 upwards */ need_configure = 0; printk(DEVICE_NAME ": FIFO enabled\n"); } if (cur_spec1 != floppy->spec1) { cur_spec1 = floppy->spec1; output_byte(FD_SPECIFY); output_byte(cur_spec1); /* hut etc */ output_byte(6); /* Head load time =6ms, DMA */ } if (cur_rate != floppy->rate) { /* use bit 6 of floppy->rate to indicate perpendicular mode */ perpendicular_mode(floppy->rate); outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR); }} /* configure_fdc_mode */static void tell_sector(int nr){ if (nr!=7) { printk(" -- FDC reply errror"); reset = 1; } else printk(": track %d, head %d, sector %d", reply_buffer[3], reply_buffer[4], reply_buffer[5]);} /* tell_sector *//* * Ok, this interrupt is called after a DMA read/write has succeeded * or failed, so we check the results, and copy any buffers. * hhb: Added better error reporting. */static void rw_interrupt(void){ char * buffer_area; int nr; char bad; nr = result(); /* check IC to find cause of interrupt */ switch ((ST0 & ST0_INTR)>>6) { case 1: /* error occured during command execution */ bad = 1; if (ST1 & ST1_WP) { printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive); request_done(0); bad = 0; } else if (ST1 & ST1_OR) { if (ftd_msg[ST0 & ST0_DS]) printk(DEVICE_NAME ": Over/Underrun - retrying\n"); /* could continue from where we stopped, but ... */ bad = 0; } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) { printk(DEVICE_NAME " %d: ", ST0 & ST0_DS); if (ST0 & ST0_ECE) { printk("Recalibrate failed!"); } else if (ST2 & ST2_CRC) { printk("data CRC error"); tell_sector(nr); } else if (ST1 & ST1_CRC) { printk("CRC error"); tell_sector(nr); } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) { if (!probing) { printk("sector not found"); tell_sector(nr); } else printk("probe failed..."); } else if (ST2 & ST2_WC) { /* seek error */ printk("wrong cylinder"); } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ printk("bad cylinder"); } else { printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3); } printk("\n"); } if (bad) bad_flp_intr(); redo_fd_request(); return; case 2: /* invalid command given */ printk(DEVICE_NAME ": Invalid FDC command given!\n"); request_done(0); return; case 3: printk(DEVICE_NAME ": Abnormal termination caused by polling\n"); bad_flp_intr(); redo_fd_request(); return; default: /* (0) Normal command termination */ break; } if (probing) { int drive = MINOR(CURRENT->dev); if (ftd_msg[drive]) printk("Auto-detected floppy type %s in fd%d\n", floppy->name,drive); current_type[drive] = floppy; floppy_sizes[drive] = floppy->size >> 1; probing = 0; } if (read_track) { buffer_track = seek_track; buffer_drive = current_drive; buffer_area = floppy_track_buffer + ((sector-1 + head*floppy->sect)<<9); copy_buffer(buffer_area,CURRENT->buffer); } else if (command == FD_READ && (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR) copy_buffer(tmp_floppy_area,CURRENT->buffer); request_done(1); redo_fd_request();}/* * We try to read tracks, but if we get too many errors, we * go back to reading just one sector at a time. * * This means we should be able to read a sector even if there * are other bad sectors on this track. */inline void setup_rw_floppy(void){ setup_DMA(); do_floppy = rw_interrupt; output_byte(command); if (command != FD_FORMAT) { if (read_track) { output_byte(current_drive); output_byte(track); output_byte(0); output_byte(1); } else { output_byte(head<<2 | current_drive); output_byte(track); output_byte(head); output_byte(sector); } output_byte(2); /* sector size = 512 */ output_byte(floppy->sect); output_byte(floppy->gap); output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ } else { output_byte(head<<2 | current_drive); output_byte(2); output_byte(floppy->sect); output_byte(floppy->fmt_gap); output_byte(FD_FILL_BYTE); } if (reset) redo_fd_request();}/* * This is the routine called after every seek (or recalibrate) interrupt * from the floppy controller. Note that the "unexpected interrupt" routine * also does a recalibrate, but doesn't come here. */static void seek_interrupt(void){/* sense drive status */ output_byte(FD_SENSEI); if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { printk(DEVICE_NAME ": seek failed\n"); recalibrate = 1; bad_flp_intr(); redo_fd_request(); return; } current_track = ST1; setup_rw_floppy();}/* * This routine is called when everything should be correctly set up * for the transfer (ie floppy motor is on and the correct floppy is * selected). */static void transfer(void){ read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) && (floppy->sect <= MAX_BUFFER_SECTORS); configure_fdc_mode(); if (reset) { redo_fd_request(); return; } if (!seek) { setup_rw_floppy(); return; } do_floppy = seek_interrupt; output_byte(FD_SEEK); if (read_track) output_byte(current_drive); else output_byte((head<<2) | current_drive); output_byte(seek_track); if (reset) redo_fd_request();}/* * Special case - used after a unexpected interrupt (or reset) */static void recalibrate_floppy(void);static void recal_interrupt(void){ output_byte(FD_SENSEI); current_track = NO_TRACK; if (result()!=2 || (ST0 & 0xE0) == 0x60) reset = 1;/* Recalibrate until track 0 is reached. Might help on some errors. */ if ((ST0 & 0x10) == 0x10) recalibrate_floppy(); /* FIXME: should limit nr of recalibrates */ else redo_fd_request();}static void unexpected_floppy_interrupt(void){ current_track = NO_TRACK; output_byte(FD_SENSEI); printk(DEVICE_NAME ": unexpected interrupt\n"); if (result()!=2 || (ST0 & 0xE0) == 0x60) reset = 1; else recalibrate = 1;}static void recalibrate_floppy(void){ recalibrate = 0; current_track = 0; do_floppy = recal_interrupt; output_byte(FD_RECALIBRATE); output_byte(head<<2 | current_drive); if (reset) redo_fd_request();}/* * Must do 4 FD_SENSEIs after reset because of ``drive polling''. */static void reset_interrupt(void){ short i; for (i=0; i<4; i++) { output_byte(FD_SENSEI); (void) result(); } output_byte(FD_SPECIFY); output_byte(cur_spec1); /* hut etc */ output_byte(6); /* Head load time =6ms, DMA */ configure_fdc_mode(); /* reprogram fdc */ if (initial_reset_flag) { initial_reset_flag = 0; recalibrate = 1; reset = 0; return; } if (!recover) redo_fd_request(); else { recalibrate_floppy(); recover = 0; }}/* * reset is done by pulling bit 2 of DOR low for a while. */static void reset_floppy(void){ int i; do_floppy = reset_interrupt; reset = 0; current_track = NO_TRACK; cur_spec1 = -1; cur_rate = -1; recalibrate = 1; need_configure = 1; if (!initial_reset_flag) printk("Reset-floppy called\n"); cli(); outb_p(current_DOR & ~0x04, FD_DOR); for (i=0 ; i<1000 ; i++) __asm__("nop"); outb(current_DOR, FD_DOR); sti();}static void floppy_shutdown(void){ cli(); do_floppy = NULL; request_done(0); recover = 1; reset_floppy(); sti(); redo_fd_request();}static void shake_done(void){ current_track = NO_TRACK; if (inb(FD_DIR) & 0x80) request_done(0); redo_fd_request();}static int retry_recal(void (*proc)(void)){ output_byte(FD_SENSEI); if (result() == 2 && (ST0 & 0x10) != 0x10) return 0; do_floppy = proc; output_byte(FD_RECALIBRATE); output_byte(head<<2 | current_drive); return 1;}static void shake_zero(void){ if (!retry_recal(shake_zero)) shake_done();}static void shake_one(void){ if (retry_recal(shake_one)) return; do_floppy = shake_done; output_byte(FD_SEEK); output_byte(head << 2 | current_drive);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -