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

📄 ataflop.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
		return;	}	/* not yet off, try again */  retry:	/* Test again later; if tested too often, it seems there is no disk	 * in the drive and the FDC 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...	 */	mod_timer(&motor_off_timer,		  jiffies + (MotorOffTrys++ < FD_MOTOR_OFF_MAXTRY ? HZ/20 : HZ/2));}/* 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;	unsigned char old_porta;	int			  stat;	if (++drive > 1 || !UD.connected)		drive = 0;	save_flags(flags);	cli(); /* protect against various other ints mucking around with the PSG */	if (!stdma_islocked()) {		sound_ym.rd_data_reg_sel = 14;		old_porta = sound_ym.rd_data_reg_sel;		sound_ym.wd_data = (old_porta | DSKDRVNONE) &			               ~(drive == 0 ? DSKDRV0 : DSKDRV1);		stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT);		sound_ym.wd_data = old_porta;		if (stat != UD.wpstat) {			DPRINT(( "wpstat[%d] = %d\n", drive, stat ));			UD.wpstat = stat;			set_bit (drive, &changed_floppies);		}	}	restore_flags(flags);	start_check_change_timer();} /* Handling of the Head Settling Flag: This flag should be set after each * seek operation, because we don't use seeks with verify. */static __inline__ void set_head_settle_flag( void ){	HeadSettleFlag = FDCCMDADD_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_irq (int irq, void *dummy, struct pt_regs *fp){	unsigned char status;	void (*handler)( int );	handler = xchg(&FloppyIRQHandler, NULL);	if (handler) {		nop();		status = FDC_READ( FDCREG_STATUS );		DPRINT(("FDC irq, status = %02x handler = %08lx\n",status,(unsigned long)handler));		handler( status );	}	else {		DPRINT(("FDC irq, no handler\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 ){	if (IsFormatting) {		IsFormatting = 0;		FormatError = 1;		wake_up( &format_wait );		return;	}			if (QUEUE_EMPTY) return;	CURRENT->errors++;	if (CURRENT->errors >= MAX_ERRORS) {		printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );		end_request( 0 );	}	else if (CURRENT->errors == RECALIBRATE_ERRORS) {		printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );		if (SelectedDrive != -1)			SUD.track = -1;	}	redo_fd_request();}#define	SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)/* ---------- Formatting ---------- */#define FILL(n,val)		\    do {			\	memset( p, val, n );	\	p += n;			\    } while(0)static int do_format(kdev_t device, struct atari_format_descr *desc){	unsigned char	*p;	int sect, nsect;	unsigned long	flags;	int type, drive = MINOR(device) & 3;	DPRINT(("do_format( dr=%d tr=%d he=%d offs=%d )\n",		drive, desc->track, desc->head, desc->sect_offset ));	save_flags(flags);	cli();	while( fdc_busy ) sleep_on( &fdc_wait );	fdc_busy = 1;	stdma_lock(floppy_irq, NULL);	atari_turnon_irq( IRQ_MFP_FDC ); /* should be already, just to be sure */	restore_flags(flags);	type = MINOR(device) >> 2;	if (type) {		if (--type >= NUM_DISK_MINORS ||		    minor2disktype[type].drive_types > DriveType) {			redo_fd_request();			return -EINVAL;		}		type = minor2disktype[type].index;		UDT = &disk_type[type];	}	if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) {		redo_fd_request();		return -EINVAL;	}	nsect = UDT->spt;	p = TrackBuffer;	/* The track buffer is used for the raw track data, so its	   contents become invalid! */	BufferDrive = -1;	/* stop deselect timer */	del_timer( &motor_off_timer );	FILL( 60 * (nsect / 9), 0x4e );	for( sect = 0; sect < nsect; ++sect ) {		FILL( 12, 0 );		FILL( 3, 0xf5 );		*p++ = 0xfe;		*p++ = desc->track;		*p++ = desc->head;		*p++ = (nsect + sect - desc->sect_offset) % nsect + 1;		*p++ = 2;		*p++ = 0xf7;		FILL( 22, 0x4e );		FILL( 12, 0 );		FILL( 3, 0xf5 );		*p++ = 0xfb;		FILL( 512, 0xe5 );		*p++ = 0xf7;		FILL( 40, 0x4e );	}	FILL( TrackBuffer+BUFFER_SIZE-p, 0x4e );	IsFormatting = 1;	FormatError = 0;	ReqTrack = desc->track;	ReqSide  = desc->head;	do_fd_action( drive );	sleep_on( &format_wait );	redo_fd_request();	return( FormatError ? -EIO : 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\n"));		if (UseTrackbuffer && !IsFormatting) {	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) );		}	    }	}	if (SelectedDrive != drive)		fd_select_drive( drive );    	if (UD.track == -1)		fd_calibrate();	else if (UD.track != ReqTrack << UDT->stretch)		fd_seek();	else if (IsFormatting)		fd_writetrack();	else		fd_rwsec();}/* Seek to track 0 if the current track is unknown */static void fd_calibrate( void ){	if (SUD.track >= 0) {		fd_calibrate_done( 0 );		return;	}	if (ATARIHW_PRESENT(FDCSPEED))		dma_wd.fdc_speed = 0; 	/* always seek with 8 Mhz */;	DPRINT(("fd_calibrate\n"));	SET_IRQ_HANDLER( fd_calibrate_done );	/* we can't verify, since the speed may be incorrect */	FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | SUD.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 (ATARIHW_PRESENT(FDCSPEED))		dma_wd.fdc_speed = SUDT->fdc_speed;	if (status & FDCSTAT_RECNF) {		printk(KERN_ERR "fd%d: restore failed\n", SelectedDrive );		fd_error();	}	else {		SUD.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 ){	if (SUD.track == ReqTrack << SUDT->stretch) {		fd_seek_done( 0 );		return;	}	if (ATARIHW_PRESENT(FDCSPEED)) {		dma_wd.fdc_speed = 0;	/* always seek witch 8 Mhz */		MFPDELAY();	}	DPRINT(("fd_seek() to track %d\n",ReqTrack));	FDC_WRITE( FDCREG_DATA, ReqTrack << SUDT->stretch);	udelay(25);	SET_IRQ_HANDLER( fd_seek_done );	FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK | SUD.steprate );	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 (ATARIHW_PRESENT(FDCSPEED))		dma_wd.fdc_speed = SUDT->fdc_speed;	if (status & FDCSTAT_RECNF) {		printk(KERN_ERR "fd%d: seek error (to track %d)\n",				SelectedDrive, ReqTrack );		/* we don't know exactly which track we are on now! */		SUD.track = -1;		fd_error();	}	else {		SUD.track = ReqTrack << SUDT->stretch;		NeedSeek = 0;		if (IsFormatting)			fd_writetrack();		else			fd_rwsec();	}}/* This does the actual reading/writing after positioning the head * over the correct track. */static int MultReadInProgress = 0;static 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) {		if (ATARIHW_PRESENT(EXTD_DMA)) {			paddr = virt_to_phys(ReqData);		}		else {			copy_buffer( ReqData, DMABuffer );			paddr = PhysDMABuffer;		}		dma_cache_maintenance( paddr, 512, 1 );		rwflag = 0x100;	}	else {		if (read_track)			paddr = PhysTrackBuffer;		else			paddr = ATARIHW_PRESENT(EXTD_DMA) ? 				virt_to_phys(ReqData) : PhysDMABuffer;		rwflag = 0;	}	fd_select_side( ReqSide );  	/* Start sector of this operation */	FDC_WRITE( FDCREG_SECTOR, read_track ? 1 : ReqSector );	MFPDELAY();	/* Cheat for track if stretch != 0 */	if (SUDT->stretch) {		track = FDC_READ( FDCREG_TRACK);		MFPDELAY();		FDC_WRITE( FDCREG_TRACK, track >> SUDT->stretch);	}	udelay(25);  	/* Setup DMA */	save_flags(flags);  	cli();	dma_wd.dma_lo = (unsigned char)paddr;	MFPDELAY();	paddr >>= 8;	dma_wd.dma_md = (unsigned char)paddr;	MFPDELAY();	paddr >>= 8;	if (ATARIHW_PRESENT(EXTD_DMA))		st_dma_ext_dmahi = (unsigned short)paddr;	else		dma_wd.dma_hi = (unsigned char)paddr;	MFPDELAY();	restore_flags(flags);  	/* Clear FIFO and switch DMA to correct mode */  	dma_wd.dma_mode_status = 0x90 | rwflag;  	MFPDELAY();	dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100);  	MFPDELAY();	dma_wd.dma_mode_status = 0x90 | rwflag;	MFPDELAY();  	/* How many sectors for DMA */	dma_wd.fdc_acces_seccount = read_track ? SUDT->spt : 1;  	udelay(25);    	/* Start operation */	dma_wd.dma_mode_status = FDCSELREG_STP | rwflag;	udelay(25);	SET_IRQ_HANDLER( fd_rwsec_done );	dma_wd.fdc_acces_seccount =	  (get_head_settle_flag() |	   (rwflag ? FDCCMD_WRSEC : (FDCCMD_RDSEC | (read_track ? FDCCMDADD_M : 0))));	old_motoron = MotorOn;	MotorOn = 1;	NeedSeek = 1;	/* wait for interrupt */	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-existent sector and need 1 sec to		 * recognise that it isn't present :-(		 */		MultReadInProgress = 1;		mod_timer(&readtrack_timer,			  /* 1 rot. + 5 rot.s if motor was off  */			  jiffies + HZ/5 + (old_motoron ? 0 : HZ));	}	start_timeout();}    static void fd_readtrack_check( unsigned long dummy ){	unsigned long flags, addr, addr2;	save_flags(flags);  	cli();	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 flow of control		 * gets here.		 */		restore_flags(flags);		return;	}	/* get the current DMA address */	/* ++ f.a. read twice to avoid being fooled by switcher */	addr = 0;	do {		addr2 = addr;		addr = dma_wd.dma_lo & 0xff;		MFPDELAY();		addr |= (dma_wd.dma_md & 0xff) << 8;		MFPDELAY();		if (ATARIHW_PRESENT( EXTD_DMA ))			addr |= (st_dma_ext_dmahi & 0xffff) << 16;		else			addr |= (dma_wd.dma_hi & 0xff) << 16;		MFPDELAY();	} while(addr != addr2);  	if (addr >= PhysTrackBuffer + SUDT->spt*512) {		/* already read enough data, force an FDC interrupt to stop		 * the read operation		 */		SET_IRQ_HANDLER( NULL );		MultReadInProgress = 0;		restore_flags(flags);		DPRINT(("fd_readtrack_check(): done\n"));		FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );		udelay(25);		/* No error until now -- the FDC would have interrupted		 * otherwise!		 */		fd_rwsec_done1(0);	}	else {		/* not yet finished, wait another tenth rotation */		restore_flags(flags);		DPRINT(("fd_readtrack_check(): not yet finished\n"));

⌨️ 快捷键说明

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