📄 fd1772.c
字号:
/* Hmm - should do something DAG */ old_motoron = MotorOn; MotorOn = 1; NeedSeek = 1; /* wait for interrupt */#ifdef TRACKBUFFER if (read_track) { /* If reading a whole track, wait about one disk rotation and * then check if all sectors are read. The FDC will even * search for the first non-existant sector and need 1 sec to * recognise that it isn't present :-( */ del_timer( &readtrack_timer ); readtrack_timer.function = fd_readtrack_check; readtrack_timer.expires = jiffies + HZ/5 + (old_motoron ? 0 : HZ); /* 1 rot. + 5 rot.s if motor was off */ DPRINT(("Setting readtrack_timer to %d @ %d\n",readtrack_timer.expires,jiffies)); add_timer( &readtrack_timer ); MultReadInProgress = 1; }#endif /*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */ START_TIMEOUT(); /*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */}#ifdef TRACKBUFFERstatic void fd_readtrack_check( unsigned long dummy ){ unsigned long flags, addr; extern unsigned char *fdc1772_dataaddr; DPRINT(("fd_readtrack_check @ %d\n",jiffies)); save_flags(flags); cliIF(); del_timer( &readtrack_timer ); if (!MultReadInProgress) { /* This prevents a race condition that could arise if the * interrupt is triggered while the calling of this timer * callback function takes place. The IRQ function then has * already cleared 'MultReadInProgress' when control flow * gets here. */ restore_flags(flags); return; } /* get the current DMA address */ addr=fdc1772_dataaddr; /* DAG - ? */ DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%p\n",addr,PhysTrackBuffer)); if (addr >= (unsigned long)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) { /* already read enough data, force an FDC interrupt to stop * the read operation */ SET_IRQ_HANDLER( NULL ); restore_flags(flags); DPRINT(("fd_readtrack_check(): done\n")); FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI ); udelay(25); /* No error until now -- the FDC would have interrupted * otherwise! */ fd_rwsec_done( 0 ); } else { /* not yet finished, wait another tenth rotation */ restore_flags(flags); DPRINT(("fd_readtrack_check(): not yet finished\n")); readtrack_timer.expires = jiffies + HZ/5/10; add_timer( &readtrack_timer ); }}#endifstatic void fd_rwsec_done(int status){ unsigned int track; DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies));#ifdef TRACKBUFFER if (read_track && !MultReadInProgress) return; MultReadInProgress = 0; STOP_TIMEOUT(); if (read_track) del_timer( &readtrack_timer );#endif /* Correct the track if stretch != 0 */ if (unit[SelectedDrive].disktype->stretch) { track = FDC1772_READ(FDC1772REG_TRACK); FDC1772_WRITE(FDC1772REG_TRACK, track << unit[SelectedDrive].disktype->stretch); } if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) { printk("fd%d: is write protected\n", SelectedDrive); goto err_end; } if ((status & FDC1772STAT_RECNF)#ifdef TRACKBUFFER /* RECNF is no error after a multiple read when the FDC * searched for a non-existant sector! */ && !(read_track && FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)#endif ) { if (Probing) { if (unit[SelectedDrive].disktype > disk_type) { /* try another disk type */ unit[SelectedDrive].disktype--; floppy_sizes[SelectedDrive] = unit[SelectedDrive].disktype->blocks >> 1; } else Probing = 0; } else { /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ if (unit[SelectedDrive].autoprobe) { unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1; floppy_sizes[SelectedDrive] = unit[SelectedDrive].disktype->blocks >> 1; Probing = 1; } } if (Probing) { setup_req_params(SelectedDrive);#ifdef TRACKBUFFER BufferDrive = -1;#endif do_fd_action(SelectedDrive); return; } printk("fd%d: sector %d not found (side %d, track %d)\n", SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack); goto err_end; } if (status & FDC1772STAT_CRC) { printk("fd%d: CRC error (side %d, track %d, sector %d)\n", SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); goto err_end; } if (status & FDC1772STAT_LOST) { printk("fd%d: lost data (side %d, track %d, sector %d)\n", SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR)); goto err_end; } Probing = 0; if (ReqCmd == READ) {#ifdef TRACKBUFFER if (!read_track) { /*cache_clear (PhysDMABuffer, 512);*/ copy_buffer (DMABuffer, ReqData); } else { /*cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);*/ BufferDrive = SelectedDrive; BufferSide = ReqSide; BufferTrack = ReqTrack; copy_buffer (SECTOR_BUFFER (ReqSector), ReqData); }#else /*cache_clear( PhysDMABuffer, 512 ); */ copy_buffer(DMABuffer, ReqData);#endif } if (++ReqCnt < CURRENT->current_nr_sectors) { /* read next sector */ setup_req_params(SelectedDrive); do_fd_action(SelectedDrive); } else { /* all sectors finished */ CURRENT->nr_sectors -= CURRENT->current_nr_sectors; CURRENT->sector += CURRENT->current_nr_sectors; end_request(1); redo_fd_request(); } return; err_end:#ifdef TRACKBUFFER BufferDrive = -1;#endif fd_error();}static void fd_times_out(unsigned long dummy){ SET_IRQ_HANDLER(NULL); /* If the timeout occured while the readtrack_check timer was * active, we need to cancel it, else bad things will happen */ del_timer( &readtrack_timer ); FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI); udelay(25); printk("floppy timeout\n"); STOP_TIMEOUT(); /* hmm - should we do this ? */ fd_error();}/* The (noop) seek operation here is needed to make the WP bit in the * FDC1772 status register accessible for check_change. If the last disk * operation would have been a RDSEC, this bit would always read as 0 * no matter what :-( To save time, the seek goes to the track we're * already on. */static void finish_fdc(void){ /* DAG - just try without this dummy seek! */ finish_fdc_done(0); return; if (!NeedSeek) { finish_fdc_done(0); } else { DPRINT(("finish_fdc: dummy seek started\n")); FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track); SET_IRQ_HANDLER(finish_fdc_done); FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK); MotorOn = 1; START_TIMEOUT(); /* we must wait for the IRQ here, because the ST-DMA is * released immediatly afterwards and the interrupt may be * delivered to the wrong driver. */ }}static void finish_fdc_done(int dummy){ unsigned long flags; DPRINT(("finish_fdc_done entered\n")); STOP_TIMEOUT(); NeedSeek = 0; if ((timer_active & (1 << FLOPPY_TIMER)) && timer_table[FLOPPY_TIMER].expires < jiffies + 5) /* If the check for a disk change is done too early after this * last seek command, the WP bit still reads wrong :-(( */ timer_table[FLOPPY_TIMER].expires = 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 fd_ref[4] ={0, 0, 0, 0};static fd_device[4] ={0, 0, 0, 0};/* * 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, CURRENT ? CURRENT->sector : 0)); if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) goto the_end; repeat: if (!CURRENT) 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -