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

📄 ataflop.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			if (minor2disktype[type].drive_types > DriveType)				return -ENODEV;			type = minor2disktype[type].index;			dtp = &disk_type[type];			if (UD.flags & FTD_MSG)			    printk (KERN_ERR "floppy%d: found dtp %p name %s!\n",			        drive, dtp, dtp->name);		}		else {			if (!UDT)				return -ENXIO;			else				dtp = UDT;		}		memset((void *)&getprm, 0, sizeof(getprm));		getprm.size = dtp->blocks;		getprm.sect = dtp->spt;		getprm.head = 2;		getprm.track = dtp->blocks/dtp->spt/2;		getprm.stretch = dtp->stretch;		if (copy_to_user((void *)param, &getprm, sizeof(getprm)))			return -EFAULT;		return 0;	}	switch (cmd) {	case FDSETPRM:	case FDDEFPRM:	        /* 		 * MSch 7/96: simple 'set geometry' case: just set the		 * 'default' device params (minor == 0).		 * Currently, the drive geometry is cleared after each		 * disk change and subsequent revalidate()! simple		 * implementation of FDDEFPRM: save geometry from a		 * FDDEFPRM call and restore it in floppy_revalidate() !		 */		/* get the parameters from user space */		if (floppy->ref != 1 && floppy->ref != -1)			return -EBUSY;		if (copy_from_user(&setprm, (void *) param, sizeof(setprm)))			return -EFAULT;		/* 		 * first of all: check for floppy change and revalidate, 		 * or the next access will revalidate - and clear UDT :-(		 */		if (check_floppy_change(disk))		        floppy_revalidate(disk);		if (UD.flags & FTD_MSG)		    printk (KERN_INFO "floppy%d: setting size %d spt %d str %d!\n",			drive, setprm.size, setprm.sect, setprm.stretch);		/* what if type > 0 here? Overwrite specified entry ? */		if (type) {		        /* refuse to re-set a predefined type for now */			redo_fd_request();			return -EINVAL;		}		/* 		 * type == 0: first look for a matching entry in the type list,		 * and set the UD.disktype field to use the perdefined entry.		 * TODO: add user-defined format to head of autoprobe list ? 		 * Useful to include the user-type for future autodetection!		 */		for (settype = 0; settype < NUM_DISK_MINORS; settype++) {			int setidx = 0;			if (minor2disktype[settype].drive_types > DriveType) {				/* skip this one, invalid for drive ... */				continue;			}			setidx = minor2disktype[settype].index;			dtp = &disk_type[setidx];			/* found matching entry ?? */			if (   dtp->blocks  == setprm.size 			    && dtp->spt     == setprm.sect			    && dtp->stretch == setprm.stretch ) {				if (UD.flags & FTD_MSG)				    printk (KERN_INFO "floppy%d: setting %s %p!\n",				        drive, dtp->name, dtp);				UDT = dtp;				set_capacity(floppy->disk, UDT->blocks);				if (cmd == FDDEFPRM) {				  /* save settings as permanent default type */				  default_params[drive].name    = dtp->name;				  default_params[drive].spt     = dtp->spt;				  default_params[drive].blocks  = dtp->blocks;				  default_params[drive].fdc_speed = dtp->fdc_speed;				  default_params[drive].stretch = dtp->stretch;				}								return 0;			}		}		/* no matching disk type found above - setting user_params */	       	if (cmd == FDDEFPRM) {			/* set permanent type */			dtp = &default_params[drive];		} else			/* set user type (reset by disk change!) */			dtp = &user_params[drive];		dtp->name   = "user format";		dtp->blocks = setprm.size;		dtp->spt    = setprm.sect;		if (setprm.sect > 14) 			dtp->fdc_speed = 3;		else			dtp->fdc_speed = 0;		dtp->stretch = setprm.stretch;		if (UD.flags & FTD_MSG)			printk (KERN_INFO "floppy%d: blk %d spt %d str %d!\n",				drive, dtp->blocks, dtp->spt, dtp->stretch);		/* sanity check */		if (!dtp || setprm.track != dtp->blocks/dtp->spt/2 ||		    setprm.head != 2) {			redo_fd_request();			return -EINVAL;		}		UDT = dtp;		set_capacity(floppy->disk, UDT->blocks);		return 0;	case FDMSGON:		UD.flags |= FTD_MSG;		return 0;	case FDMSGOFF:		UD.flags &= ~FTD_MSG;		return 0;	case FDSETEMSGTRESH:		return -EINVAL;	case FDFMTBEG:		return 0;	case FDFMTTRK:		if (floppy->ref != 1 && floppy->ref != -1)			return -EBUSY;		if (copy_from_user(&fmt_desc, (void *) param, sizeof(fmt_desc)))			return -EFAULT;		return do_format(drive, type, &fmt_desc);	case FDCLRPRM:		UDT = NULL;		/* MSch: invalidate default_params */		default_params[drive].blocks  = 0;		set_capacity(floppy->disk, MAX_DISK_SIZE * 2);	case FDFMTEND:	case FDFLUSH:		/* invalidate the buffer track to force a reread */		BufferDrive = -1;		set_bit(drive, &fake_change);		check_disk_change(inode->i_bdev);		return 0;	default:		return -EINVAL;	}}/* Initialize the 'unit' variable for drive 'drive' */static void __init fd_probe( int drive ){	UD.connected = 0;	UDT  = NULL;	if (!fd_test_drive_present( drive ))		return;	UD.connected = 1;	UD.track     = 0;	switch( UserSteprate[drive] ) {	case 2:		UD.steprate = FDCSTEP_2;		break;	case 3:		UD.steprate = FDCSTEP_3;		break;	case 6:		UD.steprate = FDCSTEP_6;		break;	case 12:		UD.steprate = FDCSTEP_12;		break;	default: /* should be -1 for "not set by user" */		if (ATARIHW_PRESENT( FDCSPEED ) || MACH_IS_MEDUSA)			UD.steprate = FDCSTEP_3;		else			UD.steprate = FDCSTEP_6;		break;	}	MotorOn = 1;	/* from probe restore operation! */}/* This function tests the physical presence of a floppy drive (not * whether a disk is inserted). This is done by issuing a restore * command, waiting max. 2 seconds (that should be enough to move the * head across the whole disk) and looking at the state of the "TR00" * signal. This should now be raised if there is a drive connected * (and there is no hardware failure :-) Otherwise, the drive is * declared absent. */static int __init fd_test_drive_present( int drive ){	unsigned long timeout;	unsigned char status;	int ok;		if (drive >= (MACH_IS_FALCON ? 1 : 2)) return( 0 );	fd_select_drive( drive );	/* disable interrupt temporarily */	atari_turnoff_irq( IRQ_MFP_FDC );	FDC_WRITE (FDCREG_TRACK, 0xff00);	FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCCMDADD_H | FDCSTEP_6 );	timeout = jiffies + 2*HZ+HZ/2;	while (time_before(jiffies, timeout))		if (!(mfp.par_dt_reg & 0x20))			break;	status = FDC_READ( FDCREG_STATUS );	ok = (status & FDCSTAT_TR00) != 0;	/* force interrupt to abort restore operation (FDC would try	 * about 50 seconds!) */	FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );	udelay(500);	status = FDC_READ( FDCREG_STATUS );	udelay(20);	if (ok) {		/* dummy seek command to make WP bit accessible */		FDC_WRITE( FDCREG_DATA, 0 );		FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );		while( mfp.par_dt_reg & 0x20 )			;		status = FDC_READ( FDCREG_STATUS );	}	atari_turnon_irq( IRQ_MFP_FDC );	return( ok );}/* Look how many and which kind of drives are connected. If there are * floppies, additionally start the disk-change and motor-off timers. */static void __init config_types( void ){	int drive, cnt = 0;	/* for probing drives, set the FDC speed to 8 MHz */	if (ATARIHW_PRESENT(FDCSPEED))		dma_wd.fdc_speed = 0;	printk(KERN_INFO "Probing floppy drive(s):\n");	for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {		fd_probe( drive );		if (UD.connected) {			printk(KERN_INFO "fd%d\n", drive);			++cnt;		}	}	if (FDC_READ( FDCREG_STATUS ) & FDCSTAT_BUSY) {		/* If FDC is still busy from probing, give it another FORCI		 * command to abort the operation. If this isn't done, the FDC		 * will interrupt later and its IRQ line stays low, because		 * the status register isn't read. And this will block any		 * interrupts on this IRQ line :-(		 */		FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );		udelay(500);		FDC_READ( FDCREG_STATUS );		udelay(20);	}		if (cnt > 0) {		start_motor_off_timer();		if (cnt == 1) fd_select_drive( 0 );		start_check_change_timer();	}}/* * floppy_open check for aliasing (/dev/fd0 can be the same as * /dev/PS0 etc), and disallows simultaneous access to the same * drive with different device numbers. */static int floppy_open( struct inode *inode, struct file *filp ){	struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;	int type  = iminor(inode) >> 2;	DPRINT(("fd_open: type=%d\n",type));	if (p->ref && p->type != type)		return -EBUSY;	if (p->ref == -1 || (p->ref && filp->f_flags & O_EXCL))		return -EBUSY;	if (filp->f_flags & O_EXCL)		p->ref = -1;	else		p->ref++;	p->type = type;	if (filp->f_flags & O_NDELAY)		return 0;	if (filp->f_mode & 3) {		check_disk_change(inode->i_bdev);		if (filp->f_mode & 2) {			if (p->wpstat) {				if (p->ref < 0)					p->ref = 0;				else					p->ref--;				floppy_release(inode, filp);				return -EROFS;			}		}	}	return 0;}static int floppy_release( struct inode * inode, struct file * filp ){	struct atari_floppy_struct *p = inode->i_bdev->bd_disk->private_data;	if (p->ref < 0)		p->ref = 0;	else if (!p->ref--) {		printk(KERN_ERR "floppy_release with fd_ref == 0");		p->ref = 0;	}	return 0;}static struct block_device_operations floppy_fops = {	.owner		= THIS_MODULE,	.open		= floppy_open,	.release	= floppy_release,	.ioctl		= fd_ioctl,	.media_changed	= check_floppy_change,	.revalidate_disk= floppy_revalidate,};static struct kobject *floppy_find(dev_t dev, int *part, void *data){	int drive = *part & 3;	int type  = *part >> 2;	if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)		return NULL;	*part = 0;	return get_disk(unit[drive].disk);}static int __init atari_floppy_init (void){	int i;	if (!MACH_IS_ATARI)		/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */		return -ENXIO;	if (MACH_IS_HADES)		/* Hades doesn't have Atari-compatible floppy */		return -ENXIO;	if (register_blkdev(FLOPPY_MAJOR,"fd"))		return -EBUSY;	for (i = 0; i < FD_MAX_UNITS; i++) {		unit[i].disk = alloc_disk(1);		if (!unit[i].disk)			goto Enomem;	}	if (UseTrackbuffer < 0)		/* not set by user -> use default: for now, we turn		   track buffering off for all Medusas, though it		   could be used with ones that have a counter		   card. But the test is too hard :-( */		UseTrackbuffer = !MACH_IS_MEDUSA;	/* initialize variables */	SelectedDrive = -1;	BufferDrive = -1;	DMABuffer = atari_stram_alloc(BUFFER_SIZE+512, "ataflop");	if (!DMABuffer) {		printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");		goto Enomem;	}	TrackBuffer = DMABuffer + 512;	PhysDMABuffer = virt_to_phys(DMABuffer);	PhysTrackBuffer = virt_to_phys(TrackBuffer);	BufferDrive = BufferSide = BufferTrack = -1;	floppy_queue = blk_init_queue(do_fd_request, &ataflop_lock);	if (!floppy_queue)		goto Enomem;	for (i = 0; i < FD_MAX_UNITS; i++) {		unit[i].track = -1;		unit[i].flags = 0;		unit[i].disk->major = FLOPPY_MAJOR;		unit[i].disk->first_minor = i;		sprintf(unit[i].disk->disk_name, "fd%d", i);		unit[i].disk->fops = &floppy_fops;		unit[i].disk->private_data = &unit[i];		unit[i].disk->queue = floppy_queue;		set_capacity(unit[i].disk, MAX_DISK_SIZE * 2);		add_disk(unit[i].disk);	}	blk_register_region(MKDEV(FLOPPY_MAJOR, 0), 256, THIS_MODULE,				floppy_find, NULL, NULL);	printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",	       DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',	       UseTrackbuffer ? "" : "no ");	config_types();	return 0;Enomem:	while (i--)		put_disk(unit[i].disk);	if (floppy_queue)		blk_cleanup_queue(floppy_queue);	unregister_blkdev(FLOPPY_MAJOR, "fd");	return -ENOMEM;}void __init atari_floppy_setup( char *str, int *ints ){	int i;		if (ints[0] < 1) {		printk(KERN_ERR "ataflop_setup: no arguments!\n" );		return;	}	else if (ints[0] > 2+FD_MAX_UNITS) {		printk(KERN_ERR "ataflop_setup: too many arguments\n" );	}	if (ints[1] < 0 || ints[1] > 2)		printk(KERN_ERR "ataflop_setup: bad drive type\n" );	else		DriveType = ints[1];	if (ints[0] >= 2)		UseTrackbuffer = (ints[2] > 0);	for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) {		if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12)			printk(KERN_ERR "ataflop_setup: bad steprate\n" );		else			UserSteprate[i-3] = ints[i];	}}static void atari_floppy_exit(void){	int i;	blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);	for (i = 0; i < FD_MAX_UNITS; i++) {		del_gendisk(unit[i].disk);		put_disk(unit[i].disk);	}	unregister_blkdev(FLOPPY_MAJOR, "fd");	blk_cleanup_queue(floppy_queue);	del_timer_sync(&fd_timer);	atari_stram_free( DMABuffer );}module_init(atari_floppy_init)module_exit(atari_floppy_exit)MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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