#endif /* CONFIG_SYSCTL */
static struct cdrom_device_info *topCdromPtr;
+static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
+ struct packet_command *cgc)
+{
+ if (cgc->sense) {
+ cgc->sense->sense_key = 0x05;
+ cgc->sense->asc = 0x20;
+ cgc->sense->ascq = 0x00;
+ }
+
+ cgc->stat = -EIO;
+ return -EIO;
+}
+
/* This macro makes sure we don't have to check on cdrom_device_ops
* existence in the run-time routines below. Change_capability is a
* hack to have the capability flags defined const, while we can still
else
cdi->cdda_method = CDDA_OLD;
+ if (!cdo->generic_packet)
+ cdo->generic_packet = cdrom_dummy_generic_packet;
+
cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
spin_lock(&cdrom_lock);
cdi->next = topCdromPtr;
if (be16_to_cpu(eh->data_len) < sizeof(*med))
return 1;
+ if (eh->nea || eh->notification_class != 0x4)
+ return 1;
+
memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
return 0;
}
unsigned char buffer[16];
int ret;
+ *write = 0;
+
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];
*write = mfd->write;
- if ((ret = cdrom_mrw_probe_pc(cdi)))
+ if ((ret = cdrom_mrw_probe_pc(cdi))) {
+ *write = 0;
return ret;
+ }
return 0;
}
static int cdrom_mrw_exit(struct cdrom_device_info *cdi)
{
disc_information di;
- int ret = 0;
+ int ret;
- if (cdrom_get_disc_info(cdi, &di))
+ ret = cdrom_get_disc_info(cdi, &di);
+ if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type))
return 1;
+ ret = 0;
if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) {
- printk(KERN_INFO "cdrom: issuing MRW back ground format suspend\n");
+ printk(KERN_INFO "cdrom: issuing MRW back ground "
+ "format suspend\n");
ret = cdrom_mrw_bgformat_susp(cdi, 0);
}
static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di;
+ int ret;
- if (cdrom_get_disc_info(cdi, &di))
+ ret = cdrom_get_disc_info(cdi, &di);
+ if (ret < 0 || ret < offsetof(typeof(di), n_first_track))
return -1;
return di.erasable;
return 1;
}
- if (cdrom_get_disc_info(cdi, &di))
+ ret = cdrom_get_disc_info(cdi, &di);
+ if (ret < 0 || ret < offsetof(typeof(di),disc_type))
return 1;
if (!di.erasable)
* 3 - MRW formatting complete
*/
ret = 0;
- printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]);
+ printk(KERN_INFO "cdrom open: mrw_status '%s'\n",
+ mrw_format_status[di.mrw_status]);
if (!di.mrw_status)
ret = 1;
- else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart)
+ else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE &&
+ mrw_format_restart)
ret = cdrom_mrw_bgformat(cdi, 1);
return ret;
*/
static int cdrom_open_write(struct cdrom_device_info *cdi)
{
+ int mrw, mrw_write, ram_write;
int ret = 1;
+ mrw = 0;
+ if (!cdrom_is_mrw(cdi, &mrw_write))
+ mrw = 1;
+
+ if (CDROM_CAN(CDC_MO_DRIVE))
+ ram_write = 1;
+ else
+ (void) cdrom_is_random_writable(cdi, &ram_write);
+
+ if (mrw)
+ cdi->mask &= ~CDC_MRW;
+ else
+ cdi->mask |= CDC_MRW;
+
+ if (mrw_write)
+ cdi->mask &= ~CDC_MRW_W;
+ else
+ cdi->mask |= CDC_MRW_W;
+
+ if (ram_write)
+ cdi->mask &= ~CDC_RAM;
+ else
+ cdi->mask |= CDC_RAM;
+
if (CDROM_CAN(CDC_MRW_W))
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi);
else if (CDROM_CAN(CDC_RAM) &&
- !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW))
+ !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE))
ret = cdrom_ram_open_write(cdi);
else if (CDROM_CAN(CDC_MO_DRIVE))
ret = mo_open_write(cdi);
if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) {
ret = cdi->ops->open(cdi, 1);
} else {
+ ret = open_for_data(cdi);
+ if (ret)
+ goto err;
if (fp->f_mode & FMODE_WRITE) {
ret = -EROFS;
- if (!CDROM_CAN(CDC_RAM))
- goto err;
if (cdrom_open_write(cdi))
goto err;
+ if (!CDROM_CAN(CDC_RAM))
+ goto err;
+ ret = 0;
}
- ret = open_for_data(cdi);
}
if (ret)
/* LU data send */
case DVD_LU_SEND_AGID:
cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n");
+ cgc.quiet = 1;
setup_report_key(&cgc, ai->lsa.agid, 0);
if ((ret = cdo->generic_packet(cdi, &cgc)))
/* Post-auth key */
case DVD_LU_SEND_TITLE_KEY:
cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n");
+ cgc.quiet = 1;
setup_report_key(&cgc, ai->lstk.agid, 4);
cgc.cmd[5] = ai->lstk.lba;
cgc.cmd[4] = ai->lstk.lba >> 8;
int lba, int nframes)
{
struct packet_command cgc;
- int nr, ret;
+ int ret = 0;
+ int nr;
+
+ cdi->last_sense = 0;
memset(&cgc, 0, sizeof(cgc));
return -ENOMEM;
if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) {
- kfree(cgc.buffer);
- return -EFAULT;
+ ret = -EFAULT;
+ goto out;
}
cgc.data_direction = CGC_DATA_READ;
ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW);
if (ret)
break;
- __copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr);
+ if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) {
+ ret = -EFAULT;
+ break;
+ }
ubuf += CD_FRAMESIZE_RAW * nr;
nframes -= nr;
lba += nr;
}
+out:
kfree(cgc.buffer);
- return 0;
+ return ret;
}
static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
if (!q)
return -ENXIO;
+ cdi->last_sense = 0;
+
while (nframes) {
nr = nframes;
if (cdi->cdda_method == CDDA_BPC_SINGLE)
rq->timeout = 60 * HZ;
bio = rq->bio;
+ if (rq->bio)
+ blk_queue_bounce(q, &rq->bio);
+
if (blk_execute_rq(q, cdi->disk, rq)) {
struct request_sense *s = rq->sense;
ret = -EIO;
cdi->last_sense = s->sense_key;
}
- if (blk_rq_unmap_user(rq, ubuf, bio, len))
+ if (blk_rq_unmap_user(rq, bio, len))
ret = -EFAULT;
if (ret)
nframes -= nr;
lba += nr;
+ ubuf += len;
}
return ret;
* these days. ATAPI / SCSI specific code now mainly resides in
* mmc_ioct().
*/
-int cdrom_ioctl(struct cdrom_device_info *cdi, struct inode *ip,
- unsigned int cmd, unsigned long arg)
+int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
+ struct inode *ip, unsigned int cmd, unsigned long arg)
{
struct cdrom_device_ops *cdo = cdi->ops;
int ret;
/* Try the generic SCSI command ioctl's first.. */
- ret = scsi_cmd_ioctl(ip->i_bdev->bd_disk, cmd, (void __user *)arg);
+ ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg);
if (ret != -ENOTTY)
return ret;
struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc;
struct request_sense sense;
- char buffer[32];
+ unsigned char buffer[32];
int ret = 0;
memset(&cgc, 0, sizeof(cgc));
case CDROMVOLCTRL:
case CDROMVOLREAD: {
struct cdrom_volctrl volctrl;
- char mask[32];
+ char mask[sizeof(buffer)];
unsigned short offset;
+
cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0)))
return ret;
- /* some drives have longer pages, adjust and reread. */
- if (buffer[1] > cgc.buflen) {
- cgc.buflen = buffer[1] + 2;
- if ((ret = cdrom_mode_sense(cdi, &cgc,
- GPMODE_AUDIO_CTL_PAGE, 0)))
- 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(*(unsigned short *)(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;
}
-
- /* get the offset from the length of the page. length
- is measure from byte 2 an on, thus the 14. */
- offset = buffer[1] - 14;
+
+ /* 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 */
buffer[offset+15] = volctrl.channel3 & mask[offset+15];
/* set volume */
- cgc.buffer = buffer;
+ cgc.buffer = buffer + offset - 8;
+ memset(cgc.buffer, 0, 8);
return cdrom_mode_select(cdi, &cgc);
}
{
struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc;
- int ret;
+ int ret, buflen;
init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
- cgc.buflen = be16_to_cpu(ti->track_information_length) +
+ buflen = be16_to_cpu(ti->track_information_length) +
sizeof(ti->track_information_length);
- if (cgc.buflen > sizeof(track_information))
- cgc.buflen = sizeof(track_information);
+ if (buflen > sizeof(track_information))
+ buflen = sizeof(track_information);
- cgc.cmd[8] = cgc.buflen;
- return cdo->generic_packet(cdi, &cgc);
+ cgc.cmd[8] = cgc.buflen = buflen;
+ if ((ret = cdo->generic_packet(cdi, &cgc)))
+ return ret;
+
+ /* return actual fill size */
+ return buflen;
}
/* requires CD R/RW */
{
struct cdrom_device_ops *cdo = cdi->ops;
struct packet_command cgc;
- int ret;
+ int ret, buflen;
/* set up command and get the disc info */
init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
/* not all drives have the same disc_info length, so requeue
* packet with the length the drive tells us it can supply
*/
- cgc.buflen = be16_to_cpu(di->disc_information_length) +
+ buflen = be16_to_cpu(di->disc_information_length) +
sizeof(di->disc_information_length);
- if (cgc.buflen > sizeof(disc_information))
- cgc.buflen = sizeof(disc_information);
+ if (buflen > sizeof(disc_information))
+ buflen = sizeof(disc_information);
- cgc.cmd[8] = cgc.buflen;
- return cdo->generic_packet(cdi, &cgc);
+ cgc.cmd[8] = cgc.buflen = buflen;
+ if ((ret = cdo->generic_packet(cdi, &cgc)))
+ return ret;
+
+ /* return actual fill size */
+ return buflen;
}
/* return the last written block on the CD-R media. this is for the udf
disc_information di;
track_information ti;
__u32 last_track;
- int ret = -1;
+ int ret = -1, ti_size;
if (!CDROM_CAN(CDC_GENERIC_PACKET))
goto use_toc;
- if ((ret = cdrom_get_disc_info(cdi, &di)))
+ ret = cdrom_get_disc_info(cdi, &di);
+ if (ret < (int)(offsetof(typeof(di), last_track_lsb)
+ + sizeof(di.last_track_lsb)))
goto use_toc;
+ /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
last_track = (di.last_track_msb << 8) | di.last_track_lsb;
- if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
+ ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+ if (ti_size < (int)offsetof(typeof(ti), track_start))
goto use_toc;
/* if this track is blank, try the previous. */
if (ti.blank) {
- last_track--;
- if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
+ if (last_track==1)
goto use_toc;
+ last_track--;
+ ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
}
+ if (ti_size < (int)(offsetof(typeof(ti), track_size)
+ + sizeof(ti.track_size)))
+ goto use_toc;
+
/* if last recorded field is valid, return it. */
- if (ti.lra_v) {
+ if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address)
+ + sizeof(ti.last_rec_address))) {
*last_written = be32_to_cpu(ti.last_rec_address);
} else {
/* make it up instead */
/* this is where we end up if the drive either can't do a
GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if
- it fails. then we return the toc contents. */
+ it doesn't give enough information or fails. then we return
+ the toc contents. */
use_toc:
toc.cdte_format = CDROM_MSF;
toc.cdte_track = CDROM_LEADOUT;
- if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))
+ if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
return ret;
sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA);
*last_written = toc.cdte_addr.lba;
disc_information di;
track_information ti;
__u16 last_track;
- int ret = -1;
+ int ret, ti_size;
if (!CDROM_CAN(CDC_GENERIC_PACKET))
goto use_last_written;
- if ((ret = cdrom_get_disc_info(cdi, &di)))
+ ret = cdrom_get_disc_info(cdi, &di);
+ if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb)
+ + sizeof(di.last_track_lsb))
goto use_last_written;
+ /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
last_track = (di.last_track_msb << 8) | di.last_track_lsb;
- if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
+ ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+ if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start))
goto use_last_written;
/* if this track is blank, try the previous. */
if (ti.blank) {
+ if (last_track == 1)
+ goto use_last_written;
last_track--;
- if ((ret = cdrom_get_track_info(cdi, last_track, 1, &ti)))
+ ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
+ if (ti_size < 0)
goto use_last_written;
}
/* if next recordable address field is valid, use it. */
- if (ti.nwa_v)
+ if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable)
+ + sizeof(ti.next_writable)) {
*next_writable = be32_to_cpu(ti.next_writable);
- else
- goto use_last_written;
-
- return 0;
+ return 0;
+ }
use_last_written:
if ((ret = cdrom_get_last_written(cdi, next_writable))) {
} cdrom_sysctl_settings;
int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
- void __user *buffer, size_t *lenp)
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
int pos;
struct cdrom_device_info *cdi;
char *info = cdrom_sysctl_settings.info;
- if (!*lenp || (filp->f_pos && !write)) {
+ if (!*lenp || (*ppos && !write)) {
*lenp = 0;
return 0;
}
strcpy(info+pos,"\n\n");
- return proc_dostring(ctl, write, filp, buffer, lenp);
+ return proc_dostring(ctl, write, filp, buffer, lenp, ppos);
}
/* Unfortunately, per device settings are not implemented through
}
static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
- void __user *buffer, size_t *lenp)
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = ctl->data;
int val = *valp;
int ret;
- ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+ ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
if (write && *valp != val) {