extractedLnx/linux-2.4.20/drivers/ide/ide.c_ide_ioctl.c
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err = 0, major, minor;
ide_drive_t *drive;
struct request rq;
kdev_t dev;
ide_settings_t *setting;
if (!inode || !(dev = inode->i_rdev))
return -EINVAL;
major = MAJOR(dev); minor = MINOR(dev);
if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
return -ENODEV;
if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) {
if (cmd == setting->read_ioctl) {
err = ide_read_setting(drive, setting);
return err >= 0 ? put_user(err, (long *) arg) : err;
} else {
if ((MINOR(inode->i_rdev) & PARTN_MASK))
return -EINVAL;
return ide_write_setting(drive, setting, arg);
}
}
ide_init_drive_cmd (&rq);
switch (cmd) {
case HDIO_GETGEO:
{
struct hd_geometry *loc = (struct hd_geometry *) arg;
unsigned short bios_cyl = drive->bios_cyl; /* truncate */
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
(unsigned long *) &loc->start)) return -EFAULT;
return 0;
}
case HDIO_GETGEO_BIG:
{
struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
(unsigned long *) &loc->start)) return -EFAULT;
return 0;
}
case HDIO_GETGEO_BIG_RAW:
{
struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
if (!loc || (drive->media != ide_disk && drive->media != ide_floppy)) return -EINVAL;
if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
(unsigned long *) &loc->start)) return -EFAULT;
return 0;
}
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (unsigned long *) arg);
case BLKGETSIZE64:
return put_user((u64)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects << 9, (u64 *) arg);
case BLKRRPART: /* Re-read partition tables */
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
return ide_revalidate_disk(inode->i_rdev);
case HDIO_OBSOLETE_IDENTITY:
case HDIO_GET_IDENTITY:
if (MINOR(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
if (drive->id == NULL)
return -ENOMSG;
if (copy_to_user((char *)arg, (char *)drive->id, (cmd == HDIO_GET_IDENTITY) ? sizeof(*drive->id) : 142))
return -EFAULT;
return 0;
case HDIO_GET_NICE:
return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP |
drive->nice0 << IDE_NICE_0 |
drive->nice1 << IDE_NICE_1 |
drive->nice2 << IDE_NICE_2,
(long *) arg);
#ifdef CONFIG_IDE_TASK_IOCTL
case HDIO_DRIVE_TASKFILE:
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
switch(drive->media) {
case ide_disk:
return ide_taskfile_ioctl(drive, inode, file, cmd, arg);
#ifdef CONFIG_PKT_TASK_IOCTL
case ide_cdrom:
case ide_tape:
case ide_floppy:
return pkt_taskfile_ioctl(drive, inode, file, cmd, arg);
#endif /* CONFIG_PKT_TASK_IOCTL */
default:
return -ENOMSG;
}
#endif /* CONFIG_IDE_TASK_IOCTL */
case HDIO_DRIVE_CMD:
{
byte args[4], *argbuf = args;
byte xfer_rate = 0;
int argsize = 4;
ide_task_t tfargs;
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
return -EACCES;
if (NULL == (void *) arg)
return ide_do_drive_cmd(drive, &rq, ide_wait);
if (copy_from_user(args, (void *)arg, 4))
return -EFAULT;
tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];
tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];
tfargs.tfRegister[IDE_SECTOR_OFFSET] = args[1];
tfargs.tfRegister[IDE_LCYL_OFFSET] = 0x00;
tfargs.tfRegister[IDE_HCYL_OFFSET] = 0x00;
tfargs.tfRegister[IDE_SELECT_OFFSET] = 0x00;
tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];
if (args[3]) {
argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL)
return -ENOMEM;
memcpy(argbuf, args, 4);
}
if (set_transfer(drive, &tfargs)) {
xfer_rate = args[1];
if (ide_ata66_check(drive, &tfargs))
goto abort;
}
err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
if (!err && xfer_rate) {
/* active-retuning-calls future */
if ((HWIF(drive)->speedproc) != NULL)
HWIF(drive)->speedproc(drive, xfer_rate);
ide_driveid_update(drive);
}
abort:
if (copy_to_user((void *)arg, argbuf, argsize))
err = -EFAULT;
if (argsize > 4)
kfree(argbuf);
return err;
}
case HDIO_DRIVE_TASK:
{
byte args[7], *argbuf = args;
int argsize = 7;
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) return -EACCES;
if (copy_from_user(args, (void *)arg, 7))
return -EFAULT;
err = ide_wait_cmd_task(drive, argbuf);
if (copy_to_user((void *)arg, argbuf, argsize))
err = -EFAULT;
return err;
}
case HDIO_SCAN_HWIF:
{
int args[3];
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
if (copy_from_user(args, (void *)arg, 3 * sizeof(int)))
return -EFAULT;
if (ide_register(args[0], args[1], args[2]) == -1)
return -EIO;
return 0;
}
case HDIO_UNREGISTER_HWIF:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
/* (arg > MAX_HWIFS) checked in function */
ide_unregister(arg);
return 0;
case HDIO_SET_NICE:
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
if (drive->driver == NULL)
return -EPERM;
if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP) | (1 << IDE_NICE_1))))
return -EPERM;
drive->dsc_overlap = (arg >> IDE_NICE_DSC_OVERLAP) & 1;
if (drive->dsc_overlap && !DRIVER(drive)->supports_dsc_overlap) {
drive->dsc_overlap = 0;
return -EPERM;
}
drive->nice1 = (arg >> IDE_NICE_1) & 1;
return 0;
case HDIO_DRIVE_RESET:
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
if (!capable(CAP_SYS_ADMIN)) return -EACCES;
#if 1
spin_lock_irqsave(&io_request_lock, flags);
if (hwgroup->handler != NULL) {
printk("%s: ide_set_handler: handler not null; %p\n", drive->name, hwgroup->handler);
(void) hwgroup->handler(drive);
// hwgroup->handler = NULL;
// hwgroup->expiry = NULL;
hwgroup->timer.expires = jiffies + 0;;
del_timer(&hwgroup->timer);
}
spin_unlock_irqrestore(&io_request_lock, flags);
#endif
(void) ide_do_reset(drive);
if (drive->suspend_reset) {
/*
* APM WAKE UP todo !!
* int nogoodpower = 1;
* while(nogoodpower) {
* check_power1() or check_power2()
* nogoodpower = 0;
* }
* HWIF(drive)->multiproc(drive);
*/
return ide_revalidate_disk(inode->i_rdev);
}
return 0;
}
case BLKROSET:
case BLKROGET:
case BLKFLSBUF:
case BLKSSZGET:
case BLKPG:
case BLKELVGET:
case BLKELVSET:
case BLKBSZGET:
case BLKBSZSET:
return blk_ioctl(inode->i_rdev, cmd, arg);
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (put_user(HWIF(drive)->bus_state, (long *)arg))
return -EFAULT;
return 0;
case HDIO_SET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
if (HWIF(drive)->busproc)
HWIF(drive)->busproc(drive, (int)arg);
return 0;
default:
if (drive->driver != NULL)
return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
return -EPERM;
}
}
Generated by GNU enscript 1.6.4.