📄 swim3.c
字号:
{ struct floppy_state *fs = (struct floppy_state *) data; volatile struct swim3 *sw = fs->swim3; fs->timeout_pending = 0; if (fs->state == settling) { printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n", sw->select, sw->control, sw->status, sw->intr, sw->intr_enable); } out_8(&sw->control_bic, DO_SEEK); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) { /* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */ fs->state = locating; act(fs); return; } printk(KERN_ERR "swim3: seek timeout\n"); end_request(0); fs->state = idle; start_request(fs);}static void xfer_timeout(unsigned long data){ struct floppy_state *fs = (struct floppy_state *) data; volatile struct swim3 *sw = fs->swim3; struct dbdma_regs *dr = fs->dma; struct dbdma_cmd *cp = fs->dma_cmd; unsigned long s; fs->timeout_pending = 0; st_le32(&dr->control, RUN << 16); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); if (CURRENT->cmd == WRITE) ++cp; if (ld_le16(&cp->xfer_status) != 0) s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9); else s = 0; CURRENT->sector += s; CURRENT->current_nr_sectors -= s; printk(KERN_ERR "swim3: timeout %sing sector %ld\n", (CURRENT->cmd==WRITE? "writ": "read"), CURRENT->sector); end_request(0); fs->state = idle; start_request(fs);}static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct floppy_state *fs = (struct floppy_state *) dev_id; volatile struct swim3 *sw = fs->swim3; int intr, err, n; int stat, resid; struct dbdma_regs *dr; struct dbdma_cmd *cp; err = in_8(&sw->error); intr = in_8(&sw->intr);#if 0 printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err);#endif if ((intr & ERROR_INTR) && fs->state != do_transfer) printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n", fs->state, CURRENT->cmd, intr, err); switch (fs->state) { case locating: if (intr & SEEN_SECTOR) { out_8(&sw->control_bic, DO_ACTION); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); del_timer(&fs->timeout); fs->timeout_pending = 0; if (sw->ctrack == 0xff) { printk(KERN_ERR "swim3: seen sector but cyl=ff?\n"); fs->cur_cyl = -1; if (fs->retries > 5) { end_request(0); fs->state = idle; start_request(fs); } else { fs->state = jogging; act(fs); } break; } fs->cur_cyl = sw->ctrack; fs->cur_sector = sw->csect; if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl) printk(KERN_ERR "swim3: expected cyl %d, got %d\n", fs->expect_cyl, fs->cur_cyl); fs->state = do_transfer; act(fs); } break; case seeking: case jogging: if (sw->nseek == 0) { out_8(&sw->control_bic, DO_SEEK); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); del_timer(&fs->timeout); fs->timeout_pending = 0; if (fs->state == seeking) ++fs->retries; fs->state = settling; act(fs); } break; case settling: out_8(&sw->intr_enable, 0); del_timer(&fs->timeout); fs->timeout_pending = 0; act(fs); break; case do_transfer: if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0) break; dr = fs->dma; cp = fs->dma_cmd; st_le32(&dr->control, RUN << 16); out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); del_timer(&fs->timeout); fs->timeout_pending = 0; if (CURRENT->cmd == WRITE) ++cp; stat = ld_le16(&cp->xfer_status); resid = ld_le16(&cp->res_count); if (intr & ERROR_INTR) { n = fs->scount - 1 - resid / 512; if (n > 0) { CURRENT->sector += n; CURRENT->current_nr_sectors -= n; CURRENT->buffer += n * 512; fs->req_sector += n; } if (fs->retries < 5) { ++fs->retries; act(fs); } else { printk("swim3: error %sing block %ld (err=%x)\n", CURRENT->cmd == WRITE? "writ": "read", CURRENT->sector, err); end_request(0); fs->state = idle; } } else { if ((stat & ACTIVE) == 0 || resid != 0) { /* musta been an error */ printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); printk(KERN_ERR " state=%d, cmd=%x, intr=%x, err=%x\n", fs->state, CURRENT->cmd, intr, err); end_request(0); fs->state = idle; start_request(fs); break; } CURRENT->sector += fs->scount; CURRENT->current_nr_sectors -= fs->scount; CURRENT->buffer += fs->scount * 512; if (CURRENT->current_nr_sectors <= 0) { end_request(1); fs->state = idle; } else { fs->req_sector += fs->scount; if (fs->req_sector > fs->secpertrack) { fs->req_sector -= fs->secpertrack; if (++fs->head > 1) { fs->head = 0; ++fs->req_cyl; } } act(fs); } } if (fs->state == idle) start_request(fs); break; default: printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state); }}/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs){}*/static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible){ unsigned long flags; save_flags(flags); cli(); if (fs->state != idle) { ++fs->wanted; while (fs->state != available) { if (interruptible && signal_pending(current)) { --fs->wanted; restore_flags(flags); return -EINTR; } interruptible_sleep_on(&fs->wait); } --fs->wanted; } fs->state = state; restore_flags(flags); return 0;}static void release_drive(struct floppy_state *fs){ unsigned long flags; save_flags(flags); cli(); fs->state = idle; start_request(fs); restore_flags(flags);}static int fd_eject(struct floppy_state *fs){ int err, n; err = grab_drive(fs, ejecting, 1); if (err) return err; swim3_action(fs, EJECT); for (n = 2*HZ; n > 0; --n) { if (swim3_readbit(fs, RELAX)) break; if (signal_pending(current)) { err = -EINTR; break; } current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } fs->ejected = 1; release_drive(fs); return err;}int swim3_fd_eject(int devnum){ if (devnum >= floppy_count) return -ENODEV; /* Do not check this - this function should ONLY be called early * in the boot process! */ /* if (floppy_states[devnum].ref_count != 1) return -EBUSY; */ return fd_eject(&floppy_states[devnum]);}static struct floppy_struct floppy_type = { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */static int floppy_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param){ struct floppy_state *fs; int err; int devnum = MINOR(inode->i_rdev); if (devnum >= floppy_count) return -ENODEV; if ((cmd & 0x80) && !suser()) return -EPERM; fs = &floppy_states[devnum]; if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; switch (cmd) { case FDEJECT: if (fs->ref_count != 1) return -EBUSY; err = fd_eject(fs); return err; case FDGETPRM: err = copy_to_user((void *) param, (void *) &floppy_type, sizeof(struct floppy_struct)); return err; } return -ENOIOCTLCMD;}static int floppy_open(struct inode *inode, struct file *filp){ struct floppy_state *fs; volatile struct swim3 *sw; int n, err; int devnum = MINOR(inode->i_rdev); if (devnum >= floppy_count) return -ENODEV; if (filp == 0) return -EIO; fs = &floppy_states[devnum]; sw = fs->swim3; err = 0; if (fs->ref_count == 0) { if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; out_8(&sw->mode, 0x95); out_8(&sw->control_bic, 0xff); out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2); udelay(10); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); swim3_action(fs, MOTOR_ON); fs->write_prot = -1; fs->cur_cyl = -1; for (n = HZ; n > 0; --n) { if (swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) { err = -EINTR; break; } current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0)) err = -ENXIO; swim3_action(fs, 9); } else if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY; if (err == 0 && (filp->f_flags & O_NDELAY) == 0 && (filp->f_mode & 3)) { check_disk_change(inode->i_rdev); if (fs->ejected) err = -ENXIO; } if (err == 0 && (filp->f_mode & 2)) { if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) err = -EROFS; } if (err) { if (fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE); } return err; } if (filp->f_flags & O_EXCL) fs->ref_count = -1; else ++fs->ref_count; return 0;}static int floppy_release(struct inode *inode, struct file *filp){ struct floppy_state *fs; volatile struct swim3 *sw; int devnum = MINOR(inode->i_rdev); if (devnum >= floppy_count) return -ENODEV; fs = &floppy_states[devnum]; sw = fs->swim3; if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); out_8(&sw->control_bic, 0xff); } return 0;}static int floppy_check_change(kdev_t dev){ struct floppy_state *fs; int devnum = MINOR(dev); if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) return 0; fs = &floppy_states[devnum]; return fs->ejected;}static int floppy_revalidate(kdev_t dev){ struct floppy_state *fs; volatile struct swim3 *sw; int ret, n; int devnum = MINOR(dev); if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count)) return 0; fs = &floppy_states[devnum]; if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD)) return -ENXIO; sw = fs->swim3; grab_drive(fs, revalidating, 0); out_8(&sw->intr_enable, 0); out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE); swim3_action(fs, MOTOR_ON); fs->write_prot = -1; fs->cur_cyl = -1; for (n = HZ; n > 0; --n) { if (swim3_readbit(fs, SEEK_COMPLETE)) break; if (signal_pending(current)) break; current->state = TASK_INTERRUPTIBLE; schedule_timeout(1); } ret = swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0; if (ret) swim3_action(fs, MOTOR_OFF); else { fs->ejected = 0; swim3_action(fs, 9); } release_drive(fs); return ret;}static void floppy_off(unsigned int nr){}static struct block_device_operations floppy_fops = { open: floppy_open, release: floppy_release, ioctl: floppy_ioctl, check_media_change: floppy_check_change, revalidate: floppy_revalidate,};int swim3_init(void){ struct device_node *swim; swim = find_devices("floppy"); while (swim && (floppy_count < MAX_FLOPPIES)) { swim3_add_device(swim); swim = swim->next; } swim = find_devices("swim3"); while (swim && (floppy_count < MAX_FLOPPIES)) { swim3_add_device(swim); swim = swim->next; } if (floppy_count > 0) { if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { printk(KERN_ERR "Unable to get major %d for floppy\n", MAJOR_NR); return -EBUSY; } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = floppy_blocksizes; blk_size[MAJOR_NR] = floppy_sizes; } return 0;}static int swim3_add_device(struct device_node *swim){ struct device_node *mediabay; struct floppy_state *fs = &floppy_states[floppy_count]; if (swim->n_addrs < 2) { printk(KERN_INFO "swim3: expecting 2 addrs (n_addrs:%d, n_intrs:%d)\n", swim->n_addrs, swim->n_intrs); return -EINVAL; } if (swim->n_intrs < 2) { printk(KERN_INFO "swim3: expecting 2 intrs (n_addrs:%d, n_intrs:%d)\n", swim->n_addrs, swim->n_intrs); return -EINVAL; } mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL; if (mediabay == NULL) feature_set(swim, FEATURE_SWIM3_enable); memset(fs, 0, sizeof(*fs)); fs->state = idle; fs->swim3 = (volatile struct swim3 *) ioremap(swim->addrs[0].address, 0x200); fs->dma = (struct dbdma_regs *) ioremap(swim->addrs[1].address, 0x200); fs->swim3_intr = swim->intrs[0].line; fs->dma_intr = swim->intrs[1].line; fs->cur_cyl = -1; fs->cur_sector = -1; fs->secpercyl = 36; fs->secpertrack = 18; fs->total_secs = 2880; fs->media_bay = mediabay; init_waitqueue_head(&fs->wait); fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space); memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd)); st_le16(&fs->dma_cmd[1].command, DBDMA_STOP); if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr); feature_clear(swim, FEATURE_SWIM3_enable); return -EBUSY; }/* if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", fs->dma_intr); feature_clear(swim, FEATURE_SWIM3_enable); return -EBUSY; }*/ init_timer(&fs->timeout); do_floppy = NULL; printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count, mediabay ? "in media bay" : ""); floppy_count++; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -