cdrom: Move mmc_ioctls above cdrom_ioctl to remove unnecessary prototype
Neaten the spacing too. Signed-off-by: Joe Perches <joe@perches.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
Родитель
1237d1eecf
Коммит
2e9aa08a48
|
@ -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)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче