📄 fdc-io.c
字号:
*/ out[0] = operation; out[1] = FTAPE_UNIT; out[2] = buff->cyl; out[3] = buff->head; out[4] = buff->sect + buff->sector_offset; out[5] = 3; /* Sector size of 1K. */ out[6] = out[4] + buff->sector_count - 1; /* last sector */ out[7] = 109; /* Gap length. */ out[8] = 0xff; /* No limit to transfer size. */ restore_flags(flags); TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", out[2], out[3], out[4], out[6] - out[4] + 1); result = fdc_command(out, 9); if (result != 0) { fdc_mode = fdc_idle; TRACE(1, "fdc_command failed"); } fdc_setup_error = result; TRACE_EXIT; return result;}int fdc_fifo_enable(void){ TRACE_FUN(8, "fdc_fifo_enable"); int result = 0; byte cmd0[] = {FDC_DUMPREGS}; byte cmd1[] = {FDC_CONFIGURE, 0, 0x07, 0}; /* enable fifo, thr = 8 */ byte cmd2[] = {FDC_LOCK}; byte cmd3[] = {FDC_UNLOCK}; byte stat; byte reg[10]; int i; if (CLK_48MHZ && fdc.type >= i82078) cmd1[0] |= FDC_CLK48_BIT; if (!fdc_fifo_locked) { /* Dump fdc internal registers for examination */ result = fdc_command(cmd0, NR_ITEMS(cmd0)); if (result < 0) { TRACE(2, "FDC dumpreg command failed, fifo unchanged"); result = -EIO; } else { /* Now read fdc internal registers from fifo */ for (i = 0; i < NR_ITEMS(reg); ++i) { fdc_read(®[i]); TRACEx2(6, "Register %d = 0x%02x", i, reg[i]); } fdc_fifo_state = (reg[8] & 0x20) == 0; fdc_lock_state = reg[7] & 0x80; fdc_fifo_thr = 1 + (reg[8] & 0x0f); TRACEx3(5, "original fifo state: %sabled, threshold %d, %slocked", (fdc_fifo_state) ? "en" : "dis", fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); /* If fdc is already locked, unlock it first ! */ if (fdc_lock_state) { fdc_ready_wait(100); result = fdc_command(cmd3, NR_ITEMS(cmd3)); if (result < 0) { TRACE(-1, "FDC unlock command failed, configuration unchanged"); result = -EIO; } } /* Enable fifo and set threshold at xx bytes to allow a * reasonably large latency and reduce number of dma bursts. */ fdc_ready_wait(100); result = fdc_command(cmd1, NR_ITEMS(cmd1)); if (result < 0) { TRACE(-1, "FDC configure command failed, fifo unchanged"); result = -EIO; } else { /* Now lock configuration so reset will not change it */ result = fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1); if (result < 0 || stat != 0x10) { TRACEx1(-1, "FDC lock command failed, stat = 0x%02x", stat); result = -EIO; } else { fdc_fifo_locked = 1; result = 0; } } } } else { TRACE(2, "Fifo not enabled because locked"); } TRACE_EXIT; return result;}/* Determine fd controller type */static byte fdc_save_state[2] = {0, 0};int fdc_probe(void){ TRACE_FUN(8, "fdc_probe"); byte cmd[1]; byte stat[16]; /* must be able to hold dumpregs & save results */ int result; /* Try to find out what kind of fd controller we have to deal with * Scheme borrowed from floppy driver: * first try if FDC_DUMPREGS command works * (this indicates that we have a 82072 or better) * then try the FDC_VERSION command (82072 doesn't support this) * then try the FDC_UNLOCK command (some older 82077's don't support this) * then try the FDC_PARTID command (82078's support this) */ cmd[0] = FDC_DUMPREGS; result = fdc_issue_command(cmd, 1, stat, 1); if (result == 0) { if (stat[0] == 0x80) { /* invalid command: must be pre 82072 */ TRACE(2, "Type 8272A/765A compatible FDC found"); result = i8272; } else { fdc_result(&stat[1], 9); fdc_save_state[0] = stat[7]; fdc_save_state[1] = stat[8]; cmd[0] = FDC_VERSION; result = fdc_issue_command(cmd, 1, stat, 1); if (result < 0 || stat[0] == 0x80) { TRACE(2, "Type 82072 FDC found"); result = i8272; } else if (*stat == 0x90) { cmd[0] = FDC_UNLOCK; result = fdc_issue_command(cmd, 1, stat, 1); if (result < 0 || stat[0] != 0x00) { TRACE(2, "Type pre-1991 82077 FDC found, treating it like a 82072"); result = i8272; } else { int i; if (fdc_save_state[0] & 0x80) { /* was locked */ cmd[0] = FDC_LOCK; /* restore lock */ result = fdc_issue_command(cmd, 1, stat, 1); TRACE(2, "FDC is already locked"); } /* Test for a i82078 FDC */ cmd[0] = FDC_PARTID; result = fdc_issue_command(cmd, 1, stat, 1); if (result < 0 || stat[0] == 0x80) { /* invalid command: not a i82078xx type FDC */ result = no_fdc; for (i = 0; i < 4; ++i) { outb_p(i, fdc.tdr); if ((inb_p(fdc.tdr) & 0x03) != i) { result = i82077; break; } } if (result == no_fdc) { result = i82077AA; TRACE(2, "Type 82077AA FDC found"); } else { TRACE(2, "Type 82077 FDC found"); } } else { /* FDC_PARTID cmd succeeded */ switch (stat[0] >> 5) { case 0x0: /* i82078SL or i82078-1. The SL part cannot run at 2Mbps (the * SL and -1 dies are identical; they are speed graded after * production, according to Intel). Some SL's can be detected * by doing a SAVE cmd and look at bit 7 of the first byte (the * SEL3V# bit). If it is 0, the part runs off 3Volts, and hence * it is a SL. */ cmd[0] = FDC_SAVE; result = fdc_issue_command(cmd, 1, stat, 16); if (result < 0) { TRACE(1, "FDC_SAVE failed. Dunno why"); /* guess we better claim the fdc to be a i82078 */ result = i82078; TRACE(2, "Type i82078 FDC (i suppose) found"); } else { if ((stat[0] & FDC_SEL3V_BIT)) { /* fdc running off 5Volts; Pray that it's a i82078-1 */ TRACE(2, "Type i82078-1 or 5Volt i82078SL FDC found"); TRACE(2, "Treating it as an i82078-1 (2Mbps) FDC"); result = i82078_1; } else { TRACE(2, "Type 3Volt i82078SL FDC (1Mbps) found"); result = i82078; } } break; case 0x1: case 0x2: /* S82078B (?!) */ /* 44pin i82078 found */ result = i82078; TRACE(2, "Type i82078 FDC found"); break; case 0x3: /* NSC PC8744 core; used in several super-IO chips */ result = i82077AA; TRACE(2, "Type 82077AA compatible FDC found"); break; default: TRACE(2, "A previously undetected FDC found"); TRACEi(2, "Treating it as a 82077AA. Please report partid=", stat[0]); result = i82077AA; } /* switch(stat[ 0] >> 5) */ } /* if (result < 0 || stat[ 0] == 0x80) */ } } else { TRACE(2, "Unknown FDC found"); result = i8272; } } } else { TRACE(-1, "No FDC found"); result = no_fdc; } TRACE_EXIT; return result;}void fdc_config_regs(unsigned fdc_base, unsigned fdc_irq, unsigned fdc_dma){ fdc.irq = fdc_irq; fdc.dma = fdc_dma; fdc.sra = fdc_base; fdc.srb = fdc_base + 1; fdc.dor = fdc_base + 2; fdc.tdr = fdc_base + 3; fdc.msr = fdc.dsr = fdc_base + 4; fdc.fifo = fdc_base + 5;#if defined MACH2 || defined PROBE_FC10 fdc.dor2 = fdc_base + 6;#endif fdc.dir = fdc.ccr = fdc_base + 7;}/* If probing for a FC-10/20 controller the fdc base address, interrupt * and dma channel must be specified. * If using an alternate fdc controller, base address, interrupt and * dma channel must be specified. */#if defined PROBE_FC10 && !defined FDC_BASE#error No FDC base address (FDC_BASE) specified in Makefile!#endif#if defined FDC_BASE && !defined FDC_IRQ#error No interrupt (FDC_IRQ) specified in Makefile!#endif#if defined FDC_BASE && !defined FDC_DMA#error No dma channel (FDC_DMA) specified in Makefile!#endifvoid fdc_config(void){ TRACE_FUN(8, "fdc_config"); static int already_done = 0; if (!already_done) {#ifdef PROBE_FC10 int fc_type; fdc_config_regs(FDC_BASE, FDC_IRQ, FDC_DMA); fc_type = fc10_enable(); if (fc_type != 0) { TRACEx1(2, "FC-%c0 controller found", '0' + fc_type); fdc.type = fc10; fdc.hook = &do_ftape; } else { TRACE(2, "FC-10/20 controller not found"); fdc.type = no_fdc; fdc.dor2 = 0; /* not used with std fdc */ fdc_config_regs(0x3f0, 6, 2); /* back to std fdc again */ fdc.hook = &do_ftape; }#else#ifdef FDC_BASE TRACE(2, "Using fdc controller at alternate address"); fdc_config_regs(FDC_BASE, FDC_IRQ, FDC_DMA); fdc.hook = &do_ftape;#else TRACE(2, "Using the standard fdc controller"); fdc_config_regs(0x3f0, 6, 2); /* std fdc */ fdc.hook = &do_ftape;#endif /* !FDC_BASE */#endif /* !PROBE_FC10 */ } *(fdc.hook) = fdc_isr; /* hook our handler in */ already_done = 1; TRACE_EXIT;}static void ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs){ TRACE_FUN(8, "ftape_interrupt"); void (*handler) (void) = *fdc.hook; *fdc.hook = NULL; if (handler) { handler(); } else { TRACE(-1, "Unexpected ftape interrupt"); } TRACE_EXIT;}int fdc_grab_irq_and_dma(void){ TRACE_FUN(8, "fdc_grab_irq_and_dma"); int result = 0; if (fdc.hook == &do_ftape) { /* Get fast interrupt handler. */ result = request_irq(fdc.irq, ftape_interrupt, SA_INTERRUPT, "ftape", ftape_id); if (result) { TRACEx1(-1, "Unable to grab IRQ%d for ftape driver", fdc.irq); result = -EIO; } else { result = request_dma(fdc.dma, ftape_id); if (result) { TRACEx1(-1, "Unable to grab DMA%d for ftape driver", fdc.dma); free_irq(fdc.irq, ftape_id); result = -EIO; } else { enable_irq(fdc.irq); } } }#ifdef FDC_DMA if (result == 0 && FDC_DMA == 2) { /* Using same dma channel as standard fdc, need to disable the * dma-gate on the std fdc. This couldn't be done in the floppy * driver as some laptops are using the dma-gate to enter a * low power or even suspended state :-( */ outb_p(FDC_RESET_NOT, 0x3f2); TRACE(2, "DMA-gate on standard fdc disabled"); }#endif TRACE_EXIT; return result;}int fdc_release_irq_and_dma(void){ TRACE_FUN(8, "fdc_grab_irq_and_dma"); int result = 0; if (fdc.hook == &do_ftape) { disable_dma(fdc.dma); /* just in case... */ free_dma(fdc.dma); disable_irq(fdc.irq); free_irq(fdc.irq, ftape_id); }#ifdef FDC_DMA if (result == 0 && FDC_DMA == 2) { /* Using same dma channel as standard fdc, need to disable the * dma-gate on the std fdc. This couldn't be done in the floppy * driver as some laptops are using the dma-gate to enter a * low power or even suspended state :-( */ outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); TRACE(2, "DMA-gate on standard fdc enabled again"); }#endif TRACE_EXIT; return result;}int fdc_uninit(void){ TRACE_FUN(8, "fdc_uninit"); int result = 0; if (fdc.sra != 0) { if (fdc.dor2 == 0) { release_region(fdc.sra, 6); release_region(fdc.sra + 7, 1); } else { release_region(fdc.sra, 8); } } TRACE_EXIT; return result;}int fdc_init(void){ TRACE_FUN(8, "fdc_init"); int result = 0; fdc_config(); if (fdc_grab_irq_and_dma() < 0) { result = -EBUSY; } else { ftape_motor = 0; fdc_catch_stray_interrupts(1); /* one always comes */ TRACE(5, "resetting fdc"); fdc_reset(); /* init fdc & clear track counters */ if (fdc.type == no_fdc) { /* default, means no FC-10 or 20 found */ fdc.type = fdc_probe(); } if (fdc.type != no_fdc) { if (fdc.type >= i82077) { if (fdc_fifo_enable() < 0) { TRACE(2, "couldn't enable fdc fifo !"); } else { TRACE(5, "fdc fifo enabled and locked"); } } } else { fdc_release_irq_and_dma(); result = -EIO; } } if (result >= 0) { if (fdc.dor2 == 0) { request_region(fdc.sra, 6, "fdc (ftape)"); request_region(fdc.sra + 7, 1, "fdc (ftape)"); } else { request_region(fdc.sra, 8, "fdc (ftape)"); } } TRACE_EXIT; return result;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -