extractedLnx/linux/drivers/block/ide.c_ide_ioctl.c
static int ide_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err, major, minor;
ide_drive_t *drive;
unsigned long flags;
struct request rq;
kdev_t dev;
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;
ide_init_drive_cmd (&rq);
switch (cmd) {
case HDIO_GETGEO:
{
struct hd_geometry *loc = (struct hd_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 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 BLKFLSBUF:
if (!suser()) return -EACCES;
fsync_dev(inode->i_rdev);
invalidate_buffers(inode->i_rdev);
return 0;
case BLKRASET:
if (!suser()) return -EACCES;
if(arg > 0xff) return -EINVAL;
read_ahead[MAJOR(inode->i_rdev)] = arg;
return 0;
case BLKRAGET:
return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg);
case BLKGETSIZE: /* Return device size */
return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg);
case BLKFRASET:
if (!suser()) return -EACCES;
max_readahead[major][minor] = arg;
return 0;
case BLKFRAGET:
return put_user(max_readahead[major][minor], (long *) arg);
case BLKSECTSET:
if (!suser()) return -EACCES;
if (!arg || arg > 0xff) return -EINVAL;
max_sectors[major][minor] = arg;
return 0;
case BLKSECTGET:
return put_user(max_sectors[major][minor], (long *) arg);
case BLKRRPART: /* Re-read partition tables */
if (!suser()) return -EACCES;
return ide_revalidate_disk(inode->i_rdev);
case HDIO_GET_KEEPSETTINGS:
return put_user(drive->keep_settings, (long *) arg);
case HDIO_GET_UNMASKINTR:
return put_user(drive->unmask, (long *) arg);
case HDIO_GET_DMA:
return put_user(drive->using_dma, (long *) arg);
case HDIO_GET_32BIT:
return put_user(drive->io_32bit, (long *) arg);
case HDIO_GET_MULTCOUNT:
return put_user(drive->mult_count, (long *) arg);
case HDIO_GET_IDENTITY:
if (MINOR(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
if (drive->id == NULL)
return -ENOMSG;
#if 0
if (copy_to_user((char *)arg, (char *)drive->id, sizeof(*drive->id)))
return -EFAULT;
#else
if (copy_to_user((char *)arg, (char *)drive->id, 142))
return -EFAULT;
#endif
return 0;
case HDIO_GET_NOWERR:
return put_user(drive->bad_wstat == BAD_R_STAT, (long *) arg);
case HDIO_GET_NICE:
{
long nice = 0;
nice |= drive->dsc_overlap << IDE_NICE_DSC_OVERLAP;
nice |= drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP;
nice |= drive->nice0 << IDE_NICE_0;
nice |= drive->nice1 << IDE_NICE_1;
nice |= drive->nice2 << IDE_NICE_2;
return put_user(nice, (long *) arg);
}
case HDIO_SET_DMA:
if (!suser()) return -EACCES;
if (drive->driver != NULL && !DRIVER(drive)->supports_dma)
return -EPERM;
if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc)
return -EPERM;
case HDIO_SET_KEEPSETTINGS:
case HDIO_SET_UNMASKINTR:
case HDIO_SET_NOWERR:
if (arg > 1)
return -EINVAL;
case HDIO_SET_32BIT:
if (!suser()) return -EACCES;
if ((MINOR(inode->i_rdev) & PARTN_MASK))
return -EINVAL;
save_flags(flags);
cli();
switch (cmd) {
case HDIO_SET_DMA:
if (!(HWIF(drive)->dmaproc)) {
restore_flags(flags);
return -EPERM;
}
if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) {
restore_flags(flags);
return -EIO;
}
break;
case HDIO_SET_KEEPSETTINGS:
drive->keep_settings = arg;
break;
case HDIO_SET_UNMASKINTR:
if (arg && drive->no_unmask) {
restore_flags(flags);
return -EPERM;
}
drive->unmask = arg;
break;
case HDIO_SET_NOWERR:
drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
break;
case HDIO_SET_32BIT:
if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) {
restore_flags(flags);
return -EINVAL;
}
if (arg && drive->no_io_32bit) {
restore_flags(flags);
return -EPERM;
}
drive->io_32bit = arg;
#ifdef CONFIG_BLK_DEV_DTC2278
if (HWIF(drive)->chipset == ide_dtc2278)
HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg;
#endif /* CONFIG_BLK_DEV_DTC2278 */
break;
}
restore_flags(flags);
return 0;
case HDIO_SET_MULTCOUNT:
if (!suser()) return -EACCES;
if (MINOR(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
if (drive->id && arg > drive->id->max_multsect)
return -EINVAL;
save_flags(flags);
cli();
if (drive->special.b.set_multmode) {
restore_flags(flags);
return -EBUSY;
}
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
restore_flags(flags);
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
return (drive->mult_count == arg) ? 0 : -EIO;
case HDIO_DRIVE_CMD:
{
byte args[4], *argbuf = args;
int argsize = 4;
if (!suser()) 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;
if (args[3]) {
argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
argbuf = kmalloc(argsize, GFP_KERNEL);
if (argbuf == NULL)
return -ENOMEM;
memcpy(argbuf, args, 4);
}
rq.buffer = argbuf;
err = ide_do_drive_cmd(drive, &rq, ide_wait);
if (copy_to_user((void *)arg, argbuf, argsize))
err = -EFAULT;
if (argsize > 4)
kfree(argbuf);
return err;
}
case HDIO_SET_PIO_MODE:
if (!suser()) return -EACCES;
if (MINOR(inode->i_rdev) & PARTN_MASK)
return -EINVAL;
if (!HWIF(drive)->tuneproc)
return -ENOSYS;
save_flags(flags);
cli();
if (drive->special.b.set_tune) {
restore_flags(flags);
return -EBUSY;
}
drive->tune_req = (byte) arg;
drive->special.b.set_tune = 1;
restore_flags(flags);
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
return 0;
case HDIO_SCAN_HWIF:
{
int args[3];
if (!suser()) 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_SET_NICE:
if (!suser()) 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;
RO_IOCTLS(inode->i_rdev, arg);
default:
if (drive->driver != NULL)
return DRIVER(drive)->ioctl(drive, inode, file, cmd, arg);
return -EPERM;
}
}
Generated by GNU enscript 1.6.4.