📄 fd1772.c
字号:
STOP_TIMEOUT(); NeedSeek = 0; if (timer_pending(&fd_timer) && time_after(jiffies + 5, fd_timer.expires)) /* If the check for a disk change is done too early after this * last seek command, the WP bit still reads wrong :-(( */ mod_timer(&fd_timer, jiffies + 5); else { /* START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ }; del_timer(&motor_off_timer); START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); save_flags(flags); cli(); /* stdma_release(); - not sure if I should do something DAG */ fdc_busy = 0; wake_up(&fdc_wait); restore_flags(flags); DPRINT(("finish_fdc() finished\n"));}/* Prevent "aliased" accesses. */static int fd_ref[4];static int fd_device[4];/* * Current device number. Taken either from the block header or from the * format request descriptor. */#define CURRENT_DEVICE (CURRENT->rq_dev)/* Current error count. */#define CURRENT_ERRORS (CURRENT->errors)/* dummy for blk.h */static void floppy_off(unsigned int nr){}/* On the old arcs write protect depends on the particular model of machine. On the A310, R140, and A440 there is a disc changed detect, however on the A4x0/1 range there is not. There is nothing to tell you which machine your on. At the moment I'm just marking changed always. I've left the Atari's 'change on write protect change' code in this part (but nothing sets it). RiscOS apparently checks the disc serial number etc. to detect changes - but if it sees a disc change line go high (?) it flips to using it. Well maybe I'll add that in the future (!?)*/static int check_floppy_change(dev_t dev){ unsigned int drive = (dev & 0x03); if (MAJOR(dev) != MAJOR_NR) { printk("floppy_changed: not a floppy\n"); return 0; } if (test_bit(drive, &fake_change)) { /* simulated change (e.g. after formatting) */ return 1; } if (test_bit(drive, &changed_floppies)) { /* surely changed (the WP signal changed at least once) */ return 1; } if (unit[drive].wpstat) { /* WP is on -> could be changed: to be sure, buffers should be * invalidated... */ return 1; } return 1; /* DAG - was 0 */}static int floppy_revalidate(dev_t dev){ int drive = dev & 3; if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change) || unit[drive].disktype == 0) {#ifdef TRACKBUFFER BufferDrive = -1;#endif clear_bit(drive, &fake_change); clear_bit(drive, &changed_floppies); unit[drive].disktype = 0; } return 0;}static __inline__ void copy_buffer(void *from, void *to){ ulong *p1 = (ulong *) from, *p2 = (ulong *) to; int cnt; for (cnt = 512 / 4; cnt; cnt--) *p2++ = *p1++;}/* This sets up the global variables describing the current request. */static void setup_req_params(int drive){ int block = ReqBlock + ReqCnt; ReqTrack = block / unit[drive].disktype->spt; ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1; ReqSide = ReqTrack & 1; ReqTrack >>= 1; ReqData = ReqBuffer + 512 * ReqCnt;#ifdef TRACKBUFFER read_track = (ReqCmd == READ && CURRENT_ERRORS == 0);#endif DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide, ReqTrack, ReqSector, (unsigned long) ReqData));}static void redo_fd_request(void){ int device, drive, type; struct archy_floppy_struct *floppy; DPRINT(("redo_fd_request: CURRENT=%08lx CURRENT->rq_dev=%04x CURRENT->sector=%ld\n", (unsigned long) CURRENT, CURRENT ? CURRENT->rq_dev : 0, !QUEUE_EMPTY ? CURRENT->sector : 0)); if (!QUEUE_EMPTY && CURRENT->rq_status == RQ_INACTIVE) goto the_end;repeat: if (QUEUE_EMPTY) goto the_end; if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) panic(DEVICE_NAME ": request list destroyed"); if (CURRENT->bh) { if (!buffer_locked(CURRENT->bh)) panic(DEVICE_NAME ": block not locked"); } device = MINOR(CURRENT_DEVICE); drive = device & 3; type = device >> 2; floppy = &unit[drive]; if (!floppy->connected) { /* drive not connected */ printk("Unknown Device: fd%d\n", drive); end_request(0); goto repeat; } if (type == 0) { if (!floppy->disktype) { Probing = 1; floppy->disktype = disk_type + NUM_DISK_TYPES - 1; floppy_sizes[drive] = floppy->disktype->blocks >> 1; floppy->autoprobe = 1; } } else { /* user supplied disk type */ --type; if (type >= NUM_DISK_TYPES) { printk("fd%d: invalid disk format", drive); end_request(0); goto repeat; } floppy->disktype = &disk_type[type]; floppy_sizes[drive] = disk_type[type].blocks >> 1; floppy->autoprobe = 0; } if (CURRENT->sector + 1 > floppy->disktype->blocks) { end_request(0); goto repeat; } /* stop deselect timer */ del_timer(&motor_off_timer); ReqCnt = 0; ReqCmd = CURRENT->cmd; ReqBlock = CURRENT->sector; ReqBuffer = CURRENT->buffer; setup_req_params(drive); do_fd_action(drive); return;the_end: finish_fdc();}static void fd1772_checkint(void){ extern int fdc1772_bytestogo; /*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/ if (fdc1772_fdc_int_done) floppy_irqconsequencehandler(); if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0); if (fdc_busy) { queue_task(&fd1772_tq,&tq_immediate); mark_bh(IMMEDIATE_BH); }}void do_fd_request(request_queue_t* q){ unsigned long flags; DPRINT(("do_fd_request for pid %d\n", current->pid)); if (fdc_busy) return; save_flags(flags); cli(); while (fdc_busy) sleep_on(&fdc_wait); fdc_busy = 1; ENABLE_IRQ(); restore_flags(flags); fdc1772_fdc_int_done = 0; redo_fd_request(); queue_task(&fd1772_tq,&tq_immediate); mark_bh(IMMEDIATE_BH);}static int invalidate_drive(int rdev){ /* invalidate the buffer track to force a reread */#ifdef TRACKBUFFER BufferDrive = -1;#endif set_bit(rdev & 3, &fake_change); check_disk_change(rdev); return 0;}static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long param){ int drive, device; device = inode->i_rdev; drive = MINOR(device); switch (cmd) { case FDFMTBEG: return 0; /* case FDC1772LRPRM: ??? DAG what does this do?? unit[drive].disktype = NULL; floppy_sizes[drive] = MAX_DISK_SIZE; return invalidate_drive (device); */ case FDFMTEND: case FDFLUSH: return invalidate_drive(drive); } if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (drive < 0 || drive > 3) return -EINVAL; switch (cmd) { default: return -EINVAL; } return 0;}/* Initialize the 'unit' variable for drive 'drive' */static void fd_probe(int drive){ unit[drive].connected = 0; unit[drive].disktype = NULL; if (!fd_test_drive_present(drive)) return; unit[drive].connected = 1; unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */ unit[drive].steprate = FDC1772STEP_6; MotorOn = 1; /* from probe restore operation! */}/* This function tests the physical presence of a floppy drive (not * whether a disk is inserted). This is done by issuing a restore * command, waiting max. 2 seconds (that should be enough to move the * head across the whole disk) and looking at the state of the "TR00" * signal. This should now be raised if there is a drive connected * (and there is no hardware failure :-) Otherwise, the drive is * declared absent. */static int fd_test_drive_present(int drive){ unsigned long timeout; unsigned char status; int ok; printk("fd_test_drive_present %d\n", drive); if (drive > 1) return (0); return (1); /* Simple hack for the moment - the autodetect doesn't seem to work on arc */ fd_select_drive(drive); /* disable interrupt temporarily */ DISABLE_IRQ(); FDC1772_WRITE(FDC1772REG_TRACK, 0x00); /* was ff00 why? */ FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6); /*printk("fd_test_drive_present: Going into timeout loop\n"); */ for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) { /* What does this piece of atariism do? - query for an interrupt? */ /* if (!(mfp.par_dt_reg & 0x20)) break; */ /* Well this is my nearest guess - quit when we get an FDC interrupt */ if (ioc_readb(IOC_FIQSTAT) & 2) break; } /*printk("fd_test_drive_present: Coming out of timeout loop\n"); */ status = FDC1772_READ(FDC1772REG_STATUS); ok = (status & FDC1772STAT_TR00) != 0; /*printk("fd_test_drive_present: ok=%d\n",ok); */ /* force interrupt to abort restore operation (FDC1772 would try * about 50 seconds!) */ FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); udelay(500); status = FDC1772_READ(FDC1772REG_STATUS); udelay(20); /*printk("fd_test_drive_present: just before OK code %d\n",ok); */ if (ok) { /* dummy seek command to make WP bit accessible */ FDC1772_WRITE(FDC1772REG_DATA, 0); FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); printk("fd_test_drive_present: just before wait for int\n"); /* DAG: Guess means wait for interrupt */ while (!(ioc_readb(IOC_FIQSTAT) & 2)); printk("fd_test_drive_present: just after wait for int\n"); status = FDC1772_READ(FDC1772REG_STATUS); } printk("fd_test_drive_present: just before ENABLE_IRQ\n"); ENABLE_IRQ(); printk("fd_test_drive_present: about to return\n"); return (ok);}/* Look how many and which kind of drives are connected. If there are * floppies, additionally start the disk-change and motor-off timers. */static void config_types(void){ int drive, cnt = 0; printk("Probing floppy drive(s):\n"); for (drive = 0; drive < FD_MAX_UNITS; drive++) { fd_probe(drive); if (unit[drive].connected) { printk("fd%d\n", drive); ++cnt; } } if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) { /* If FDC1772 is still busy from probing, give it another FORCI * command to abort the operation. If this isn't done, the FDC1772 * will interrupt later and its IRQ line stays low, because * the status register isn't read. And this will block any * interrupts on this IRQ line :-( */ FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); udelay(500); FDC1772_READ(FDC1772REG_STATUS); udelay(20); } if (cnt > 0) { START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY); if (cnt == 1) fd_select_drive(0); /*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */ }}/* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */static int floppy_open(struct inode *inode, struct file *filp){ int drive; int old_dev; if (!filp) { DPRINT(("Weird, open called with filp=0\n")); return -EIO; } drive = MINOR(inode->i_rdev) & 3; if ((MINOR(inode->i_rdev) >> 2) > NUM_DISK_TYPES) return -ENXIO; old_dev = fd_device[drive]; if (fd_ref[drive]) if (old_dev != inode->i_rdev) return -EBUSY; if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL)) return -EBUSY; if (filp->f_flags & O_EXCL) fd_ref[drive] = -1; else fd_ref[drive]++; fd_device[drive] = inode->i_rdev; if (old_dev && old_dev != inode->i_rdev) invalidate_buffers(old_dev); if (filp->f_flags & O_NDELAY) return 0; if (filp->f_mode & 3) { check_disk_change(inode->i_rdev); if (filp->f_mode & 2) { if (unit[drive].wpstat) { floppy_release(inode, filp); return -EROFS; } } } return 0;}static int floppy_release(struct inode *inode, struct file *filp){ int drive = MINOR(inode->i_rdev) & 3; if (fd_ref[drive] < 0) fd_ref[drive] = 0; else if (!fd_ref[drive]--) { printk("floppy_release with fd_ref == 0"); fd_ref[drive] = 0; } return 0;}static struct block_device_operations floppy_fops ={ open: floppy_open, release: floppy_release, ioctl: fd_ioctl, check_media_change: check_floppy_change, revalidate: floppy_revalidate,};int fd1772_init(void){ int i; if (!machine_is_archimedes()) return 0; if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) { printk("Unable to get major %d for floppy\n", MAJOR_NR); return 1; } if (request_dma(FLOPPY_DMA, "fd1772")) { printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA); return 1; }; if (request_dma(FIQ_FD1772, "fd1772 end")) { printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772); free_dma(FLOPPY_DMA); return 1; }; enable_dma(FIQ_FD1772); /* This inserts a call to our command end routine */ /* initialize variables */ SelectedDrive = -1;#ifdef TRACKBUFFER BufferDrive = BufferSide = BufferTrack = -1; /* Atari uses 512 - I want to eventually cope with 1K sectors */ DMABuffer = (char *)kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL); TrackBuffer = DMABuffer + 512;#else /* Allocate memory for the DMAbuffer - on the Atari this takes it out of some special memory... */ DMABuffer = (char *) kmalloc(2048); /* Copes with pretty large sectors */#endif for (i = 0; i < FD_MAX_UNITS; i++) { unit[i].track = -1; } for (i = 0; i < 256; i++) if ((i >> 2) > 0 && (i >> 2) <= NUM_DISK_TYPES) floppy_sizes[i] = disk_type[(i >> 2) - 1].blocks >> 1; else floppy_sizes[i] = MAX_DISK_SIZE; blk_size[MAJOR_NR] = floppy_sizes; blksize_size[MAJOR_NR] = floppy_blocksizes; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); config_types(); return 0;}void floppy_eject(void){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -