-- Mt Rainier support
-- DVD-RAM write open fixes
+ Nov 5 2001, Aug 8 2002. Modified by Andy Polyakov
+ <appro@fy.chalmers.se> to support MMC-3 compliant DVD+RW units.
+
+ Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW
+ 2.4.x patch by Andy Polyakov <appro@fy.chalmers.se>
+
-------------------------------------------------------------------------*/
#define REVISION "Revision: 3.20"
static int check_media_type;
/* automatically restart mrw format */
static int mrw_format_restart = 1;
-MODULE_PARM(debug, "i");
-MODULE_PARM(autoclose, "i");
-MODULE_PARM(autoeject, "i");
-MODULE_PARM(lockdoor, "i");
-MODULE_PARM(check_media_type, "i");
-MODULE_PARM(mrw_format_restart, "i");
+module_param(debug, bool, 0);
+module_param(autoclose, bool, 0);
+module_param(autoeject, bool, 0);
+module_param(lockdoor, bool, 0);
+module_param(check_media_type, bool, 0);
+module_param(mrw_format_restart, bool, 0);
-static spinlock_t cdrom_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(cdrom_lock);
static const char *mrw_format_status[] = {
"not mrw",
/* These are used to simplify getting data in from and back to user land */
#define IOCTL_IN(arg, type, in) \
- if (copy_from_user(&(in), (type *) (arg), sizeof (in))) \
+ if (copy_from_user(&(in), (type __user *) (arg), sizeof (in))) \
return -EFAULT;
#define IOCTL_OUT(arg, type, out) \
- if (copy_to_user((type *) (arg), &(out), sizeof (out))) \
+ if (copy_to_user((type __user *) (arg), &(out), sizeof (out))) \
return -EFAULT;
/* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in
#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
ENSURE(get_mcn, CDC_MCN);
ENSURE(reset, CDC_RESET);
ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
- ENSURE(dev_ioctl, CDC_IOCTLS);
ENSURE(generic_packet, CDC_GENERIC_PACKET);
cdi->mc_flags = 0;
cdo->n_minors = 0;
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;
int cdrom_get_media_event(struct cdrom_device_info *cdi,
struct media_event_desc *med)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
unsigned char buffer[8];
struct event_header *eh = (struct event_header *) buffer;
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;
}
* the first prototypes used 0x2c as the page code for the mrw mode page,
* subsequently this was changed to 0x03. probe the one used by this drive
*/
-int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
+static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
char buffer[16];
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
return 1;
}
-int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write)
+static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct mrw_feature_desc *mfd;
unsigned char buffer[16];
int ret;
+ *write = 0;
+
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
return ret;
mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];
+ if (be16_to_cpu(mfd->feature_code) != CDF_MRW)
+ return 1;
*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_bgformat(struct cdrom_device_info *cdi, int cont)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
unsigned char buffer[12];
int ret;
static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.cmd[0] = GPCMD_CLOSE_TRACK;
static int cdrom_flush_cache(struct cdrom_device_info *cdi)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.cmd[0] = GPCMD_FLUSH_CACHE;
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);
}
- if (!ret)
+ if (!ret && cdi->media_written)
ret = cdrom_flush_cache(cdi);
return ret;
static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct mode_page_header *mph;
char buffer[16];
int ret, offset, size;
return 0;
}
-int cdrom_get_random_writable(struct cdrom_device_info *cdi,
+static int cdrom_get_random_writable(struct cdrom_device_info *cdi,
struct rwrt_feature_desc *rfd)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
char buffer[24];
- struct feature_header *fh;
int ret;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
return ret;
- fh = (struct feature_header *)&buffer[0];
- if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+
- sizeof(struct rwrt_feature_desc)))
- memcpy(rfd, &buffer[sizeof(struct feature_header)],
- sizeof (*rfd));
- else
- memset(rfd, 0, sizeof(*rfd));
-
+ memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd));
return 0;
}
-int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
+static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
char buffer[16];
- struct feature_header *fh;
__u16 *feature_code;
int ret;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
- cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */
- cgc.cmd[3] = CDF_HWDM; /* often 0x0024 */
- cgc.cmd[8] = sizeof(buffer); /* often 0x10 */
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+ cgc.cmd[3] = CDF_HWDM;
+ cgc.cmd[8] = sizeof(buffer);
cgc.quiet = 1;
if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
return ret;
- fh = (struct feature_header *)&buffer[0];
- ret = 1;
- if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+8)) {
- feature_code = (__u16 *)&buffer[sizeof(struct feature_header)];
- if (CDF_HWDM == be16_to_cpu(*feature_code))
- ret = 0;
- }
- return ret;
+ feature_code = (__u16 *) &buffer[sizeof(struct feature_header)];
+ if (be16_to_cpu(*feature_code) == CDF_HWDM)
+ return 0;
+
+ return 1;
}
-int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
+static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
{
struct rwrt_feature_desc rfd;
int ret;
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 mo_open_write(struct cdrom_device_info *cdi)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
char buffer[255];
int ret;
return ret;
}
+static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
+{
+ struct packet_command cgc;
+ char buffer[32];
+ int ret, mmc3_profile;
+
+ init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
+ cgc.cmd[1] = 0;
+ cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */
+ cgc.cmd[8] = sizeof(buffer); /* Allocation Length */
+ cgc.quiet = 1;
+
+ if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+ mmc3_profile = 0xffff;
+ else
+ mmc3_profile = (buffer[6] << 8) | buffer[7];
+
+ cdi->mmc3_profile = mmc3_profile;
+}
+
+static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
+{
+ switch (cdi->mmc3_profile) {
+ case 0x12: /* DVD-RAM */
+ case 0x1A: /* DVD+RW */
+ return 0;
+ default:
+ return 1;
+ }
+}
+
/*
* returns 0 for ok to open write, non-0 to disallow
*/
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);
+ else if (!cdrom_is_dvd_rw(cdi))
+ ret = 0;
return ret;
}
+static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi)
+{
+ struct packet_command cgc;
+
+ if (cdi->mmc3_profile != 0x1a) {
+ cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
+ return;
+ }
+
+ if (!cdi->media_written) {
+ cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
+ return;
+ }
+
+ printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n",
+ cdi->name);
+
+ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+ cgc.cmd[0] = GPCMD_FLUSH_CACHE;
+ cgc.timeout = 30*HZ;
+ cdi->ops->generic_packet(cdi, &cgc);
+
+ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+ cgc.cmd[0] = GPCMD_CLOSE_TRACK;
+ cgc.timeout = 3000*HZ;
+ cgc.quiet = 1;
+ cdi->ops->generic_packet(cdi, &cgc);
+
+ init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+ cgc.cmd[0] = GPCMD_CLOSE_TRACK;
+ cgc.cmd[2] = 2; /* Close session */
+ cgc.quiet = 1;
+ cgc.timeout = 3000*HZ;
+ cdi->ops->generic_packet(cdi, &cgc);
+
+ cdi->media_written = 0;
+}
+
static int cdrom_close_write(struct cdrom_device_info *cdi)
{
#if 0
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;
+ cdrom_mmc3_profile(cdi);
if (fp->f_mode & FMODE_WRITE) {
ret = -EROFS;
- if (!CDROM_CAN(CDC_RAM))
- goto err;
if (cdrom_open_write(cdi))
- goto err;
+ goto err_release;
+ if (!CDROM_CAN(CDC_RAM))
+ goto err_release;
+ ret = 0;
+ cdi->media_written = 0;
}
- ret = open_for_data(cdi);
}
if (ret)
not be mounting, but opening with O_NONBLOCK */
check_disk_change(ip->i_bdev);
return 0;
+err_release:
+ cdi->ops->release(cdi);
err:
cdi->use_count--;
return ret;
}
cdinfo(CD_OPEN, "the tray is now closed.\n");
}
+ /* the door should be closed now, check for the disc */
+ ret = cdo->drive_status(cdi, CDSL_CURRENT);
if (ret!=CDS_DISC_OK) {
ret = -ENOMEDIUM;
goto clean_up_and_return;
This ensures that the drive gets unlocked after a mount fails. This
is a goto to avoid bloating the driver with redundant code. */
clean_up_and_return:
- cdinfo(CD_WARNING, "open failed.\n");
+ cdinfo(CD_OPEN, "open failed.\n");
if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
cdo->lock_door(cdi, 0);
cdinfo(CD_OPEN, "door unlocked.\n");
cdi->use_count--;
if (cdi->use_count == 0)
cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
+ if (cdi->use_count == 0)
+ cdrom_dvd_rw_close_write(cdi);
if (cdi->use_count == 0 &&
(cdo->capability & CDC_LOCK) && !keeplocked) {
cdinfo(CD_CLOSE, "Unlocking door!\n");
static int cdrom_read_mech_status(struct cdrom_device_info *cdi,
struct cdrom_changer_info *buf)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
int length;
/* If SLOT < 0, unload the current slot. Otherwise, try to load SLOT. */
static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot)
{
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n");
if (cdi->sanyo_slot && slot < 0)
if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
cdi->mc_flags = 0x3; /* set bit on both queues */
ret |= 1;
+ cdi->media_written = 0;
}
cdi->mc_flags &= ~mask; /* clear bit */
return ret;
*curr = requested;
}
-void init_cdrom_command(struct cdrom_generic_command *cgc, void *buf, int len,
+void init_cdrom_command(struct packet_command *cgc, void *buf, int len,
int type)
{
- memset(cgc, 0, sizeof(struct cdrom_generic_command));
+ memset(cgc, 0, sizeof(struct packet_command));
if (buf)
memset(buf, 0, len);
cgc->buffer = (char *) buf;
#define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))
#define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
-static void setup_report_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
+static void setup_report_key(struct packet_command *cgc, unsigned agid, unsigned type)
{
cgc->cmd[0] = GPCMD_REPORT_KEY;
cgc->cmd[10] = type | (agid << 6);
cgc->data_direction = CGC_DATA_READ;
}
-static void setup_send_key(struct cdrom_generic_command *cgc, unsigned agid, unsigned type)
+static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned type)
{
cgc->cmd[0] = GPCMD_SEND_KEY;
cgc->cmd[10] = type | (agid << 6);
{
int ret;
u_char buf[20];
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
rpc_state_t rpc_state;
/* 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;
{
unsigned char buf[21], *base;
struct dvd_layer *layer;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
int ret, layer_num = s->physical.layer_num;
{
int ret;
u_char buf[8];
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
{
int ret, size;
u_char *buf;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
size = sizeof(s->disckey.value) + 4;
{
int ret;
u_char buf[4 + 188];
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = s->type;
- cgc.cmd[9] = cgc.buflen = 0xff;
+ cgc.cmd[9] = cgc.buflen & 0xff;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
{
int ret = 0, size;
u_char *buf;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct cdrom_device_ops *cdo = cdi->ops;
size = sizeof(s->manufact.value) + 4;
s->manufact.len = buf[0] << 8 | buf[1];
if (s->manufact.len < 0 || s->manufact.len > 2048) {
cdinfo(CD_WARNING, "Received invalid manufacture info length"
- " (%d)\n", s->bca.len);
+ " (%d)\n", s->manufact.len);
ret = -EIO;
} else {
memcpy(s->manufact.value, &buf[4], s->manufact.len);
}
int cdrom_mode_sense(struct cdrom_device_info *cdi,
- struct cdrom_generic_command *cgc,
+ struct packet_command *cgc,
int page_code, int page_control)
{
struct cdrom_device_ops *cdo = cdi->ops;
}
int cdrom_mode_select(struct cdrom_device_info *cdi,
- struct cdrom_generic_command *cgc)
+ struct packet_command *cgc)
{
struct cdrom_device_ops *cdo = cdi->ops;
struct cdrom_subchnl *subchnl, int mcn)
{
struct cdrom_device_ops *cdo = cdi->ops;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
char buffer[32];
int ret;
* Specific READ_10 interface
*/
static int cdrom_read_cd(struct cdrom_device_info *cdi,
- struct cdrom_generic_command *cgc, int lba,
+ struct packet_command *cgc, int lba,
int blocksize, int nblocks)
{
struct cdrom_device_ops *cdo = cdi->ops;
/* very generic interface for reading the various types of blocks */
static int cdrom_read_block(struct cdrom_device_info *cdi,
- struct cdrom_generic_command *cgc,
+ struct packet_command *cgc,
int lba, int nblocks, int format, int blksize)
{
struct cdrom_device_ops *cdo = cdi->ops;
static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,
int lba, int nframes)
{
- struct cdrom_generic_command cgc;
- int nr, ret;
+ struct packet_command cgc;
+ 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;
+ rq = blk_get_request(q, READ, GFP_KERNEL);
+ if (!rq)
+ return -ENOMEM;
+
+ cdi->last_sense = 0;
+
while (nframes) {
nr = nframes;
if (cdi->cdda_method == CDDA_BPC_SINGLE)
len = nr * CD_FRAMESIZE_RAW;
- rq = blk_rq_map_user(q, READ, ubuf, len);
- if (IS_ERR(rq))
- return PTR_ERR(rq);
+ ret = blk_rq_map_user(q, rq, ubuf, len);
+ if (ret)
+ break;
memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_READ_CD;
rq->timeout = 60 * HZ;
bio = rq->bio;
- if (blk_execute_rq(q, cdi->disk, rq)) {
+ if (rq->bio)
+ blk_queue_bounce(q, &rq->bio);
+
+ if (blk_execute_rq(q, cdi->disk, rq, 0)) {
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(bio, len))
ret = -EFAULT;
if (ret)
nframes -= nr;
lba += nr;
+ ubuf += len;
}
+ blk_put_request(rq);
return ret;
}
return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
}
-/* Just about every imaginable ioctl is supported in the Uniform layer
- * 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)
+static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
+ void __user *argp)
{
- struct cdrom_device_ops *cdo = cdi->ops;
+ struct cdrom_multisession ms_info;
+ u8 requested_format;
int ret;
- /* Try the generic SCSI command ioctl's first.. */
- ret = scsi_cmd_ioctl(ip->i_bdev->bd_disk, cmd, arg);
- if (ret != -ENOTTY)
+ cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
+
+ if (!(cdi->ops->capability & CDC_MULTI_SESSION))
+ return -ENOSYS;
+
+ if (copy_from_user(&ms_info, argp, sizeof(ms_info)))
+ return -EFAULT;
+
+ requested_format = ms_info.addr_format;
+ if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+ return -EINVAL;
+ ms_info.addr_format = CDROM_LBA;
+
+ ret = cdi->ops->get_last_session(cdi, &ms_info);
+ if (ret)
return ret;
- /* the first few commands do not deal with audio drive_info, but
- only with routines in cdrom device operations. */
- switch (cmd) {
- case CDROMMULTISESSION: {
- struct cdrom_multisession ms_info;
- u_char requested_format;
- cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
- if (!(cdo->capability & CDC_MULTI_SESSION))
- return -ENOSYS;
- IOCTL_IN(arg, struct cdrom_multisession, ms_info);
- requested_format = ms_info.addr_format;
- if (!((requested_format == CDROM_MSF) ||
- (requested_format == CDROM_LBA)))
- return -EINVAL;
- ms_info.addr_format = CDROM_LBA;
- if ((ret=cdo->get_last_session(cdi, &ms_info)))
+ sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format);
+
+ if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
+ return -EFAULT;
+
+ cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
+ return 0;
+}
+
+static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
+
+ if (!CDROM_CAN(CDC_OPEN_TRAY))
+ return -ENOSYS;
+ if (cdi->use_count != 1 || keeplocked)
+ return -EBUSY;
+ if (CDROM_CAN(CDC_LOCK)) {
+ int ret = cdi->ops->lock_door(cdi, 0);
+ if (ret)
return ret;
- sanitize_format(&ms_info.addr, &ms_info.addr_format,
- requested_format);
- IOCTL_OUT(arg, struct cdrom_multisession, ms_info);
- cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
- return 0;
- }
+ }
- case CDROMEJECT: {
- cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
- if (!CDROM_CAN(CDC_OPEN_TRAY))
- return -ENOSYS;
- if (cdi->use_count != 1 || keeplocked)
- return -EBUSY;
- if (CDROM_CAN(CDC_LOCK))
- if ((ret=cdo->lock_door(cdi, 0)))
- return ret;
+ return cdi->ops->tray_move(cdi, 1);
+}
- return cdo->tray_move(cdi, 1);
- }
+static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
- case CDROMCLOSETRAY: {
- cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
- if (!CDROM_CAN(CDC_CLOSE_TRAY))
- return -ENOSYS;
- return cdo->tray_move(cdi, 0);
- }
+ if (!CDROM_CAN(CDC_CLOSE_TRAY))
+ return -ENOSYS;
+ return cdi->ops->tray_move(cdi, 0);
+}
- case CDROMEJECT_SW: {
- cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
- if (!CDROM_CAN(CDC_OPEN_TRAY))
- return -ENOSYS;
- if (keeplocked)
- return -EBUSY;
- cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
- if (arg)
- cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
- return 0;
- }
+static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
- case CDROM_MEDIA_CHANGED: {
- struct cdrom_changer_info *info;
- int changed;
+ if (!CDROM_CAN(CDC_OPEN_TRAY))
+ return -ENOSYS;
+ if (keeplocked)
+ return -EBUSY;
- cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
- if (!CDROM_CAN(CDC_MEDIA_CHANGED))
- return -ENOSYS;
+ cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+ if (arg)
+ cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+ return 0;
+}
- /* cannot select disc or select current disc */
- if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
- return media_changed(cdi, 1);
+static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ struct cdrom_changer_info *info;
+ int ret;
- if ((unsigned int)arg >= cdi->capacity)
- return -EINVAL;
+ cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
+ if (!CDROM_CAN(CDC_MEDIA_CHANGED))
+ return -ENOSYS;
- if ((ret = cdrom_read_mech_status(cdi, info))) {
- kfree(info);
- return ret;
- }
+ /* cannot select disc or select current disc */
+ if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
+ return media_changed(cdi, 1);
- changed = info->slots[arg].change;
- kfree(info);
- return changed;
- }
+ if ((unsigned int)arg >= cdi->capacity)
+ return -EINVAL;
- case CDROM_SET_OPTIONS: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
- /* options need to be in sync with capability. too late for
- that, so we have to check each one separately... */
- switch (arg) {
- case CDO_USE_FFLAGS:
- case CDO_CHECK_TYPE:
- break;
- case CDO_LOCK:
- if (!CDROM_CAN(CDC_LOCK))
- return -ENOSYS;
- break;
- case 0:
- return cdi->options;
- /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
- default:
- if (!CDROM_CAN(arg))
- return -ENOSYS;
- }
- cdi->options |= (int) arg;
- return cdi->options;
- }
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
- case CDROM_CLEAR_OPTIONS: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
- cdi->options &= ~(int) arg;
- return cdi->options;
- }
+ ret = cdrom_read_mech_status(cdi, info);
+ if (!ret)
+ ret = info->slots[arg].change;
+ kfree(info);
+ return ret;
+}
- case CDROM_SELECT_SPEED: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
- if (!CDROM_CAN(CDC_SELECT_SPEED))
- return -ENOSYS;
- return cdo->select_speed(cdi, arg);
- }
+static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
- case CDROM_SELECT_DISC: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
- if (!CDROM_CAN(CDC_SELECT_DISC))
+ /*
+ * Options need to be in sync with capability.
+ * Too late for that, so we have to check each one separately.
+ */
+ switch (arg) {
+ case CDO_USE_FFLAGS:
+ case CDO_CHECK_TYPE:
+ break;
+ case CDO_LOCK:
+ if (!CDROM_CAN(CDC_LOCK))
+ return -ENOSYS;
+ break;
+ case 0:
+ return cdi->options;
+ /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
+ default:
+ if (!CDROM_CAN(arg))
return -ENOSYS;
+ }
+ cdi->options |= (int) arg;
+ return cdi->options;
+}
- if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE))
- if ((int)arg >= cdi->capacity)
- return -EINVAL;
-
- /* cdo->select_disc is a hook to allow a driver-specific
- * way of seleting disc. However, since there is no
- * equiv hook for cdrom_slot_status this may not
- * actually be useful...
- */
- if (cdo->select_disc != NULL)
- return cdo->select_disc(cdi, arg);
-
- /* no driver specific select_disc(), call our own */
- cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
- return cdrom_select_disc(cdi, arg);
- }
+static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
- case CDROMRESET: {
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
- if (!CDROM_CAN(CDC_RESET))
- return -ENOSYS;
- invalidate_bdev(ip->i_bdev, 0);
- return cdo->reset(cdi);
- }
+ cdi->options &= ~(int) arg;
+ return cdi->options;
+}
- case CDROM_LOCKDOOR: {
- cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
- if (!CDROM_CAN(CDC_LOCK))
- return -EDRIVE_CANT_DO_THIS;
- keeplocked = arg ? 1 : 0;
- /* don't unlock the door on multiple opens,but allow root
- * to do so */
- if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))
- return -EBUSY;
- return cdo->lock_door(cdi, arg);
- }
+static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
- case CDROM_DEBUG: {
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
- debug = arg ? 1 : 0;
- return debug;
- }
+ if (!CDROM_CAN(CDC_SELECT_SPEED))
+ return -ENOSYS;
+ return cdi->ops->select_speed(cdi, arg);
+}
- case CDROM_GET_CAPABILITY: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
- return (cdo->capability & ~cdi->mask);
- }
+static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
+
+ if (!CDROM_CAN(CDC_SELECT_DISC))
+ return -ENOSYS;
+
+ if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
+ if ((int)arg >= cdi->capacity)
+ return -EINVAL;
+ }
+
+ /*
+ * ->select_disc is a hook to allow a driver-specific way of
+ * seleting disc. However, since there is no equivalent hook for
+ * cdrom_slot_status this may not actually be useful...
+ */
+ if (cdi->ops->select_disc)
+ return cdi->ops->select_disc(cdi, arg);
+
+ cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
+ return cdrom_select_disc(cdi, arg);
+}
+
+static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
+ struct block_device *bdev)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!CDROM_CAN(CDC_RESET))
+ return -ENOSYS;
+ invalidate_bdev(bdev, 0);
+ return cdi->ops->reset(cdi);
+}
+
+static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
+
+ if (!CDROM_CAN(CDC_LOCK))
+ return -EDRIVE_CANT_DO_THIS;
+
+ keeplocked = arg ? 1 : 0;
+
+ /*
+ * Don't unlock the door on multiple opens by default, but allow
+ * root to do so.
+ */
+ if (cdi->use_count != 1 && !arg && !capable(CAP_SYS_ADMIN))
+ return -EBUSY;
+ return cdi->ops->lock_door(cdi, arg);
+}
+
+static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ debug = arg ? 1 : 0;
+ return debug;
+}
+
+static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
+ return (cdi->ops->capability & ~cdi->mask);
+}
-/* The following function is implemented, although very few audio
+/*
+ * The following function is implemented, although very few audio
* discs give Universal Product Code information, which should just be
* the Medium Catalog Number on the box. Note, that the way the code
* is written on the CD is /not/ uniform across all discs!
*/
- case CDROM_GET_MCN: {
- struct cdrom_mcn mcn;
- cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
- if (!(cdo->capability & CDC_MCN))
- return -ENOSYS;
- if ((ret=cdo->get_mcn(cdi, &mcn)))
- return ret;
- IOCTL_OUT(arg, struct cdrom_mcn, mcn);
- cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
- return 0;
- }
+static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_mcn mcn;
+ int ret;
- case CDROM_DRIVE_STATUS: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
- if (!(cdo->capability & CDC_DRIVE_STATUS))
- return -ENOSYS;
- if (!CDROM_CAN(CDC_SELECT_DISC))
- return cdo->drive_status(cdi, CDSL_CURRENT);
- if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
- return cdo->drive_status(cdi, CDSL_CURRENT);
- if (((int)arg >= cdi->capacity))
- return -EINVAL;
- return cdrom_slot_status(cdi, arg);
- }
+ cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
- /* Ok, this is where problems start. The current interface for the
- CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption
- that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly,
- while this is often the case, it is also very common for CDs to
- have some tracks with data, and some tracks with audio. Just
- because I feel like it, I declare the following to be the best
- way to cope. If the CD has ANY data tracks on it, it will be
- returned as a data CD. If it has any XA tracks, I will return
- it as that. Now I could simplify this interface by combining these
- returns with the above, but this more clearly demonstrates
- the problem with the current interface. Too bad this wasn't
- designed to use bitmasks... -Erik
-
- Well, now we have the option CDS_MIXED: a mixed-type CD.
- User level programmers might feel the ioctl is not very useful.
- ---david
- */
- case CDROM_DISC_STATUS: {
- tracktype tracks;
- cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
- cdrom_count_tracks(cdi, &tracks);
- if (tracks.error)
- return(tracks.error);
-
- /* Policy mode on */
- if (tracks.audio > 0) {
- if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0)
- return CDS_AUDIO;
- else
- return CDS_MIXED;
- }
- if (tracks.cdi > 0) return CDS_XA_2_2;
- if (tracks.xa > 0) return CDS_XA_2_1;
- if (tracks.data > 0) return CDS_DATA_1;
- /* Policy mode off */
+ if (!(cdi->ops->capability & CDC_MCN))
+ return -ENOSYS;
+ ret = cdi->ops->get_mcn(cdi, &mcn);
+ if (ret)
+ return ret;
- cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
- return CDS_NO_INFO;
- }
+ if (copy_to_user(argp, &mcn, sizeof(mcn)))
+ return -EFAULT;
+ cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
+ return 0;
+}
- case CDROM_CHANGER_NSLOTS: {
- cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
- return cdi->capacity;
- }
+static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
+ unsigned long arg)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
+
+ if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
+ return -ENOSYS;
+ if (!CDROM_CAN(CDC_SELECT_DISC) ||
+ (arg == CDSL_CURRENT || arg == CDSL_NONE))
+ return cdi->ops->drive_status(cdi, CDSL_CURRENT);
+ if (((int)arg >= cdi->capacity))
+ return -EINVAL;
+ return cdrom_slot_status(cdi, arg);
+}
+
+/*
+ * Ok, this is where problems start. The current interface for the
+ * CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption that
+ * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, while this
+ * is often the case, it is also very common for CDs to have some tracks
+ * with data, and some tracks with audio. Just because I feel like it,
+ * I declare the following to be the best way to cope. If the CD has ANY
+ * data tracks on it, it will be returned as a data CD. If it has any XA
+ * tracks, I will return it as that. Now I could simplify this interface
+ * by combining these returns with the above, but this more clearly
+ * demonstrates the problem with the current interface. Too bad this
+ * wasn't designed to use bitmasks... -Erik
+ *
+ * Well, now we have the option CDS_MIXED: a mixed-type CD.
+ * User level programmers might feel the ioctl is not very useful.
+ * ---david
+ */
+static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
+{
+ tracktype tracks;
+
+ cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
+
+ cdrom_count_tracks(cdi, &tracks);
+ if (tracks.error)
+ return tracks.error;
+
+ /* Policy mode on */
+ if (tracks.audio > 0) {
+ if (!tracks.data && !tracks.cdi && !tracks.xa)
+ return CDS_AUDIO;
+ else
+ return CDS_MIXED;
+ }
+
+ if (tracks.cdi > 0)
+ return CDS_XA_2_2;
+ if (tracks.xa > 0)
+ return CDS_XA_2_1;
+ if (tracks.data > 0)
+ return CDS_DATA_1;
+ /* Policy mode off */
+
+ cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
+ return CDS_NO_INFO;
+}
+
+static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
+{
+ cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
+ return cdi->capacity;
+}
+
+static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_subchnl q;
+ u8 requested, back;
+ int ret;
+
+ /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&q, argp, sizeof(q)))
+ return -EFAULT;
+
+ requested = q.cdsc_format;
+ if (requested != CDROM_MSF && requested != CDROM_LBA)
+ return -EINVAL;
+ q.cdsc_format = CDROM_MSF;
+
+ ret = cdi->ops->audio_ioctl(cdi, CDROMSUBCHNL, &q);
+ 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(argp, &q, sizeof(q)))
+ return -EFAULT;
+ /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+ return 0;
+}
+
+static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_tochdr header;
+ int ret;
+
+ /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&header, argp, sizeof(header)))
+ return -EFAULT;
+
+ ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(argp, &header, sizeof(header)))
+ return -EFAULT;
+ /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
+ return 0;
+}
+
+static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_tocentry entry;
+ u8 requested_format;
+ int ret;
+
+ /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&entry, argp, sizeof(entry)))
+ return -EFAULT;
+
+ requested_format = entry.cdte_format;
+ if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+ return -EINVAL;
+ /* make interface to low-level uniform */
+ entry.cdte_format = CDROM_MSF;
+ ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry);
+ if (ret)
+ return ret;
+ sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
+
+ if (copy_to_user(argp, &entry, sizeof(entry)))
+ return -EFAULT;
+ /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
+ return 0;
+}
+
+static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_msf msf;
+
+ cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&msf, argp, sizeof(msf)))
+ return -EFAULT;
+ return cdi->ops->audio_ioctl(cdi, CDROMPLAYMSF, &msf);
+}
+
+static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_ti ti;
+ int ret;
+
+ cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&ti, argp, sizeof(ti)))
+ return -EFAULT;
+
+ ret = check_for_audio_disc(cdi, cdi->ops);
+ if (ret)
+ return ret;
+ return cdi->ops->audio_ioctl(cdi, CDROMPLAYTRKIND, &ti);
+}
+static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_volctrl volume;
+
+ cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ if (copy_from_user(&volume, argp, sizeof(volume)))
+ return -EFAULT;
+ return cdi->ops->audio_ioctl(cdi, CDROMVOLCTRL, &volume);
+}
+
+static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
+ void __user *argp)
+{
+ struct cdrom_volctrl volume;
+ int ret;
+
+ cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+
+ ret = cdi->ops->audio_ioctl(cdi, CDROMVOLREAD, &volume);
+ if (ret)
+ return ret;
+
+ if (copy_to_user(argp, &volume, sizeof(volume)))
+ return -EFAULT;
+ return 0;
+}
+
+static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
+ unsigned int cmd)
+{
+ int ret;
+
+ cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
+
+ if (!CDROM_CAN(CDC_PLAY_AUDIO))
+ return -ENOSYS;
+ ret = check_for_audio_disc(cdi, cdi->ops);
+ if (ret)
+ return ret;
+ return cdi->ops->audio_ioctl(cdi, cmd, NULL);
+}
+
+/*
+ * Just about every imaginable ioctl is supported in the Uniform layer
+ * these days.
+ * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
+ */
+int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
+ struct inode *ip, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int ret;
+
+ /*
+ * Try the generic SCSI command ioctl's first.
+ */
+ ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, argp);
+ if (ret != -ENOTTY)
+ return ret;
+
+ switch (cmd) {
+ case CDROMMULTISESSION:
+ return cdrom_ioctl_multisession(cdi, argp);
+ case CDROMEJECT:
+ return cdrom_ioctl_eject(cdi);
+ case CDROMCLOSETRAY:
+ return cdrom_ioctl_closetray(cdi);
+ case CDROMEJECT_SW:
+ return cdrom_ioctl_eject_sw(cdi, arg);
+ case CDROM_MEDIA_CHANGED:
+ return cdrom_ioctl_media_changed(cdi, arg);
+ case CDROM_SET_OPTIONS:
+ return cdrom_ioctl_set_options(cdi, arg);
+ case CDROM_CLEAR_OPTIONS:
+ return cdrom_ioctl_clear_options(cdi, arg);
+ case CDROM_SELECT_SPEED:
+ return cdrom_ioctl_select_speed(cdi, arg);
+ case CDROM_SELECT_DISC:
+ return cdrom_ioctl_select_disc(cdi, arg);
+ case CDROMRESET:
+ return cdrom_ioctl_reset(cdi, ip->i_bdev);
+ case CDROM_LOCKDOOR:
+ return cdrom_ioctl_lock_door(cdi, arg);
+ case CDROM_DEBUG:
+ return cdrom_ioctl_debug(cdi, arg);
+ case CDROM_GET_CAPABILITY:
+ return cdrom_ioctl_get_capability(cdi);
+ case CDROM_GET_MCN:
+ return cdrom_ioctl_get_mcn(cdi, argp);
+ case CDROM_DRIVE_STATUS:
+ return cdrom_ioctl_drive_status(cdi, arg);
+ case CDROM_DISC_STATUS:
+ return cdrom_ioctl_disc_status(cdi);
+ case CDROM_CHANGER_NSLOTS:
+ return cdrom_ioctl_changer_nslots(cdi);
}
- /* use the ioctls that are implemented through the generic_packet()
- interface. this may look at bit funny, but if -ENOTTY is
- returned that particular ioctl is not implemented and we
- let it go through the device specific ones. */
+ /*
+ * Use the ioctls that are implemented through the generic_packet()
+ * interface. this may look at bit funny, but if -ENOTTY is
+ * returned that particular ioctl is not implemented and we
+ * let it go through the device specific ones.
+ */
if (CDROM_CAN(CDC_GENERIC_PACKET)) {
ret = mmc_ioctl(cdi, cmd, arg);
- if (ret != -ENOTTY) {
+ if (ret != -ENOTTY)
return ret;
- }
}
- /* note: most of the cdinfo() calls are commented out here,
- because they fill up the sys log when CD players poll
- the drive. */
+ /*
+ * Note: most of the cdinfo() calls are commented out here,
+ * because they fill up the sys log when CD players poll
+ * the drive.
+ */
switch (cmd) {
- case CDROMSUBCHNL: {
- struct cdrom_subchnl q;
- u_char requested, back;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
- IOCTL_IN(arg, struct cdrom_subchnl, q);
- requested = q.cdsc_format;
- if (!((requested == CDROM_MSF) ||
- (requested == CDROM_LBA)))
- return -EINVAL;
- q.cdsc_format = CDROM_MSF;
- if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))
- return ret;
- back = q.cdsc_format; /* local copy */
- sanitize_format(&q.cdsc_absaddr, &back, requested);
- sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
- IOCTL_OUT(arg, struct cdrom_subchnl, q);
- /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
- return 0;
- }
- case CDROMREADTOCHDR: {
- struct cdrom_tochdr header;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
- IOCTL_IN(arg, struct cdrom_tochdr, header);
- if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
- return ret;
- IOCTL_OUT(arg, struct cdrom_tochdr, header);
- /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
- return 0;
- }
- case CDROMREADTOCENTRY: {
- struct cdrom_tocentry entry;
- u_char requested_format;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
- IOCTL_IN(arg, struct cdrom_tocentry, entry);
- requested_format = entry.cdte_format;
- if (!((requested_format == CDROM_MSF) ||
- (requested_format == CDROM_LBA)))
- return -EINVAL;
- /* make interface to low-level uniform */
- entry.cdte_format = CDROM_MSF;
- if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
- return ret;
- sanitize_format(&entry.cdte_addr,
- &entry.cdte_format, requested_format);
- IOCTL_OUT(arg, struct cdrom_tocentry, entry);
- /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
- return 0;
- }
- case CDROMPLAYMSF: {
- struct cdrom_msf msf;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
- IOCTL_IN(arg, struct cdrom_msf, msf);
- return cdo->audio_ioctl(cdi, cmd, &msf);
- }
- case CDROMPLAYTRKIND: {
- struct cdrom_ti ti;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
- IOCTL_IN(arg, struct cdrom_ti, ti);
- CHECKAUDIO;
- return cdo->audio_ioctl(cdi, cmd, &ti);
- }
- case CDROMVOLCTRL: {
- struct cdrom_volctrl volume;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
- IOCTL_IN(arg, struct cdrom_volctrl, volume);
- return cdo->audio_ioctl(cdi, cmd, &volume);
- }
- case CDROMVOLREAD: {
- struct cdrom_volctrl volume;
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
- if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
- return ret;
- IOCTL_OUT(arg, struct cdrom_volctrl, volume);
- return 0;
- }
+ case CDROMSUBCHNL:
+ return cdrom_ioctl_get_subchnl(cdi, argp);
+ case CDROMREADTOCHDR:
+ return cdrom_ioctl_read_tochdr(cdi, argp);
+ case CDROMREADTOCENTRY:
+ return cdrom_ioctl_read_tocentry(cdi, argp);
+ case CDROMPLAYMSF:
+ return cdrom_ioctl_play_msf(cdi, argp);
+ case CDROMPLAYTRKIND:
+ return cdrom_ioctl_play_trkind(cdi, argp);
+ case CDROMVOLCTRL:
+ return cdrom_ioctl_volctrl(cdi, argp);
+ case CDROMVOLREAD:
+ return cdrom_ioctl_volread(cdi, argp);
case CDROMSTART:
case CDROMSTOP:
case CDROMPAUSE:
- case CDROMRESUME: {
- if (!CDROM_CAN(CDC_PLAY_AUDIO))
- return -ENOSYS;
- cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
- CHECKAUDIO;
- return cdo->audio_ioctl(cdi, cmd, NULL);
- }
- } /* switch */
+ case CDROMRESUME:
+ return cdrom_ioctl_audioctl(cdi, cmd);
+ }
- /* do the device specific ioctls */
- if (CDROM_CAN(CDC_IOCTLS))
- return cdo->dev_ioctl(cdi, cmd, arg);
-
return -ENOSYS;
}
static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
{
struct cdrom_device_ops *cdo = cdi->ops;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct modesel_head mh;
memset(&mh, 0, sizeof(mh));
unsigned long arg)
{
struct cdrom_device_ops *cdo = cdi->ops;
- struct cdrom_generic_command cgc;
+ struct packet_command cgc;
struct request_sense sense;
- char buffer[32];
+ unsigned char buffer[32];
int ret = 0;
memset(&cgc, 0, sizeof(cgc));
ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1);
ret |= cdrom_switch_blocksize(cdi, blocksize);
}
- if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize))
+ if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize))
ret = -EFAULT;
kfree(cgc.buffer);
return ret;
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);
}
if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL)
return -ENOMEM;
cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
- if (copy_from_user(s, (dvd_struct *)arg, size)) {
+ if (copy_from_user(s, (dvd_struct __user *)arg, size)) {
kfree(s);
return -EFAULT;
}
kfree(s);
return ret;
}
- if (copy_to_user((dvd_struct *)arg, s, size))
+ if (copy_to_user((dvd_struct __user *)arg, s, size))
ret = -EFAULT;
kfree(s);
return ret;
track_information *ti)
{
struct cdrom_device_ops *cdo = cdi->ops;
- struct cdrom_generic_command cgc;
- int ret;
+ struct packet_command cgc;
+ 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 */
static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di)
{
struct cdrom_device_ops *cdo = cdi->ops;
- struct cdrom_generic_command cgc;
- int ret;
+ struct packet_command cgc;
+ 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))) {
EXPORT_SYMBOL(cdrom_mode_sense);
EXPORT_SYMBOL(init_cdrom_command);
EXPORT_SYMBOL(cdrom_get_media_event);
-EXPORT_SYMBOL(cdrom_is_mrw);
-EXPORT_SYMBOL(cdrom_is_random_writable);
#ifdef CONFIG_SYSCTL
#define CDROM_STR_SIZE 1000
-struct cdrom_sysctl_settings {
+static struct cdrom_sysctl_settings {
char info[CDROM_STR_SIZE]; /* general info */
int autoclose; /* close tray upon mount, etc */
int autoeject; /* eject on umount */
int check; /* check media type */
} cdrom_sysctl_settings;
-int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
- void *buffer, size_t *lenp)
+static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp,
+ 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
procfs/sysctl yet. When they are, this will naturally disappear. For now
just update all drives. Later this will become the template on which
new registered drives will be based. */
-void cdrom_update_settings(void)
+static void cdrom_update_settings(void)
{
struct cdrom_device_info *cdi;
}
static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp,
- void *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) {
}
/* Place files in /proc/sys/dev/cdrom */
-ctl_table cdrom_table[] = {
+static ctl_table cdrom_table[] = {
{
.ctl_name = DEV_CDROM_INFO,
.procname = "info",
{ .ctl_name = 0 }
};
-ctl_table cdrom_cdrom_table[] = {
+static ctl_table cdrom_cdrom_table[] = {
{
.ctl_name = DEV_CDROM,
.procname = "cdrom",
};
/* Make sure that /proc/sys/dev is there */
-ctl_table cdrom_root_table[] = {
-#ifdef CONFIG_PROC_FS
+static ctl_table cdrom_root_table[] = {
{
.ctl_name = CTL_DEV,
.procname = "dev",
.mode = 0555,
.child = cdrom_cdrom_table,
},
-#endif /* CONFIG_PROC_FS */
{ .ctl_name = 0 }
};
static struct ctl_table_header *cdrom_sysctl_header;