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

📄 ataflop.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		local_irq_restore(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 */		local_irq_restore(flags);		DPRINT(("fd_readtrack_check(): not yet finished\n"));		mod_timer(&readtrack_timer, jiffies + HZ/5/10);	}}static void fd_rwsec_done( int status ){	DPRINT(("fd_rwsec_done()\n"));	if (read_track) {		del_timer(&readtrack_timer);		if (!MultReadInProgress)			return;		MultReadInProgress = 0;	}	fd_rwsec_done1(status);}static void fd_rwsec_done1(int status){	unsigned int track;	stop_timeout();		/* Correct the track if stretch != 0 */	if (SUDT->stretch) {		track = FDC_READ( FDCREG_TRACK);		MFPDELAY();		FDC_WRITE( FDCREG_TRACK, track << SUDT->stretch);	}	if (!UseTrackbuffer) {		dma_wd.dma_mode_status = 0x90;		MFPDELAY();		if (!(dma_wd.dma_mode_status & 0x01)) {			printk(KERN_ERR "fd%d: DMA error\n", SelectedDrive );			goto err_end;		}	}	MFPDELAY();	if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {		printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );		goto err_end;	}		if ((status & FDCSTAT_RECNF) &&	    /* RECNF is no error after a multiple read when the FDC	       searched for a non-existent sector! */	    !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) {		if (Probing) {			if (SUDT > disk_type) {			    if (SUDT[-1].blocks > ReqBlock) {				/* try another disk type */				SUDT--;				set_capacity(unit[SelectedDrive].disk,							SUDT->blocks);			    } else				Probing = 0;			}			else {				if (SUD.flags & FTD_MSG)					printk(KERN_INFO "fd%d: Auto-detected floppy type %s\n",					       SelectedDrive, SUDT->name );				Probing=0;			}		} else {	/* record not found, but not probing. Maybe stretch wrong ? Restart probing */			if (SUD.autoprobe) {				SUDT = disk_type + StartDiskType[DriveType];				set_capacity(unit[SelectedDrive].disk,							SUDT->blocks);				Probing = 1;			}		}		if (Probing) {			if (ATARIHW_PRESENT(FDCSPEED)) {				dma_wd.fdc_speed = SUDT->fdc_speed;				MFPDELAY();			}			setup_req_params( SelectedDrive );			BufferDrive = -1;			do_fd_action( SelectedDrive );			return;		}		printk(KERN_ERR "fd%d: sector %d not found (side %d, track %d)\n",		       SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack );		goto err_end;	}	if (status & FDCSTAT_CRC) {		printk(KERN_ERR "fd%d: CRC error (side %d, track %d, sector %d)\n",		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );		goto err_end;	}	if (status & FDCSTAT_LOST) {		printk(KERN_ERR "fd%d: lost data (side %d, track %d, sector %d)\n",		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );		goto err_end;	}	Probing = 0;		if (ReqCmd == READ) {		if (!read_track) {			void *addr;			addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer;			dma_cache_maintenance( virt_to_phys(addr), 512, 0 );			if (!ATARIHW_PRESENT( EXTD_DMA ))				copy_buffer (addr, ReqData);		} else {			dma_cache_maintenance( PhysTrackBuffer, MaxSectors[DriveType] * 512, 0 );			BufferDrive = SelectedDrive;			BufferSide  = ReqSide;			BufferTrack = ReqTrack;			copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);		}	}  	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(CURRENT, 1);		redo_fd_request();	}	return;    err_end:	BufferDrive = -1;	fd_error();}static void fd_writetrack( void ){	unsigned long paddr, flags;	unsigned int track;		DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide ));	paddr = PhysTrackBuffer;	dma_cache_maintenance( paddr, BUFFER_SIZE, 1 );	fd_select_side( ReqSide );  	/* Cheat for track if stretch != 0 */	if (SUDT->stretch) {		track = FDC_READ( FDCREG_TRACK);		MFPDELAY();		FDC_WRITE(FDCREG_TRACK,track >> SUDT->stretch);	}	udelay(40);  	/* Setup DMA */	local_irq_save(flags);	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();	local_irq_restore(flags);  	/* Clear FIFO and switch DMA to correct mode */  	dma_wd.dma_mode_status = 0x190;  	MFPDELAY();	dma_wd.dma_mode_status = 0x90;  	MFPDELAY();	dma_wd.dma_mode_status = 0x190;	MFPDELAY();  	/* How many sectors for DMA */	dma_wd.fdc_acces_seccount = BUFFER_SIZE/512;	udelay(40);    	/* Start operation */	dma_wd.dma_mode_status = FDCSELREG_STP | 0x100;	udelay(40);	SET_IRQ_HANDLER( fd_writetrack_done );	dma_wd.fdc_acces_seccount = FDCCMD_WRTRA | get_head_settle_flag(); 	MotorOn = 1;	start_timeout();	/* wait for interrupt */}static void fd_writetrack_done( int status ){	DPRINT(("fd_writetrack_done()\n"));	stop_timeout();	if (status & FDCSTAT_WPROT) {		printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );		goto err_end;	}		if (status & FDCSTAT_LOST) {		printk(KERN_ERR "fd%d: lost data (side %d, track %d)\n",				SelectedDrive, ReqSide, ReqTrack );		goto err_end;	}	wake_up( &format_wait );	return;  err_end:	fd_error();}static void fd_times_out( unsigned long dummy ){	atari_disable_irq( IRQ_MFP_FDC );	if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but					  * before we came here... */	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 */	if (UseTrackbuffer)		del_timer( &readtrack_timer );	FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );	udelay( 25 );		printk(KERN_ERR "floppy timeout\n" );	fd_error();  end:	atari_enable_irq( IRQ_MFP_FDC );}/* The (noop) seek operation here is needed to make the WP bit in the * FDC 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 ){	if (!NeedSeek) {		finish_fdc_done( 0 );	}	else {		DPRINT(("finish_fdc: dummy seek started\n"));		FDC_WRITE (FDCREG_DATA, SUD.track);		SET_IRQ_HANDLER( finish_fdc_done );		FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);		MotorOn = 1;		start_timeout();		/* we must wait for the IRQ here, because the ST-DMA		   is released immediately 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_pending(&fd_timer) && time_before(fd_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 :-((		 */		mod_timer(&fd_timer, jiffies + 5);	else		start_check_change_timer();	start_motor_off_timer();	local_irq_save(flags);	stdma_release();	fdc_busy = 0;	wake_up( &fdc_wait );	local_irq_restore(flags);	DPRINT(("finish_fdc() finished\n"));}/* The detection of disk changes is a dark chapter in Atari history :-( * Because the "Drive ready" signal isn't present in the Atari * hardware, one has to rely on the "Write Protect". This works fine, * as long as no write protected disks are used. TOS solves this * problem by introducing tri-state logic ("maybe changed") and * looking at the serial number in block 0. This isn't possible for * Linux, since the floppy driver can't make assumptions about the * filesystem used on the disk and thus the contents of block 0. I've * chosen the method to always say "The disk was changed" if it is * unsure whether it was. This implies that every open or mount * invalidates the disk buffers if you work with write protected * disks. But at least this is better than working with incorrect data * due to unrecognised disk changes. */static int check_floppy_change(struct gendisk *disk){	struct atari_floppy_struct *p = disk->private_data;	unsigned int drive = p - unit;	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 (UD.wpstat) {		/* WP is on -> could be changed: to be sure, buffers should be		 * invalidated...		 */		return 1;	}	return 0;}static int floppy_revalidate(struct gendisk *disk){	struct atari_floppy_struct *p = disk->private_data;	unsigned int drive = p - unit;	if (test_bit(drive, &changed_floppies) ||	    test_bit(drive, &fake_change) ||	    p->disktype == 0) {		if (UD.flags & FTD_MSG)			printk(KERN_ERR "floppy: clear format %p!\n", UDT);		BufferDrive = -1;		clear_bit(drive, &fake_change);		clear_bit(drive, &changed_floppies);		/* MSch: clearing geometry makes sense only for autoprobe		   formats, for 'permanent user-defined' parameter:		   restore default_params[] here if flagged valid! */		if (default_params[drive].blocks == 0)			UDT = 0;		else			UDT = &default_params[drive];	}	return 0;}/* This sets up the global variables describing the current request. */static void setup_req_params( int drive ){	int block = ReqBlock + ReqCnt;	ReqTrack = block / UDT->spt;	ReqSector = block - ReqTrack * UDT->spt + 1;	ReqSide = ReqTrack & 1;	ReqTrack >>= 1;	ReqData = ReqBuffer + 512 * ReqCnt;	if (UseTrackbuffer)		read_track = (ReqCmd == READ && CURRENT->errors == 0);	else		read_track = 0;	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 drive, type;	struct atari_floppy_struct *floppy;	DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",		CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",		CURRENT ? CURRENT->sector : 0 ));	IsFormatting = 0;repeat:	if (!CURRENT)		goto the_end;	floppy = CURRENT->rq_disk->private_data;	drive = floppy - unit;	type = floppy->type;		if (!UD.connected) {		/* drive not connected */		printk(KERN_ERR "Unknown Device: fd%d\n", drive );		end_request(CURRENT, 0);		goto repeat;	}			if (type == 0) {		if (!UDT) {			Probing = 1;			UDT = disk_type + StartDiskType[DriveType];			set_capacity(floppy->disk, UDT->blocks);			UD.autoprobe = 1;		}	} 	else {		/* user supplied disk type */		if (--type >= NUM_DISK_MINORS) {			printk(KERN_WARNING "fd%d: invalid disk format", drive );			end_request(CURRENT, 0);			goto repeat;		}		if (minor2disktype[type].drive_types > DriveType)  {			printk(KERN_WARNING "fd%d: unsupported disk format", drive );			end_request(CURRENT, 0);			goto repeat;		}		type = minor2disktype[type].index;		UDT = &disk_type[type];		set_capacity(floppy->disk, UDT->blocks);		UD.autoprobe = 0;	}		if (CURRENT->sector + 1 > UDT->blocks) {		end_request(CURRENT, 0);		goto repeat;	}	/* stop deselect timer */	del_timer( &motor_off_timer );			ReqCnt = 0;	ReqCmd = rq_data_dir(CURRENT);	ReqBlock = CURRENT->sector;	ReqBuffer = CURRENT->buffer;	setup_req_params( drive );	do_fd_action( drive );	return;  the_end:	finish_fdc();}void do_fd_request(request_queue_t * q){ 	unsigned long flags;	DPRINT(("do_fd_request for pid %d\n",current->pid));	while( fdc_busy ) sleep_on( &fdc_wait );	fdc_busy = 1;	stdma_lock(floppy_irq, NULL);	atari_disable_irq( IRQ_MFP_FDC );	local_save_flags(flags);	/* The request function is called with ints	local_irq_disable();		 * disabled... so must save the IPL for later */ 	redo_fd_request();	local_irq_restore(flags);	atari_enable_irq( IRQ_MFP_FDC );}static int fd_ioctl(struct inode *inode, struct file *filp,		    unsigned int cmd, unsigned long param){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct atari_floppy_struct *floppy = disk->private_data;	int drive = floppy - unit;	int type = floppy->type;	struct atari_format_descr fmt_desc;	struct atari_disk_type *dtp;	struct floppy_struct getprm;	int settype;	struct floppy_struct setprm;	switch (cmd) {	case FDGETPRM:		if (type) {			if (--type >= NUM_DISK_MINORS)				return -ENODEV;

⌨️ 快捷键说明

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