📄 floppy.c
字号:
/*===========================================================================* * f_expire_tmrs * *===========================================================================*/PRIVATE void f_expire_tmrs(struct driver *dp, message *m_ptr){/* A synchronous alarm message was received. Check if there are any expired * timers. Possibly reschedule the next alarm. */ clock_t now; /* current time */ timer_t *tp; int s; /* Get the current time to compare the timers against. */ if ((s=getuptime(&now)) != OK) panic("FLOPPY","Couldn't get uptime from clock.", s); /* Scan the timers queue for expired timers. Dispatch the watchdog function * for each expired timers. FLOPPY watchdog functions are f_tmr_timeout() * and stop_motor(). Possibly a new alarm call must be scheduled. */ tmrs_exptimers(&f_timers, now, NULL); if (f_timers == NULL) { f_next_timeout = TMR_NEVER; } else { /* set new sync alarm */ f_next_timeout = f_timers->tmr_exp_time; if ((s=sys_setalarm(f_next_timeout, 1)) != OK) panic("FLOPPY","Couldn't set synchronous alarm.", s); }}/*===========================================================================* * f_set_timer * *===========================================================================*/PRIVATE void f_set_timer(tp, delta, watchdog)timer_t *tp; /* timer to be set */clock_t delta; /* in how many ticks */tmr_func_t watchdog; /* watchdog function to be called */{ clock_t now; /* current time */ int s; /* Get the current time. */ if ((s=getuptime(&now)) != OK) panic("FLOPPY","Couldn't get uptime from clock.", s); /* Add the timer to the local timer queue. */ tmrs_settimer(&f_timers, tp, now + delta, watchdog, NULL); /* Possibly reschedule an alarm call. This happens when the front of the * timers queue was reinserted at another position, i.e., when a timer was * reset, or when a new timer was added in front. */ if (f_timers->tmr_exp_time != f_next_timeout) { f_next_timeout = f_timers->tmr_exp_time; if ((s=sys_setalarm(f_next_timeout, 1)) != OK) panic("FLOPPY","Couldn't set synchronous alarm.", s); }}/*===========================================================================* * f_prepare * *===========================================================================*/PRIVATE struct device *f_prepare(device)int device;{/* Prepare for I/O on a device. */ f_device = device; f_drive = device & ~(DEV_TYPE_BITS | FORMAT_DEV_BIT); if (f_drive < 0 || f_drive >= NR_DRIVES) return(NIL_DEV); f_fp = &floppy[f_drive]; f_dv = &f_fp->fl_geom; if (f_fp->fl_density < NT) { f_dp = &fdensity[f_fp->fl_density]; f_sectors = f_dp->secpt; f_fp->fl_geom.dv_size = mul64u((long) (NR_HEADS * f_sectors * f_dp->cyls), SECTOR_SIZE); } /* A partition? */ if ((device &= DEV_TYPE_BITS) >= MINOR_fd0p0) f_dv = &f_fp->fl_part[(device - MINOR_fd0p0) >> DEV_TYPE_SHIFT]; return f_dv;}/*===========================================================================* * f_name * *===========================================================================*/PRIVATE char *f_name(){/* Return a name for the current device. */ static char name[] = "fd0"; name[2] = '0' + f_drive; return name;}/*===========================================================================* * f_cleanup * *===========================================================================*/PRIVATE void f_cleanup(){ /* Start a timer to turn the motor off in a few seconds. */ tmr_arg(&f_fp->fl_tmr_stop)->ta_int = f_drive; f_set_timer(&f_fp->fl_tmr_stop, MOTOR_OFF, stop_motor); /* Exiting the floppy driver, so forget where we are. */ f_fp->fl_sector = NO_SECTOR;}/*===========================================================================* * f_transfer * *===========================================================================*/PRIVATE int f_transfer(proc_nr, opcode, position, iov, nr_req)int proc_nr; /* process doing the request */int opcode; /* DEV_GATHER or DEV_SCATTER */off_t position; /* offset on device to read or write */iovec_t *iov; /* pointer to read or write request vector */unsigned nr_req; /* length of request vector */{ struct floppy *fp = f_fp; iovec_t *iop, *iov_end = iov + nr_req; int s, r, errors; unsigned block; /* Seen any 32M floppies lately? */ unsigned nbytes, count, chunk, sector; unsigned long dv_size = cv64ul(f_dv->dv_size); vir_bytes user_addr; vir_bytes uaddrs[MAX_SECTORS], *up; u8_t cmd[3]; /* Check disk address. */ if ((position & SECTOR_MASK) != 0) return(EINVAL); errors = 0; while (nr_req > 0) { /* How many bytes to transfer? */ nbytes = 0; for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size; /* Which block on disk and how close to EOF? */ if (position >= dv_size) return(OK); /* At EOF */ if (position + nbytes > dv_size) nbytes = dv_size - position; block = div64u(add64ul(f_dv->dv_base, position), SECTOR_SIZE); if ((nbytes & SECTOR_MASK) != 0) return(EINVAL); /* Using a formatting device? */ if (f_device & FORMAT_DEV_BIT) { if (opcode != DEV_SCATTER) return(EIO); if (iov->iov_size < SECTOR_SIZE + sizeof(fmt_param)) return(EINVAL); if ((s=sys_datacopy(proc_nr, iov->iov_addr + SECTOR_SIZE, SELF, (vir_bytes) &fmt_param, (phys_bytes) sizeof(fmt_param))) != OK) panic("FLOPPY", "Sys_vircopy failed", s); /* Check that the number of sectors in the data is reasonable, * to avoid division by 0. Leave checking of other data to * the FDC. */ if (fmt_param.sectors_per_cylinder == 0) return(EIO); /* Only the first sector of the parameters now needed. */ iov->iov_size = nbytes = SECTOR_SIZE; } /* Only try one sector if there were errors. */ if (errors > 0) nbytes = SECTOR_SIZE; /* Compute cylinder and head of the track to access. */ fp->fl_cylinder = block / (NR_HEADS * f_sectors); fp->fl_hardcyl = fp->fl_cylinder * f_dp->steps; fp->fl_head = (block % (NR_HEADS * f_sectors)) / f_sectors; /* For each sector on this track compute the user address it is to * go or to come from. */ for (up = uaddrs; up < uaddrs + MAX_SECTORS; up++) *up = 0; count = 0; iop = iov; sector = block % f_sectors; for (;;) { user_addr = iop->iov_addr; chunk = iop->iov_size; if ((chunk & SECTOR_MASK) != 0) return(EINVAL); while (chunk > 0) { uaddrs[sector++] = user_addr; chunk -= SECTOR_SIZE; user_addr += SECTOR_SIZE; count += SECTOR_SIZE; if (sector == f_sectors || count == nbytes) goto track_set_up; } iop++; } track_set_up: /* First check to see if a reset is needed. */ if (need_reset) f_reset(); /* See if motor is running; if not, turn it on and wait. */ start_motor(); /* Set the stepping rate and data rate */ if (f_dp != prev_dp) { cmd[0] = FDC_SPECIFY; cmd[1] = f_dp->spec1; cmd[2] = SPEC2; (void) fdc_command(cmd, 3); if ((s=sys_outb(FDC_RATE, f_dp->rate)) != OK) panic("FLOPPY","Sys_outb failed", s); prev_dp = f_dp; } /* If we are going to a new cylinder, perform a seek. */ r = seek(); /* Avoid read_id() if we don't plan to read much. */ if (fp->fl_sector == NO_SECTOR && count < (6 * SECTOR_SIZE)) fp->fl_sector = 0; for (nbytes = 0; nbytes < count; nbytes += SECTOR_SIZE) { if (fp->fl_sector == NO_SECTOR) { /* Find out what the current sector is. This often * fails right after a seek, so try it twice. */ if (r == OK && read_id() != OK) r = read_id(); } /* Look for the next job in uaddrs[] */ if (r == OK) { for (;;) { if (fp->fl_sector >= f_sectors) fp->fl_sector = 0; up = &uaddrs[fp->fl_sector]; if (*up != 0) break; fp->fl_sector++; } } if (r == OK && opcode == DEV_SCATTER) { /* Copy the user bytes to the DMA buffer. */ if ((s=sys_datacopy(proc_nr, *up, SELF, (vir_bytes) tmp_buf, (phys_bytes) SECTOR_SIZE)) != OK) panic("FLOPPY", "Sys_vircopy failed", s); } /* Set up the DMA chip and perform the transfer. */ if (r == OK) { if (dma_setup(opcode) != OK) { /* This can only fail for addresses above 16MB * that cannot be handled by the controller, * because it uses 24-bit addressing. */ return(EIO); } r = fdc_transfer(opcode); } if (r == OK && opcode == DEV_GATHER) { /* Copy the DMA buffer to user space. */ if ((s=sys_datacopy(SELF, (vir_bytes) tmp_buf, proc_nr, *up, (phys_bytes) SECTOR_SIZE)) != OK) panic("FLOPPY", "Sys_vircopy failed", s); } if (r != OK) { /* Don't retry if write protected or too many errors. */ if (err_no_retry(r) || ++errors == MAX_ERRORS) { return(EIO); } /* Recalibrate if halfway. */ if (errors == MAX_ERRORS / 2) fp->fl_calibration = UNCALIBRATED; nbytes = 0; break; /* retry */ } } /* Book the bytes successfully transferred. */ position += nbytes; for (;;) { if (nbytes < iov->iov_size) { /* Not done with this one yet. */ iov->iov_addr += nbytes; iov->iov_size -= nbytes; break; } nbytes -= iov->iov_size; iov->iov_addr += iov->iov_size; iov->iov_size = 0; if (nbytes == 0) { /* The rest is optional, so we return to give FS a * chance to think it over. */ return(OK); } iov++; nr_req--; } } return(OK);}/*===========================================================================* * dma_setup * *===========================================================================*/PRIVATE int dma_setup(opcode)int opcode; /* DEV_GATHER or DEV_SCATTER */{/* The IBM PC can perform DMA operations by using the DMA chip. To use it, * the DMA (Direct Memory Access) chip is loaded with the 20-bit memory address * to be read from or written to, the byte count minus 1, and a read or write
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -