Esempio n. 1
0
int set_pio_mode(ide_drive_t *drive, int arg)
{
	struct request rq;

	if (arg < 0 || arg > 255)
		return -EINVAL;

	if (!HWIF(drive)->tuneproc)
		return -ENOSYS;
	if (drive->special.b.set_tune)
		return -EBUSY;
	ide_init_drive_cmd(&rq);
	drive->tune_req = (u8) arg;
	drive->special.b.set_tune = 1;
	(void) ide_do_drive_cmd(drive, &rq, ide_wait);
	return 0;
}
int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
	u8 *buf = NULL;
	int bufsize = 0, err = 0;
	u8 args[4], xfer_rate = 0;
	ide_task_t tfargs;
	struct ide_taskfile *tf = &tfargs.tf;
	struct hd_driveid *id = drive->id;

	if (NULL == (void *) arg) {
		struct request rq;

		ide_init_drive_cmd(&rq);
		rq.cmd_type = REQ_TYPE_ATA_TASKFILE;

		return ide_do_drive_cmd(drive, &rq, ide_wait);
	}

	if (copy_from_user(args, (void __user *)arg, 4))
		return -EFAULT;

	memset(&tfargs, 0, sizeof(ide_task_t));
	tf->feature = args[2];
	if (args[0] == WIN_SMART) {
		tf->nsect = args[3];
		tf->lbal  = args[1];
		tf->lbam  = 0x4f;
		tf->lbah  = 0xc2;
		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
	} else {
		tf->nsect = args[1];
		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
	}
	tf->command = args[0];
	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;

	if (args[3]) {
		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
		bufsize = SECTOR_WORDS * 4 * args[3];
		buf = kzalloc(bufsize, GFP_KERNEL);
		if (buf == NULL)
			return -ENOMEM;
	}

	if (tf->command == WIN_SETFEATURES &&
	    tf->feature == SETFEATURES_XFER &&
	    tf->nsect >= XFER_SW_DMA_0 &&
	    (id->dma_ultra || id->dma_mword || id->dma_1word)) {
		xfer_rate = args[1];
		if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
					    "be set\n", drive->name);
			goto abort;
		}
	}

	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);

	args[0] = tf->status;
	args[1] = tf->error;
	args[2] = tf->nsect;

	if (!err && xfer_rate) {
		/* active-retuning-calls future */
		ide_set_xfer_rate(drive, xfer_rate);
		ide_driveid_update(drive);
	}
abort:
	if (copy_to_user((void __user *)arg, &args, 4))
		err = -EFAULT;
	if (buf) {
		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
			err = -EFAULT;
		kfree(buf);
	}
	return err;
}