Source
x
/*
* IDE ioctls handling.
*/
static const struct ide_ioctl_devset ide_ioctl_settings[] = {
{ HDIO_GET_32BIT, HDIO_SET_32BIT, &ide_devset_io_32bit },
{ HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, &ide_devset_keepsettings },
{ HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, &ide_devset_unmaskirq },
{ HDIO_GET_DMA, HDIO_SET_DMA, &ide_devset_using_dma },
{ -1, HDIO_SET_PIO_MODE, &ide_devset_pio_mode },
{ 0 }
};
int ide_setting_ioctl(ide_drive_t *drive, struct block_device *bdev,
unsigned int cmd, unsigned long arg,
const struct ide_ioctl_devset *s)
{
const struct ide_devset *ds;
int err = -EOPNOTSUPP;
for (; (ds = s->setting); s++) {
if (ds->get && s->get_ioctl == cmd)
goto read_val;
else if (ds->set && s->set_ioctl == cmd)
goto set_val;
}
return err;
read_val:
mutex_lock(&ide_setting_mtx);
err = ds->get(drive);
mutex_unlock(&ide_setting_mtx);
return err >= 0 ? put_user(err, (long __user *)arg) : err;
set_val:
if (bdev != bdev->bd_contains)
err = -EINVAL;
else {
if (!capable(CAP_SYS_ADMIN))
err = -EACCES;
else {
mutex_lock(&ide_setting_mtx);
err = ide_devset_execute(drive, ds, arg);
mutex_unlock(&ide_setting_mtx);
}
}
return err;
}
EXPORT_SYMBOL_GPL(ide_setting_ioctl);
static int ide_get_identity_ioctl(ide_drive_t *drive, unsigned int cmd,
unsigned long arg)
{
u16 *id = NULL;
int size = (cmd == HDIO_GET_IDENTITY) ? (ATA_ID_WORDS * 2) : 142;
int rc = 0;
if ((drive->dev_flags & IDE_DFLAG_ID_READ) == 0) {
rc = -ENOMSG;
goto out;
}
/* ata_id_to_hd_driveid() relies on 'id' to be fully allocated. */
id = kmalloc(ATA_ID_WORDS * 2, GFP_KERNEL);
if (id == NULL) {
rc = -ENOMEM;
goto out;
}
memcpy(id, drive->id, size);
ata_id_to_hd_driveid(id);
if (copy_to_user((void __user *)arg, id, size))
rc = -EFAULT;
kfree(id);
out:
return rc;
}
static int ide_get_nice_ioctl(ide_drive_t *drive, unsigned long arg)
{
return put_user((!!(drive->dev_flags & IDE_DFLAG_DSC_OVERLAP)
<< IDE_NICE_DSC_OVERLAP) |
(!!(drive->dev_flags & IDE_DFLAG_NICE1)
<< IDE_NICE_1), (long __user *)arg);