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; }