static int fd_locked_ioctl()

in ataflop.c [1582:1767]


static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
		    unsigned int cmd, unsigned long param)
{
	struct gendisk *disk = 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;
	void __user *argp = (void __user *)param;

	switch (cmd) {
	case FDGETPRM:
		if (type) {
			if (--type >= NUM_DISK_MINORS)
				return -ENODEV;
			if (minor2disktype[type].drive_types > DriveType)
				return -ENODEV;
			type = minor2disktype[type].index;
			dtp = &atari_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(argp, &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, argp, sizeof(setprm)))
			return -EFAULT;
		/* 
		 * first of all: check for floppy change and revalidate, 
		 * or the next access will revalidate - and clear UDT :-(
		 */

		if (floppy_check_events(disk, 0))
		        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 */
			finish_fdc();
			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 = &atari_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(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 (setprm.track != dtp->blocks/dtp->spt/2 ||
		    setprm.head != 2) {
			finish_fdc();
			return -EINVAL;
		}

		UDT = dtp;
		set_capacity(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, argp, 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(disk, MAX_DISK_SIZE * 2);
		fallthrough;
	case FDFMTEND:
	case FDFLUSH:
		/* invalidate the buffer track to force a reread */
		BufferDrive = -1;
		set_bit(drive, &fake_change);
		if (bdev_check_media_change(bdev))
			floppy_revalidate(bdev->bd_disk);
		return 0;
	default:
		return -EINVAL;
	}
}