Enscript Output

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.