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;
}
}