⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fd1772.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static __inline__ void set_head_settle_flag(void){	HeadSettleFlag = FDC1772CMDADD_E;}static __inline__ int get_head_settle_flag(void){	int tmp = HeadSettleFlag;	HeadSettleFlag = 0;	return (tmp);}/* General Interrupt Handling */static void (*FloppyIRQHandler) (int status) = NULL;static void floppy_irqconsequencehandler(void){	unsigned char status;	void (*handler) (int);	fdc1772_fdc_int_done = 0;	handler = FloppyIRQHandler;	FloppyIRQHandler = NULL;	if (handler) {		nop();		status = (unsigned char) fdc1772_comendstatus;		DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));		handler(status);	} else {		DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));	}	DPRINT(("FDC1772 irq: end of floppy_irq\n"));}/* Error handling: If some error happened, retry some times, then * recalibrate, then try again, and fail after MAX_ERRORS. */static void fd_error(void){	printk("FDC1772: fd_error\n");	/*panic("fd1772: fd_error"); *//* DAG tmp */	if (QUEUE_EMPTY)		return;	CURRENT->errors++;	if (CURRENT->errors >= MAX_ERRORS) {		printk("fd%d: too many errors.\n", SelectedDrive);		end_request(0);	} else if (CURRENT->errors == RECALIBRATE_ERRORS) {		printk("fd%d: recalibrating\n", SelectedDrive);		if (SelectedDrive != -1)			unit[SelectedDrive].track = -1;	}	redo_fd_request();}#define	SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)/* do_fd_action() is the general procedure for a fd request: All * required parameter settings (drive select, side select, track * position) are checked and set if needed. For each of these * parameters and the actual reading or writing exist two functions: * one that starts the setting (or skips it if possible) and one * callback for the "done" interrupt. Each done func calls the next * set function to propagate the request down to fd_rwsec_done(). */static void do_fd_action(int drive){	DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));#ifdef TRACKBUFFERrepeat:	if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {		if (ReqCmd == READ) {			copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );			if (++ReqCnt < CURRENT->current_nr_sectors) {				/* read next sector */				setup_req_params( drive );				goto repeat;			} else {				/* all sectors finished */				CURRENT->nr_sectors -= CURRENT->current_nr_sectors;				CURRENT->sector += CURRENT->current_nr_sectors;				end_request( 1 );				redo_fd_request();				return;			}		} else {			/* cmd == WRITE, pay attention to track buffer			 * consistency! */			copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );		}	}#endif	if (SelectedDrive != drive) {		/*unit[drive].track = -1; DAG */		fd_select_drive(drive);	};	if (unit[drive].track == -1)		fd_calibrate();	else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)		fd_seek();	else		fd_rwsec();}/* Seek to track 0 if the current track is unknown */static void fd_calibrate(void){	DPRINT(("fd_calibrate\n"));	if (unit[SelectedDrive].track >= 0) {		fd_calibrate_done(0);		return;	}	DPRINT(("fd_calibrate (after track compare)\n"));	SET_IRQ_HANDLER(fd_calibrate_done);	/* we can't verify, since the speed may be incorrect */	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);	NeedSeek = 1;	MotorOn = 1;	START_TIMEOUT();	/* wait for IRQ */}static void fd_calibrate_done(int status){	DPRINT(("fd_calibrate_done()\n"));	STOP_TIMEOUT();	/* set the correct speed now */	if (status & FDC1772STAT_RECNF) {		printk("fd%d: restore failed\n", SelectedDrive);		fd_error();	} else {		unit[SelectedDrive].track = 0;		fd_seek();	}}/* Seek the drive to the requested track. The drive must have been * calibrated at some point before this. */static void fd_seek(void){	unsigned long flags;	DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,		unit[SelectedDrive].track));	if (unit[SelectedDrive].track == ReqTrack <<	    unit[SelectedDrive].disktype->stretch) {		fd_seek_done(0);		return;	}	FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<		      unit[SelectedDrive].disktype->stretch);	udelay(25);	save_flags(flags);	clf();	SET_IRQ_HANDLER(fd_seek_done);	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |		/* DAG */		(MotorOn?FDC1772CMDADD_H:0));	restore_flags(flags);	MotorOn = 1;	set_head_settle_flag();	START_TIMEOUT();	/* wait for IRQ */}static void fd_seek_done(int status){	DPRINT(("fd_seek_done()\n"));	STOP_TIMEOUT();	/* set the correct speed */	if (status & FDC1772STAT_RECNF) {		printk("fd%d: seek error (to track %d)\n",		       SelectedDrive, ReqTrack);		/* we don't know exactly which track we are on now! */		unit[SelectedDrive].track = -1;		fd_error();	} else {		unit[SelectedDrive].track = ReqTrack <<		    unit[SelectedDrive].disktype->stretch;		NeedSeek = 0;		fd_rwsec();	}}/* This does the actual reading/writing after positioning the head * over the correct track. */#ifdef TRACKBUFFERstatic int MultReadInProgress = 0;#endifstatic void fd_rwsec(void){	unsigned long paddr, flags;	unsigned int rwflag, old_motoron;	unsigned int track;	DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));	if (ReqCmd == WRITE) {		/*cache_push( (unsigned long)ReqData, 512 ); */		paddr = (unsigned long) ReqData;		rwflag = 0x100;	} else {		paddr = (unsigned long) PhysDMABuffer;#ifdef TRACKBUFFER		if (read_track)			paddr = (unsigned long)PhysTrackBuffer;#endif		rwflag = 0;	}	DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,		ReqSector, FDC1772_READ(FDC1772REG_TRACK)));	fd_select_side(ReqSide);	/*DPRINT(("fd_rwsec() before start sector \n")); */	/* Start sector of this operation */#ifdef TRACKBUFFER	FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );#else	FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );#endif	/* Cheat for track if stretch != 0 */	if (unit[SelectedDrive].disktype->stretch) {		track = FDC1772_READ(FDC1772REG_TRACK);		FDC1772_WRITE(FDC1772REG_TRACK, track >>			      unit[SelectedDrive].disktype->stretch);	}	udelay(25);	DPRINT(("fd_rwsec() before setup DMA \n"));	/* Setup DMA - Heavily modified by DAG */	save_flags(flags);	clf();	disable_dma(FLOPPY_DMA);	set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);	set_dma_addr(FLOPPY_DMA, (long) paddr);		/* DAG - changed from Atari specific */#ifdef TRACKBUFFER	set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);#else	set_dma_count(FLOPPY_DMA, 512);		/* Block/sector size - going to have to change */#endif	SET_IRQ_HANDLER(fd_rwsec_done);	/* Turn on dma int */	enable_dma(FLOPPY_DMA);	/* Now give it something to do */	FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : #ifdef TRACKBUFFER	      (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) |	      /* Hmm - the idea here is to stop the FDC spinning the disc	      up when we know that we already still have it spinning */	      (MotorOn?FDC1772CMDADD_H:0))#else	      FDC1772CMD_RDSEC#endif		));	restore_flags(flags);	DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));	/*sti(); *//* DAG - Hmm */	/* 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 :-(		 */		/* 1 rot. + 5 rot.s if motor was off  */		mod_timer(&readtrack_timer, jiffies + HZ/5 + (old_motoron ? 0 : HZ));		DPRINT(("Setting readtrack_timer to %d @ %d\n",			readtrack_timer.expires,jiffies));		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);	clf();	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=(unsigned long)fdc1772_dataaddr; /* DAG - ? */	DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer));	if (addr >= (unsigned int)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, FD1772_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 occurred 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"));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -