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

📄 fd1772.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	cli();	oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));	restore_flags(flags);	/* restore track register to saved value */	FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);	udelay(25);	SelectedDrive = drive;}/* Deselect both drives. */static void fd_deselect(void){	unsigned long flags;	DPRINT(("fd_deselect\n"));	save_flags(flags);	cli();	oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);	restore_flags(flags);	SelectedDrive = -1;}/* This timer function deselects the drives when the FDC1772 switched the * motor off. The deselection cannot happen earlier because the FDC1772 * counts the index signals, which arrive only if one drive is selected. */static void fd_motor_off_timer(unsigned long dummy){	unsigned long flags;	unsigned char status;	int delay;	del_timer(&motor_off_timer);	if (SelectedDrive < 0)		/* no drive selected, needn't deselect anyone */		return;	save_flags(flags);	cli();	if (fdc_busy)		/* was stdma_islocked */		goto retry;	status = FDC1772_READ(FDC1772REG_STATUS);	if (!(status & 0x80)) {		/* motor already turned off by FDC1772 -> deselect drives */     /* In actual fact its this deselection which turns the motor off on the        Arc, since the motor control is actually on Latch A */		DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));		fd_deselect();		MotorOn = 0;		restore_flags(flags);		return;	}	/* not yet off, try again */      retry:	restore_flags(flags);	/* Test again later; if tested too often, it seems there is no disk	 * in the drive and the FDC1772 will leave the motor on forever (or,	 * at least until a disk is inserted). So we'll test only twice	 * per second from then on...	 */	delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?	    (++MotorOffTrys, HZ / 20) : HZ / 2;	START_MOTOR_OFF_TIMER(delay);}/* This function is repeatedly called to detect disk changes (as good * as possible) and keep track of the current state of the write protection. */static void check_change(void){	static int drive = 0;	unsigned long flags;	int stat;	if (fdc_busy)		return;		/* Don't start poking about if the fdc is busy */	return;			/* lets just forget it for the mo DAG */	if (++drive > 1 || !unit[drive].connected)		drive = 0;	save_flags(flags);	cli();	if (!stdma_islocked()) {		stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);		/* The idea here is that if the write protect line has changed then		the disc must have changed */		if (stat != unit[drive].wpstat) {			DPRINT(("wpstat[%d] = %d\n", drive, stat));			unit[drive].wpstat = stat;			set_bit(drive, &changed_floppies);		}	}	restore_flags(flags);	START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);}/* Handling of the Head Settling Flag: This flag should be set after each * seek operation, because we dont't use seeks with verify. */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 (!CURRENT)		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 TRACKBUFFER  repeat:  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);  cliIF();	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 {#ifdef TRACKBUFFER    if (read_track)      paddr = (unsigned long)PhysTrackBuffer;    else      paddr =(unsigned long)PhysDMABuffer;#else    paddr = (unsigned long)PhysDMABuffer;#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);	cliIF();	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 */

⌨️ 快捷键说明

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