?? old-fdc.c
字號:
#if 0 { unsigned i; LOG_PRINTF(("Result bytes: ")); for (i = 0; i < fdd->fdc->result_size; i++) LOG_PRINTF(("%u(%02xh) ", fdd->fdc->result[i], fdd->fdc->result[i])); LOG_PRINTF(("\n")); } #endif return FDC_OK;}/* Returns nonzero if the motor of the specified drive is on */static inline int is_motor_on(Fdc *fdc, unsigned drive){ return fdc->dor & (1 << (drive + 4));}/* Turns the motor off after the spindown time */static void motor_off_cb(void *params){ Fdd *fdd = (Fdd *) params; if (is_motor_on(fdd->fdc, fdd->number)) { fdd->fdc->dor &= ~(1 << (fdd->number + 4)); fd32_outb(fdd->fdc->base_port + FDC_DOR, fdd->fdc->dor); fdd->flags &= ~(DF_SPINUP | DF_SPINDN); }}/* Signals that motor spinup time elapsed */static void motor_spin_cb(void *fdd){ ((Fdd *) fdd)->flags |= DF_SPINUP;}/* Turns the motor on and selects the drive */static void motor_on(Fdd *fdd){ if (fdd->flags & DF_SPINDN) fd32_event_delete(fdd->spin_down); fdd->flags &= ~DF_SPINDN; if (!is_motor_on(fdd->fdc, fdd->number)) { if (!(fdd->flags & DF_SPINUP)) /* TODO: Check for FD32_EVENT_NULL */ if (fd32_event_post(fdd->dp->spin_up, motor_spin_cb, fdd) < 0) LOG_PRINTF(("Motor on: Out of events!\n")); fdd->fdc->dor |= (1 << (fdd->number + 4)); /* Select drive */ fdd->fdc->dor = (fdd->fdc->dor & 0xFC) | fdd->number; fd32_outb(fdd->fdc->base_port + FDC_DOR, fdd->fdc->dor); }}/* Schedule motor off setting up the spindown timer */static void motor_down(Fdd *fdd){ if (is_motor_on(fdd->fdc, fdd->number)) { if (fdd->flags & DF_SPINDN) return; fdd->spin_down = fd32_event_post(fdd->dp->spin_down, motor_off_cb, fdd); if (fdd->spin_down == -1) LOG_PRINTF(("[FDC] motor_down: out of events!\n")); fdd->flags |= DF_SPINDN; }}/* This is the IRQ6 handler. irq_signaled is global! */static void irq6(int n){ irq_signaled = 1; /* Signal operation finished */ fd32_master_eoi(); /* Send EOI the PIC */}/* Returns nonzero if there was a disk change */int fdc_disk_changed(Fdd *fdd){ unsigned changeline; motor_on(fdd); changeline = fd32_inb(fdd->fdc->base_port + FDC_DIR) & 0x80; motor_down(fdd); return changeline || (fdd->flags & DF_CHANGED);}/* Recalibrates a drive (seek head to track 0). *//* Since the RECALIBRATE command sends up to 79 pulses to the head, *//* this function issues as many RECALIBRATE as needed. *//* The drive is supposed to be selected (motor on). */static void recalibrate(Fdd *fdd){ unsigned k; LOG_PRINTF(("Recalibrate\n")); for (k = 0; k < 13; k++) { sendbyte(fdd->fdc->base_port, CMD_RECAL); sendbyte(fdd->fdc->base_port, fdd->number); wait_fdc(fdd); /* Send a "sense interrupt status" command */ sendbyte(fdd->fdc->base_port, CMD_SENSEI); fdd->fdc->sr0 = getbyte(fdd->fdc->base_port); fdd->track = getbyte(fdd->fdc->base_port); if (!(fdd->fdc->sr0 & 0x10)) break; /* Exit if Unit Check is not set */ } LOG_PRINTF(("Calibration result on drive %u: SR0=%02xh, Track=%u\n", fdd->number, fdd->fdc->sr0, fdd->track));}/* Seeks a drive to the specified track. *//* The drive is supposed to be selected (motor on). */int fdc_seek(Fdd *fdd, unsigned track){ if (fdd->track == track) return FDC_OK; /* Already there */ if (track >= fdd->fmt->tracks) return FDC_ERROR; /* Invalid track */ sendbyte(fdd->fdc->base_port, CMD_SEEK); sendbyte(fdd->fdc->base_port, fdd->number); sendbyte(fdd->fdc->base_port, track); if (wait_fdc(fdd)) return FDC_TIMEOUT; /* Timeout */ /* Send a "sense interrupt status" command */ sendbyte(fdd->fdc->base_port, CMD_SENSEI); fdd->fdc->sr0 = getbyte(fdd->fdc->base_port); fdd->track = getbyte(fdd->fdc->base_port); /* Check that seek worked */ if ((fdd->fdc->sr0 != 0x20 + fdd->number) || (fdd->track != track)) { LOG_PRINTF(("Seek error on drive %u: SR0=%02xh, Track=%u Expected=%u\n", fdd->number, fdd->fdc->sr0, fdd->track, track)); return FDC_ERROR; } LOG_PRINTF(("Seek result on drive %u: SR0=%02xh, Track=%u\n", fdd->number, fdd->fdc->sr0, fdd->track)); return FDC_OK;}/* Gets the position of the heads by reading the next sector identifier. *//* Fills chs with the current head position. *//* The drive is supposed to be selected (motor on). */static int readid(Fdd *fdd, Chs *chs){ int res = 0; sendbyte(fdd->fdc->base_port, CMD_READID); sendbyte(fdd->fdc->base_port, fdd->number); if (wait_fdc(fdd)) res = FDC_TIMEOUT; if (res < 0) return res; if ((fdd->fdc->result[0] & 0xC0) != 0) return FDC_ERROR; chs->c = fdd->fdc->result[3]; chs->h = fdd->fdc->result[4]; chs->s = fdd->fdc->result[5]; return FDC_OK;}/* Program data rate and specify drive timings using the SPECIFY command */static void specify(const Fdd *fdd){ fd32_outb(fdd->fdc->base_port + FDC_CCR, fdd->fmt->rate); sendbyte(fdd->fdc->base_port, CMD_SPECIFY); sendbyte(fdd->fdc->base_port, fdd->fmt->sr_hut); sendbyte(fdd->fdc->base_port, fdd->dp->hlt << 1); /* Always DMA */}#endif/* Resets the FDC to a known state */static void reset_fdc(Fdc *fdc){ unsigned k; volatile int irq_timeout = 0; int irq_timeout_event; fd32_outb(fdc->base_port + FDC_DOR, 0); /* Stop the motor and disable IRQ/DMA */ /* TODO: Add a small delay (20 us) to make older controllers more happy */ //fd32_outb(fdc->base_port + FDC_DOR, 0x1C); /* Re-enable IRQ/DMA and release reset */ fd32_outb(fdc->base_port + FDC_MSR, 0x80); /* reset */ fd32_outb(fdc->base_port + FDC_DOR, 0x0C); /* Re-enable IRQ/DMA and release reset */ fdc->dor = 0x0C; /* Resetting triggered 4 interrupts - handle them */ //irq_timeout_event = fd32_event_post(default_drive_params[0].int_tmout, irq_timeout_cb, (void *) &irq_timeout); /* TODO: Check for FD32_EVENT_NULL */ //WFC(!irq_signaled && !irq_timeout); //fd32_event_delete(irq_timeout_event); irq_signaled=0; printk("now waiting for irq6\n"); k = inp(0x3f4); // read status of fdc printk("status of fdc: %x\n",k); while (!irq_signaled); printk("pased irq6\n"); //if (irq_timeout) // LOG_PRINTF(("Timed out while waiting for FDC after reset\n")); /* FDC specs say to sense interrupt status four times */ for (k = 0; k < 4; k++) { /* Send a "sense interrupt status" command */ sendbyte(fdc->base_port, CMD_SENSEI); fdc->sr0 = getbyte(fdc->base_port); printk("sr0:%x\n",fdc->sr0); fdc->drive[k].track = getbyte(fdc->base_port); } irq_signaled = 0;}#ifdef MYFDC /* Get a drive to a known state */static void reset_drive(Fdd *fdd){ if (fdd->dp->cmos_type == 0) return; if (fdd->flags & DF_SPINDN) fd32_event_delete(fdd->spin_down); fdd->flags = 0; fdd->track = 0; specify(fdd); motor_on(fdd); fdc_seek(fdd, SAFESEEK); recalibrate(fdd); motor_down(fdd); fdd->flags |= DF_CHANGED; /* So that fdc_log_disk can be issued */}/* Transfer sectors between the disk and the DMA buffer. *//* The drive is supposed to be selected (motor on). */static int fdc_xfer(Fdd *fdd, const Chs *chs, DWORD dma_addr, unsigned num_sectors, FdcTransfer op){ LOG_PRINTF(("[FDC] fdc_xfer: C=%u, H=%u, S=%u, n=%u, op=%u\n", chs->c, chs->h, chs->s, num_sectors, op)); /* Wait for motor spin quickly enough */ WFC(!(fdd->flags & DF_SPINUP)); /* Send read/write command */ if (op == FDC_READ) { dma_xfer(dma_addr, 512 * num_sectors, 0); /* Read */ sendbyte(fdd->fdc->base_port, CMD_READ); } else { dma_xfer(dma_addr, 512 * num_sectors, 1); /* Write */ sendbyte(fdd->fdc->base_port, CMD_WRITE); } sendbyte(fdd->fdc->base_port, (chs->h << 2) | fdd->number); sendbyte(fdd->fdc->base_port, chs->c); sendbyte(fdd->fdc->base_port, chs->h); sendbyte(fdd->fdc->base_port, chs->s); sendbyte(fdd->fdc->base_port, 2); /* 512 bytes per sector */ sendbyte(fdd->fdc->base_port, fdd->fmt->sec_per_trk); sendbyte(fdd->fdc->base_port, fdd->fmt->gap3); sendbyte(fdd->fdc->base_port, 0xFF); /* DTL (bytes to transfer) = unused */ /* Wait for completion and produce exit code */ if (wait_fdc(fdd)) { reset_fdc(fdd->fdc); reset_drive(fdd); return FDC_TIMEOUT; } if ((fdd->fdc->result[0] & 0xC0) == 0) return FDC_OK; return FDC_ERROR;}/* Reads sectors from the floppy, up to the end of the cylinder. *//* If buffer is NULL, the read data is discarded (may be used to probe). */int fdc_read(Fdd *fdd, const Chs *chs, BYTE *buffer, unsigned num_sectors){ unsigned tries; int res = FDC_ERROR; if (fdd->dp->cmos_type == 0) return FDC_ERROR; /* Drive not available */ /* TODO: Place a timeout for Busy check */ while (busy); /* Wait while the floppy driver is already busy: BUSY WAIT! */ busy = 1; motor_on(fdd); specify(fdd); for (tries = 0; tries < 3; tries++) { /* Move head to right track */ if (fdc_seek(fdd, chs->c) == FDC_OK) { /* If changeline is active, no disk is in drive */ if (fd32_inb(fdd->fdc->base_port + FDC_DIR) & 0x80) { LOG_PRINTF(("[FDC] fdc_read: no disk in drive\n")); res = FDC_NODISK; break; } res = fdc_xfer(fdd, chs, dma_addr, num_sectors, FDC_READ); if (res == FDC_OK) break;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -