From 2e9aa08a4801d439daec4c7d1b953c27b212d423 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 4 May 2014 17:05:08 -0700 Subject: [PATCH] cdrom: Move mmc_ioctls above cdrom_ioctl to remove unnecessary prototype Neaten the spacing too. Signed-off-by: Joe Perches Signed-off-by: Jens Axboe --- drivers/cdrom/cdrom.c | 806 +++++++++++++++++++++--------------------- 1 file changed, 402 insertions(+), 404 deletions(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 08abbae6bf68..332c3aee1346 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -337,8 +337,6 @@ do { \ #define CDROM_DEF_TIMEOUT (7 * HZ) /* Not-exported routines. */ -static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, - unsigned long arg); int cdrom_get_last_written(struct cdrom_device_info *, long *); static int cdrom_get_next_writable(struct cdrom_device_info *, long *); @@ -2713,6 +2711,408 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi, return cdi->ops->audio_ioctl(cdi, cmd, NULL); } +/* + * Required when we need to use READ_10 to issue other than 2048 block + * reads + */ +static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct packet_command cgc; + struct modesel_head mh; + + memset(&mh, 0, sizeof(mh)); + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + memset(&cgc, 0, sizeof(cgc)); + cgc.cmd[0] = 0x15; + cgc.cmd[1] = 1 << 4; + cgc.cmd[4] = 12; + cgc.buflen = sizeof(mh); + cgc.buffer = (char *) &mh; + cgc.data_direction = CGC_DATA_WRITE; + mh.block_desc_length = 0x08; + mh.block_length_med = (size >> 8) & 0xff; + mh.block_length_lo = size & 0xff; + + return cdo->generic_packet(cdi, &cgc); +} + +static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc, + int cmd) +{ + struct request_sense sense; + struct cdrom_msf msf; + int blocksize = 0, format = 0, lba; + int ret; + + switch (cmd) { + case CDROMREADRAW: + blocksize = CD_FRAMESIZE_RAW; + break; + case CDROMREADMODE1: + blocksize = CD_FRAMESIZE; + format = 2; + break; + case CDROMREADMODE2: + blocksize = CD_FRAMESIZE_RAW0; + break; + } + if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) + return -EFAULT; + lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0) + return -EINVAL; + + cgc->buffer = kzalloc(blocksize, GFP_KERNEL); + if (cgc->buffer == NULL) + return -ENOMEM; + + memset(&sense, 0, sizeof(sense)); + cgc->sense = &sense; + cgc->data_direction = CGC_DATA_READ; + ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize); + if (ret && sense.sense_key == 0x05 && + sense.asc == 0x20 && + sense.ascq == 0x00) { + /* + * SCSI-II devices are not required to support + * READ_CD, so let's try switching block size + */ + /* FIXME: switch back again... */ + ret = cdrom_switch_blocksize(cdi, blocksize); + if (ret) + goto out; + cgc->sense = NULL; + ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1); + ret |= cdrom_switch_blocksize(cdi, blocksize); + } + if (!ret && copy_to_user(arg, cgc->buffer, blocksize)) + ret = -EFAULT; +out: + kfree(cgc->buffer); + return ret; +} + +static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi, + void __user *arg) +{ + struct cdrom_read_audio ra; + int lba; + + if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg, + sizeof(ra))) + return -EFAULT; + + if (ra.addr_format == CDROM_MSF) + lba = msf_to_lba(ra.addr.msf.minute, + ra.addr.msf.second, + ra.addr.msf.frame); + else if (ra.addr_format == CDROM_LBA) + lba = ra.addr.lba; + else + return -EINVAL; + + /* FIXME: we need upper bound checking, too!! */ + if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) + return -EINVAL; + + return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes); +} + +static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi, + void __user *arg) +{ + int ret; + struct cdrom_subchnl q; + u_char requested, back; + if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q))) + return -EFAULT; + requested = q.cdsc_format; + if (!((requested == CDROM_MSF) || + (requested == CDROM_LBA))) + return -EINVAL; + q.cdsc_format = CDROM_MSF; + ret = cdrom_read_subchannel(cdi, &q, 0); + if (ret) + return ret; + back = q.cdsc_format; /* local copy */ + sanitize_format(&q.cdsc_absaddr, &back, requested); + sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); + if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q))) + return -EFAULT; + /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ + return 0; +} + +static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_msf msf; + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); + if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) + return -EFAULT; + cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF; + cgc->cmd[3] = msf.cdmsf_min0; + cgc->cmd[4] = msf.cdmsf_sec0; + cgc->cmd[5] = msf.cdmsf_frame0; + cgc->cmd[6] = msf.cdmsf_min1; + cgc->cmd[7] = msf.cdmsf_sec1; + cgc->cmd[8] = msf.cdmsf_frame1; + cgc->data_direction = CGC_DATA_NONE; + return cdo->generic_packet(cdi, cgc); +} + +static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc) +{ + struct cdrom_device_ops *cdo = cdi->ops; + struct cdrom_blk blk; + cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); + if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) + return -EFAULT; + cgc->cmd[0] = GPCMD_PLAY_AUDIO_10; + cgc->cmd[2] = (blk.from >> 24) & 0xff; + cgc->cmd[3] = (blk.from >> 16) & 0xff; + cgc->cmd[4] = (blk.from >> 8) & 0xff; + cgc->cmd[5] = blk.from & 0xff; + cgc->cmd[7] = (blk.len >> 8) & 0xff; + cgc->cmd[8] = blk.len & 0xff; + cgc->data_direction = CGC_DATA_NONE; + return cdo->generic_packet(cdi, cgc); +} + +static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc, + unsigned int cmd) +{ + struct cdrom_volctrl volctrl; + unsigned char buffer[32]; + char mask[sizeof(buffer)]; + unsigned short offset; + int ret; + + cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n"); + + if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg, + sizeof(volctrl))) + return -EFAULT; + + cgc->buffer = buffer; + cgc->buflen = 24; + ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 0); + if (ret) + return ret; + + /* originally the code depended on buffer[1] to determine + how much data is available for transfer. buffer[1] is + unfortunately ambigious and the only reliable way seem + to be to simply skip over the block descriptor... */ + offset = 8 + be16_to_cpu(*(__be16 *)(buffer + 6)); + + if (offset + 16 > sizeof(buffer)) + return -E2BIG; + + if (offset + 16 > cgc->buflen) { + cgc->buflen = offset + 16; + ret = cdrom_mode_sense(cdi, cgc, + GPMODE_AUDIO_CTL_PAGE, 0); + if (ret) + return ret; + } + + /* sanity check */ + if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || + buffer[offset + 1] < 14) + return -EINVAL; + + /* now we have the current volume settings. if it was only + a CDROMVOLREAD, return these values */ + if (cmd == CDROMVOLREAD) { + volctrl.channel0 = buffer[offset+9]; + volctrl.channel1 = buffer[offset+11]; + volctrl.channel2 = buffer[offset+13]; + volctrl.channel3 = buffer[offset+15]; + if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl, + sizeof(volctrl))) + return -EFAULT; + return 0; + } + + /* get the volume mask */ + cgc->buffer = mask; + ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 1); + if (ret) + return ret; + + buffer[offset + 9] = volctrl.channel0 & mask[offset + 9]; + buffer[offset + 11] = volctrl.channel1 & mask[offset + 11]; + buffer[offset + 13] = volctrl.channel2 & mask[offset + 13]; + buffer[offset + 15] = volctrl.channel3 & mask[offset + 15]; + + /* set volume */ + cgc->buffer = buffer + offset - 8; + memset(cgc->buffer, 0, 8); + return cdrom_mode_select(cdi, cgc); +} + +static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, + struct packet_command *cgc, + int cmd) +{ + struct cdrom_device_ops *cdo = cdi->ops; + cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); + cgc->cmd[0] = GPCMD_START_STOP_UNIT; + cgc->cmd[1] = 1; + cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0; + cgc->data_direction = CGC_DATA_NONE; + return cdo->generic_packet(cdi, cgc); +} + +static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, + struct packet_command *cgc, + int cmd) +{ + struct cdrom_device_ops *cdo = cdi->ops; + cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); + cgc->cmd[0] = GPCMD_PAUSE_RESUME; + cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; + cgc->data_direction = CGC_DATA_NONE; + return cdo->generic_packet(cdi, cgc); +} + +static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, + void __user *arg, + struct packet_command *cgc) +{ + int ret; + dvd_struct *s; + int size = sizeof(dvd_struct); + + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + + s = kmalloc(size, GFP_KERNEL); + if (!s) + return -ENOMEM; + + cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); + if (copy_from_user(s, arg, size)) { + kfree(s); + return -EFAULT; + } + + ret = dvd_read_struct(cdi, s, cgc); + if (ret) + goto out; + + if (copy_to_user(arg, s, size)) + ret = -EFAULT; +out: + kfree(s); + return ret; +} + +static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi, + void __user *arg) +{ + int ret; + dvd_authinfo ai; + if (!CDROM_CAN(CDC_DVD)) + return -ENOSYS; + cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n"); + if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai))) + return -EFAULT; + ret = dvd_do_auth(cdi, &ai); + if (ret) + return ret; + if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai))) + return -EFAULT; + return 0; +} + +static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi, + void __user *arg) +{ + int ret; + long next = 0; + cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); + ret = cdrom_get_next_writable(cdi, &next); + if (ret) + return ret; + if (copy_to_user((long __user *)arg, &next, sizeof(next))) + return -EFAULT; + return 0; +} + +static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi, + void __user *arg) +{ + int ret; + long last = 0; + cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); + ret = cdrom_get_last_written(cdi, &last); + if (ret) + return ret; + if (copy_to_user((long __user *)arg, &last, sizeof(last))) + return -EFAULT; + return 0; +} + +static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + unsigned long arg) +{ + struct packet_command cgc; + void __user *userptr = (void __user *)arg; + + memset(&cgc, 0, sizeof(cgc)); + + /* build a unified command and queue it through + cdo->generic_packet() */ + switch (cmd) { + case CDROMREADRAW: + case CDROMREADMODE1: + case CDROMREADMODE2: + return mmc_ioctl_cdrom_read_data(cdi, userptr, &cgc, cmd); + case CDROMREADAUDIO: + return mmc_ioctl_cdrom_read_audio(cdi, userptr); + case CDROMSUBCHNL: + return mmc_ioctl_cdrom_subchannel(cdi, userptr); + case CDROMPLAYMSF: + return mmc_ioctl_cdrom_play_msf(cdi, userptr, &cgc); + case CDROMPLAYBLK: + return mmc_ioctl_cdrom_play_blk(cdi, userptr, &cgc); + case CDROMVOLCTRL: + case CDROMVOLREAD: + return mmc_ioctl_cdrom_volume(cdi, userptr, &cgc, cmd); + case CDROMSTART: + case CDROMSTOP: + return mmc_ioctl_cdrom_start_stop(cdi, &cgc, cmd); + case CDROMPAUSE: + case CDROMRESUME: + return mmc_ioctl_cdrom_pause_resume(cdi, &cgc, cmd); + case DVD_READ_STRUCT: + return mmc_ioctl_dvd_read_struct(cdi, userptr, &cgc); + case DVD_AUTH: + return mmc_ioctl_dvd_auth(cdi, userptr); + case CDROM_NEXT_WRITABLE: + return mmc_ioctl_cdrom_next_writable(cdi, userptr); + case CDROM_LAST_WRITTEN: + return mmc_ioctl_cdrom_last_written(cdi, userptr); + } + + return -ENOTTY; +} + /* * Just about every imaginable ioctl is supported in the Uniform layer * these days. @@ -2810,408 +3210,6 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, return -ENOSYS; } -/* - * Required when we need to use READ_10 to issue other than 2048 block - * reads - */ -static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) -{ - struct cdrom_device_ops *cdo = cdi->ops; - struct packet_command cgc; - struct modesel_head mh; - - memset(&mh, 0, sizeof(mh)); - mh.block_desc_length = 0x08; - mh.block_length_med = (size >> 8) & 0xff; - mh.block_length_lo = size & 0xff; - - memset(&cgc, 0, sizeof(cgc)); - cgc.cmd[0] = 0x15; - cgc.cmd[1] = 1 << 4; - cgc.cmd[4] = 12; - cgc.buflen = sizeof(mh); - cgc.buffer = (char *) &mh; - cgc.data_direction = CGC_DATA_WRITE; - mh.block_desc_length = 0x08; - mh.block_length_med = (size >> 8) & 0xff; - mh.block_length_lo = size & 0xff; - - return cdo->generic_packet(cdi, &cgc); -} - -static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc, - int cmd) -{ - struct request_sense sense; - struct cdrom_msf msf; - int blocksize = 0, format = 0, lba; - int ret; - - switch (cmd) { - case CDROMREADRAW: - blocksize = CD_FRAMESIZE_RAW; - break; - case CDROMREADMODE1: - blocksize = CD_FRAMESIZE; - format = 2; - break; - case CDROMREADMODE2: - blocksize = CD_FRAMESIZE_RAW0; - break; - } - if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) - return -EFAULT; - lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0); - /* FIXME: we need upper bound checking, too!! */ - if (lba < 0) - return -EINVAL; - - cgc->buffer = kzalloc(blocksize, GFP_KERNEL); - if (cgc->buffer == NULL) - return -ENOMEM; - - memset(&sense, 0, sizeof(sense)); - cgc->sense = &sense; - cgc->data_direction = CGC_DATA_READ; - ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize); - if (ret && sense.sense_key == 0x05 && - sense.asc == 0x20 && - sense.ascq == 0x00) { - /* - * SCSI-II devices are not required to support - * READ_CD, so let's try switching block size - */ - /* FIXME: switch back again... */ - ret = cdrom_switch_blocksize(cdi, blocksize); - if (ret) - goto out; - cgc->sense = NULL; - ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1); - ret |= cdrom_switch_blocksize(cdi, blocksize); - } - if (!ret && copy_to_user(arg, cgc->buffer, blocksize)) - ret = -EFAULT; -out: - kfree(cgc->buffer); - return ret; -} - -static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi, - void __user *arg) -{ - struct cdrom_read_audio ra; - int lba; - - if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg, - sizeof(ra))) - return -EFAULT; - - if (ra.addr_format == CDROM_MSF) - lba = msf_to_lba(ra.addr.msf.minute, - ra.addr.msf.second, - ra.addr.msf.frame); - else if (ra.addr_format == CDROM_LBA) - lba = ra.addr.lba; - else - return -EINVAL; - - /* FIXME: we need upper bound checking, too!! */ - if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) - return -EINVAL; - - return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes); -} - -static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi, - void __user *arg) -{ - int ret; - struct cdrom_subchnl q; - u_char requested, back; - if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q))) - return -EFAULT; - requested = q.cdsc_format; - if (!((requested == CDROM_MSF) || - (requested == CDROM_LBA))) - return -EINVAL; - q.cdsc_format = CDROM_MSF; - ret = cdrom_read_subchannel(cdi, &q, 0); - if (ret) - return ret; - back = q.cdsc_format; /* local copy */ - sanitize_format(&q.cdsc_absaddr, &back, requested); - sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); - if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q))) - return -EFAULT; - /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ - return 0; -} - -static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) -{ - struct cdrom_device_ops *cdo = cdi->ops; - struct cdrom_msf msf; - cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); - if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) - return -EFAULT; - cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF; - cgc->cmd[3] = msf.cdmsf_min0; - cgc->cmd[4] = msf.cdmsf_sec0; - cgc->cmd[5] = msf.cdmsf_frame0; - cgc->cmd[6] = msf.cdmsf_min1; - cgc->cmd[7] = msf.cdmsf_sec1; - cgc->cmd[8] = msf.cdmsf_frame1; - cgc->data_direction = CGC_DATA_NONE; - return cdo->generic_packet(cdi, cgc); -} - -static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) -{ - struct cdrom_device_ops *cdo = cdi->ops; - struct cdrom_blk blk; - cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); - if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) - return -EFAULT; - cgc->cmd[0] = GPCMD_PLAY_AUDIO_10; - cgc->cmd[2] = (blk.from >> 24) & 0xff; - cgc->cmd[3] = (blk.from >> 16) & 0xff; - cgc->cmd[4] = (blk.from >> 8) & 0xff; - cgc->cmd[5] = blk.from & 0xff; - cgc->cmd[7] = (blk.len >> 8) & 0xff; - cgc->cmd[8] = blk.len & 0xff; - cgc->data_direction = CGC_DATA_NONE; - return cdo->generic_packet(cdi, cgc); -} - -static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc, - unsigned int cmd) -{ - struct cdrom_volctrl volctrl; - unsigned char buffer[32]; - char mask[sizeof(buffer)]; - unsigned short offset; - int ret; - - cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n"); - - if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg, - sizeof(volctrl))) - return -EFAULT; - - cgc->buffer = buffer; - cgc->buflen = 24; - ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 0); - if (ret) - return ret; - - /* originally the code depended on buffer[1] to determine - how much data is available for transfer. buffer[1] is - unfortunately ambigious and the only reliable way seem - to be to simply skip over the block descriptor... */ - offset = 8 + be16_to_cpu(*(__be16 *)(buffer + 6)); - - if (offset + 16 > sizeof(buffer)) - return -E2BIG; - - if (offset + 16 > cgc->buflen) { - cgc->buflen = offset + 16; - ret = cdrom_mode_sense(cdi, cgc, - GPMODE_AUDIO_CTL_PAGE, 0); - if (ret) - return ret; - } - - /* sanity check */ - if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || - buffer[offset + 1] < 14) - return -EINVAL; - - /* now we have the current volume settings. if it was only - a CDROMVOLREAD, return these values */ - if (cmd == CDROMVOLREAD) { - volctrl.channel0 = buffer[offset+9]; - volctrl.channel1 = buffer[offset+11]; - volctrl.channel2 = buffer[offset+13]; - volctrl.channel3 = buffer[offset+15]; - if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl, - sizeof(volctrl))) - return -EFAULT; - return 0; - } - - /* get the volume mask */ - cgc->buffer = mask; - ret = cdrom_mode_sense(cdi, cgc, GPMODE_AUDIO_CTL_PAGE, 1); - if (ret) - return ret; - - buffer[offset + 9] = volctrl.channel0 & mask[offset + 9]; - buffer[offset + 11] = volctrl.channel1 & mask[offset + 11]; - buffer[offset + 13] = volctrl.channel2 & mask[offset + 13]; - buffer[offset + 15] = volctrl.channel3 & mask[offset + 15]; - - /* set volume */ - cgc->buffer = buffer + offset - 8; - memset(cgc->buffer, 0, 8); - return cdrom_mode_select(cdi, cgc); -} - -static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, - struct packet_command *cgc, - int cmd) -{ - struct cdrom_device_ops *cdo = cdi->ops; - cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); - cgc->cmd[0] = GPCMD_START_STOP_UNIT; - cgc->cmd[1] = 1; - cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0; - cgc->data_direction = CGC_DATA_NONE; - return cdo->generic_packet(cdi, cgc); -} - -static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, - struct packet_command *cgc, - int cmd) -{ - struct cdrom_device_ops *cdo = cdi->ops; - cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); - cgc->cmd[0] = GPCMD_PAUSE_RESUME; - cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; - cgc->data_direction = CGC_DATA_NONE; - return cdo->generic_packet(cdi, cgc); -} - -static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, - void __user *arg, - struct packet_command *cgc) -{ - int ret; - dvd_struct *s; - int size = sizeof(dvd_struct); - - if (!CDROM_CAN(CDC_DVD)) - return -ENOSYS; - - s = kmalloc(size, GFP_KERNEL); - if (!s) - return -ENOMEM; - - cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); - if (copy_from_user(s, arg, size)) { - kfree(s); - return -EFAULT; - } - - ret = dvd_read_struct(cdi, s, cgc); - if (ret) - goto out; - - if (copy_to_user(arg, s, size)) - ret = -EFAULT; -out: - kfree(s); - return ret; -} - -static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi, - void __user *arg) -{ - int ret; - dvd_authinfo ai; - if (!CDROM_CAN(CDC_DVD)) - return -ENOSYS; - cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n"); - if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai))) - return -EFAULT; - ret = dvd_do_auth(cdi, &ai); - if (ret) - return ret; - if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai))) - return -EFAULT; - return 0; -} - -static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi, - void __user *arg) -{ - int ret; - long next = 0; - cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); - ret = cdrom_get_next_writable(cdi, &next); - if (ret) - return ret; - if (copy_to_user((long __user *)arg, &next, sizeof(next))) - return -EFAULT; - return 0; -} - -static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi, - void __user *arg) -{ - int ret; - long last = 0; - cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); - ret = cdrom_get_last_written(cdi, &last); - if (ret) - return ret; - if (copy_to_user((long __user *)arg, &last, sizeof(last))) - return -EFAULT; - return 0; -} - -static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, - unsigned long arg) -{ - struct packet_command cgc; - void __user *userptr = (void __user *)arg; - - memset(&cgc, 0, sizeof(cgc)); - - /* build a unified command and queue it through - cdo->generic_packet() */ - switch (cmd) { - case CDROMREADRAW: - case CDROMREADMODE1: - case CDROMREADMODE2: - return mmc_ioctl_cdrom_read_data(cdi, userptr, &cgc, cmd); - case CDROMREADAUDIO: - return mmc_ioctl_cdrom_read_audio(cdi, userptr); - case CDROMSUBCHNL: - return mmc_ioctl_cdrom_subchannel(cdi, userptr); - case CDROMPLAYMSF: - return mmc_ioctl_cdrom_play_msf(cdi, userptr, &cgc); - case CDROMPLAYBLK: - return mmc_ioctl_cdrom_play_blk(cdi, userptr, &cgc); - case CDROMVOLCTRL: - case CDROMVOLREAD: - return mmc_ioctl_cdrom_volume(cdi, userptr, &cgc, cmd); - case CDROMSTART: - case CDROMSTOP: - return mmc_ioctl_cdrom_start_stop(cdi, &cgc, cmd); - case CDROMPAUSE: - case CDROMRESUME: - return mmc_ioctl_cdrom_pause_resume(cdi, &cgc, cmd); - case DVD_READ_STRUCT: - return mmc_ioctl_dvd_read_struct(cdi, userptr, &cgc); - case DVD_AUTH: - return mmc_ioctl_dvd_auth(cdi, userptr); - case CDROM_NEXT_WRITABLE: - return mmc_ioctl_cdrom_next_writable(cdi, userptr); - case CDROM_LAST_WRITTEN: - return mmc_ioctl_cdrom_last_written(cdi, userptr); - } - - return -ENOTTY; -} - static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, track_information *ti) {