patch-2.1.34 linux/drivers/cdrom/cdrom.c
Next file: linux/drivers/char/lp.c
Previous file: linux/drivers/cdrom/Makefile
Back to the patch index
Back to the overall index
- Lines: 934
- Date:
Mon Apr 14 09:38:37 1997
- Orig file:
v2.1.33/linux/drivers/cdrom/cdrom.c
- Orig date:
Fri Apr 4 08:52:18 1997
diff -u --recursive --new-file v2.1.33/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
@@ -1,9 +1,9 @@
/* cdrom.c. Common ioctl and open routines for various Linux cdrom drivers. -*- linux-c -*-
- Copyright (c) 1996 David van Leeuwen.
+ Copyright (c) 1996, 1997 David A. van Leeuwen.
The routines in the file should provide an interface between
software accessing cdroms and the various drivers that implement
- specific hardware devices.
+ specific hardware devices.
*/
@@ -21,9 +21,29 @@
#include <linux/cdrom.h>
#include <linux/ucdrom.h>
+/* define CHECKTYPE if you want to check for audio/data cdrom. You
+ must use cd player programs that respect the O_NONBLOCK option for
+ opening the cdrom-device for ioctl-commanding only. (See
+ Documentation/cdrom/cdrom-standard.tex). Patches for a number of cd
+ players (CDplayer-2.0, cd-console-1.1, workbone-2.3, cdtool-1.0,
+ cdp-0.33, cdplayer-0.4, cdthing-1.4, lyn0.8a, playcd-1.0) can be
+ found in directory
+
+ ftp://ftp.gwdg.de/pub/linux/cdrom/drivers/cm206/
+
+ A runtime configuration program "checktype.c" to allow for cdrom
+ medium type checking can be found at the same location.
+
+ In order to be able to get neat system errors like "No medium
+ found" or "Wrong medium type" upon attempting to mount/play an
+ empty slot, mount an audio disc or play a data disc, you need to
+ have a new libc.5.so. */
+#undef CHECKTYPE
+
#define FM_WRITE 0x2 /* file mode write bit */
-#define VERSION "Generic CD-ROM driver, v 1.21 1996/11/08 03:24:49"
+#define VERSION "$Id: cdrom.c,v 1.7 1997/02/27 22:14:26 david Exp $"
+#define REVISION "$Revision: 1.7 $"
/* Not-exported routines. */
static int cdrom_open(struct inode *ip, struct file *fp);
@@ -34,19 +54,19 @@
struct file_operations cdrom_fops =
{
- NULL, /* lseek */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir */
- NULL, /* poll */
- cdrom_ioctl, /* ioctl */
- NULL, /* mmap */
- cdrom_open, /* open */
- cdrom_release, /* release */
- NULL, /* fsync */
- NULL, /* fasync */
- cdrom_media_changed, /* media_change */
- NULL /* revalidate */
+ NULL, /* lseek */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ cdrom_ioctl, /* ioctl */
+ NULL, /* mmap */
+ cdrom_open, /* open */
+ cdrom_release, /* release */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ cdrom_media_changed, /* media_change */
+ NULL /* revalidate */
};
static struct cdrom_device_info *cdromdevs[MAX_BLKDEV] = {
@@ -62,68 +82,71 @@
#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
/* We don't use $name$ yet, but it could be used for the /proc
- * filesystem in the future, or for other purposes.
+ * filesystem in the future, or for other purposes.
*/
int register_cdrom(struct cdrom_device_info *cdi, char *name)
{
- int major = MAJOR (cdi->dev);
- struct cdrom_device_ops *cdo = cdi->ops;
- int *change_capability = (int *)&cdo->capability; /* hack */
-
- if (major < 0 || major >= MAX_BLKDEV)
- return -1;
- if (cdo->open == NULL || cdo->release == NULL)
- return -2;
- ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
- ENSURE(lock_door, CDC_LOCK);
- ENSURE(select_speed, CDC_SELECT_SPEED);
- ENSURE(select_disc, CDC_SELECT_DISC);
- ENSURE(get_last_session, CDC_MULTI_SESSION);
- ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
- ENSURE(media_changed, CDC_MEDIA_CHANGED);
- if (cdromdevs[major]==NULL) cdo->n_minors = 0;
- else cdo->n_minors++;
- cdi->next = cdromdevs[major];
- cdromdevs[major] = cdi;
- cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
- cdi->mc_flags = 0;
- return 0;
+ int major = MAJOR (cdi->dev);
+ struct cdrom_device_ops *cdo = cdi->ops;
+ int *change_capability = (int *)&cdo->capability; /* hack */
+
+ if (major < 0 || major >= MAX_BLKDEV)
+ return -1;
+ if (cdo->open == NULL || cdo->release == NULL)
+ return -2;
+ ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+ ENSURE(lock_door, CDC_LOCK);
+ ENSURE(select_speed, CDC_SELECT_SPEED);
+ ENSURE(select_disc, CDC_SELECT_DISC);
+ ENSURE(get_last_session, CDC_MULTI_SESSION);
+ ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
+ ENSURE(media_changed, CDC_MEDIA_CHANGED);
+ if (cdromdevs[major]==NULL) cdo->n_minors = 0;
+ else cdo->n_minors++;
+ cdi->next = cdromdevs[major];
+ cdromdevs[major] = cdi;
+ cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
+#ifdef CHECKTYPE
+ cdi->options |= CDO_CHECK_TYPE;
+#endif
+ cdi->mc_flags = 0;
+ return 0;
}
#undef ENSURE
int unregister_cdrom(struct cdrom_device_info *unreg)
{
- struct cdrom_device_info *cdi, *prev;
- int major = MAJOR (unreg->dev);
+ struct cdrom_device_info *cdi, *prev;
+ int major = MAJOR (unreg->dev);
- if (major < 0 || major >= MAX_BLKDEV)
- return -1;
+ if (major < 0 || major >= MAX_BLKDEV)
+ return -1;
- prev = NULL;
- cdi = cdromdevs[major];
- while (cdi != NULL && cdi->dev != unreg->dev) {
- prev = cdi;
- cdi = cdi->next;
- }
-
- if (cdi == NULL)
- return -2;
- if (prev)
- prev->next = cdi->next;
- else
- cdromdevs[major] = cdi->next;
- cdi->ops->n_minors--;
- return 0;
+ prev = NULL;
+ cdi = cdromdevs[major];
+ while (cdi != NULL && cdi->dev != unreg->dev) {
+ prev = cdi;
+ cdi = cdi->next;
+ }
+
+ if (cdi == NULL)
+ return -2;
+ if (prev)
+ prev->next = cdi->next;
+ else
+ cdromdevs[major] = cdi->next;
+ cdi->ops->n_minors--;
+ return 0;
}
static
struct cdrom_device_info *cdrom_find_device (kdev_t dev)
{
- struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)];
+ struct cdrom_device_info *cdi = cdromdevs[MAJOR (dev)];
- while (cdi != NULL && cdi->dev != dev)
- cdi = cdi->next;
- return cdi;
+ while (cdi != NULL && cdi->dev != dev)
+ cdi = cdi->next;
+ return cdi;
}
/* We use the open-option O_NONBLOCK to indicate that the
@@ -141,83 +164,88 @@
int cdrom_open(struct inode *ip, struct file *fp)
{
kdev_t dev = ip->i_rdev;
- struct cdrom_device_info *cdi = cdrom_find_device(dev);
- int purpose = !!(fp->f_flags & O_NONBLOCK);
- int ret=0;
-
- if (cdi == NULL)
- return -ENODEV;
- if (fp->f_mode & FM_WRITE)
- return -EROFS;
- purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
- if (cdi->use_count || purpose)
- ret = cdi->ops->open(cdi, purpose);
- else
- ret = open_for_data(cdi);
- if (!ret) cdi->use_count++;
- return ret;
+ struct cdrom_device_info *cdi = cdrom_find_device(dev);
+ int purpose = !!(fp->f_flags & O_NONBLOCK);
+ int ret=0;
+
+ if (cdi == NULL)
+ return -ENODEV;
+ if (fp->f_mode & FM_WRITE)
+ return -EROFS;
+ purpose = purpose || !(cdi->options & CDO_USE_FFLAGS);
+ if (cdi->use_count || purpose)
+ ret = cdi->ops->open(cdi, purpose);
+ else
+ ret = open_for_data(cdi);
+ if (!ret) cdi->use_count++;
+ return ret;
}
static
int open_for_data(struct cdrom_device_info * cdi)
{
- int ret;
- struct cdrom_device_ops *cdo = cdi->ops;
- if (cdo->drive_status != NULL) {
- int ds = cdo->drive_status(cdi, CDSL_CURRENT);
- if (ds == CDS_TRAY_OPEN) {
- /* can/may i close it? */
- if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
- cdi->options & CDO_AUTO_CLOSE) {
- if (cdo->tray_move(cdi,0))
- return -EIO;
- } else
- return -ENXIO; /* can't close: too bad */
- ds = cdo->drive_status(cdi, CDSL_CURRENT);
- if (ds == CDS_NO_DISC)
- return -ENXIO;
- }
- }
- if (cdo->disc_status != NULL) {
- int ds = cdo->disc_status(cdi);
- if (ds == CDS_NO_DISC)
- return -ENXIO;
- if (cdi->options & CDO_CHECK_TYPE &&
- ds != CDS_DATA_1)
- return -ENODATA;
- }
- /* all is well, we can open the device */
- ret = cdo->open(cdi, 0); /* open for data */
- if (cdo->capability & ~cdi->mask & CDC_LOCK &&
- cdi->options & CDO_LOCK)
- cdo->lock_door(cdi, 1);
- return ret;
+ int ret;
+ struct cdrom_device_ops *cdo = cdi->ops;
+ if (cdo->drive_status != NULL) {
+ int ds = cdo->drive_status(cdi, CDSL_CURRENT);
+ if (ds == CDS_TRAY_OPEN) {
+ /* can/may i close it? */
+ if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+ cdi->options & CDO_AUTO_CLOSE) {
+ if (cdo->tray_move(cdi,0))
+ return -EIO;
+ } else
+ return -ENOMEDIUM; /* can't close: too bad */
+ ds = cdo->drive_status(cdi, CDSL_CURRENT);
+ if (ds == CDS_NO_DISC)
+ return -ENOMEDIUM;
+ }
+ }
+ if (cdo->disc_status != NULL) {
+ int ds = cdo->disc_status(cdi);
+ if (ds == CDS_NO_DISC)
+ return -ENOMEDIUM;
+ if (cdi->options & CDO_CHECK_TYPE &&
+ ds != CDS_DATA_1)
+ return -EMEDIUMTYPE;
+ }
+ /* all is well, we can open the device */
+ ret = cdo->open(cdi, 0); /* open for data */
+ if (cdo->capability & ~cdi->mask & CDC_LOCK &&
+ cdi->options & CDO_LOCK)
+ cdo->lock_door(cdi, 1);
+ return ret;
}
/* Admittedly, the logic below could be performed in a nicer way. */
static
int cdrom_release(struct inode *ip, struct file *fp)
{
- kdev_t dev = ip->i_rdev;
- struct cdrom_device_info *cdi = cdrom_find_device (dev);
- struct cdrom_device_ops *cdo;
-
- if (cdi == NULL)
- return 0;
- cdo = cdi->ops;
- if (cdi->use_count == 1 && /* last process that closes dev*/
- cdi->options & CDO_LOCK &&
- cdo->capability & ~cdi->mask & CDC_LOCK)
- cdo->lock_door(cdi, 0);
- cdo->release(cdi);
- if (cdi->use_count > 0) cdi->use_count--;
- if (cdi->use_count == 0) { /* last process that closes dev*/
- sync_dev(dev);
- invalidate_buffers(dev);
- if (cdi->options & CDO_AUTO_EJECT &&
- cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
- cdo->tray_move(cdi, 1);
- }
+ kdev_t dev = ip->i_rdev;
+ struct cdrom_device_info *cdi = cdrom_find_device (dev);
+ struct cdrom_device_ops *cdo;
+ int opened_for_data;
+
+ if (cdi == NULL)
+ return 0;
+ opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
+ !(fp && fp->f_flags & O_NONBLOCK);
+ cdo = cdi->ops;
+ if (cdi->use_count == 1 && /* last process that closes dev*/
+ opened_for_data &&
+ cdi->options & CDO_LOCK &&
+ cdo->capability & ~cdi->mask & CDC_LOCK)
+ cdo->lock_door(cdi, 0);
+ cdo->release(cdi);
+ if (cdi->use_count > 0) cdi->use_count--;
+ if (cdi->use_count == 0) { /* last process that closes dev*/
+ sync_dev(dev);
+ invalidate_buffers(dev);
+ if (opened_for_data &&
+ cdi->options & CDO_AUTO_EJECT &&
+ cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+ cdo->tray_move(cdi, 1);
+ }
return 0;
}
@@ -230,37 +258,37 @@
static
int media_changed(struct cdrom_device_info *cdi, int queue)
{
- unsigned int mask = (1 << (queue & 1));
- int ret = !!(cdi->mc_flags & mask);
+ unsigned int mask = (1 << (queue & 1));
+ int ret = !!(cdi->mc_flags & mask);
- /* changed since last call? */
- if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
- cdi->mc_flags = 0x3; /* set bit on both queues */
- ret |= 1;
- }
- cdi->mc_flags &= ~mask; /* clear bit */
- return ret;
+ /* changed since last call? */
+ if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) {
+ cdi->mc_flags = 0x3; /* set bit on both queues */
+ ret |= 1;
+ }
+ cdi->mc_flags &= ~mask; /* clear bit */
+ return ret;
}
static
int cdrom_media_changed(kdev_t dev)
{
- struct cdrom_device_info *cdi = cdrom_find_device (dev);
- if (cdi == NULL)
- return -ENODEV;
- if (cdi->ops->media_changed == NULL)
- return -EINVAL;
- return media_changed(cdi, 0);
+ struct cdrom_device_info *cdi = cdrom_find_device (dev);
+ if (cdi == NULL)
+ return -ENODEV;
+ if (cdi->ops->media_changed == NULL)
+ return -EINVAL;
+ return media_changed(cdi, 0);
}
/* Requests to the low-level drivers will /always/ be done in the
- following format convention:
+ following format convention:
CDROM_LBA: all data-related requests.
- CDROM_MSF: all audio-related requests.
+ CDROM_MSF: all audio-related requests.
However, a low-level implementation is allowed to refuse this
- request, and return information in its own favorite format.
+ request, and return information in its own favorite format.
It doesn't make sense /at all/ to ask for a play_audio in LBA
format, or ask for multi-session info in MSF format. However, for
@@ -271,22 +299,22 @@
static
void sanitize_format(union cdrom_addr *addr,
- u_char * curr, u_char requested)
+ u_char * curr, u_char requested)
{
- if (*curr == requested)
- return; /* nothing to be done! */
- if (requested == CDROM_LBA) {
- addr->lba = (int) addr->msf.frame +
- 75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
- } else { /* CDROM_MSF */
- int lba = addr->lba;
- addr->msf.frame = lba % 75;
- lba /= 75;
- lba += 2;
- addr->msf.second = lba % 60;
- addr->msf.minute = lba / 60;
- }
- *curr = requested;
+ if (*curr == requested)
+ return; /* nothing to be done! */
+ if (requested == CDROM_LBA) {
+ addr->lba = (int) addr->msf.frame +
+ 75 * (addr->msf.second - 2 + 60 * addr->msf.minute);
+ } else { /* CDROM_MSF */
+ int lba = addr->lba;
+ addr->msf.frame = lba % 75;
+ lba /= 75;
+ lba += 2;
+ addr->msf.second = lba % 60;
+ addr->msf.minute = lba / 60;
+ }
+ *curr = requested;
}
/* All checking and format change makes this code really hard to read!
@@ -296,7 +324,7 @@
* shouldn't be in inner loops.
*/
#define GETARG(type, x) { \
- int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
+ int ret=verify_area(VERIFY_READ, (void *) arg, sizeof x); \
if (ret) return ret; \
copy_from_user(&x, (type *) arg, sizeof x); }
#define PUTARG(type, x) { \
@@ -318,238 +346,286 @@
* memory-verification is performed for these ioctls.
*/
static
+int check_for_audio_disc(struct cdrom_device_info * cdi,
+ struct cdrom_device_ops * cdo);
+
+static
int cdrom_ioctl(struct inode *ip, struct file *fp,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
- kdev_t dev = ip->i_rdev;
- struct cdrom_device_info *cdi = cdrom_find_device (dev);
- struct cdrom_device_ops *cdo;
-
- if (cdi == NULL)
- return -ENODEV;
- cdo = cdi->ops;
- /* the first few commands do not deal with audio capabilities, but
- only with routines in cdrom device operations. */
- switch (cmd) {
- /* maybe we should order cases after statistics of use? */
-
- case CDROMMULTISESSION:
- {
- struct cdrom_multisession ms_info;
- u_char requested_format;
- if (!(cdo->capability & CDC_MULTI_SESSION))
- return -EINVAL;
- GETARG(struct cdrom_multisession, ms_info);
- requested_format = ms_info.addr_format;
- ms_info.addr_format = CDROM_LBA;
- cdo->get_last_session(cdi, &ms_info);
- sanitize_format(&ms_info.addr, &ms_info.addr_format,
- requested_format);
- PUTARG(struct cdrom_multisession, ms_info);
- return 0;
- }
-
- case CDROMEJECT:
- if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) {
+ kdev_t dev = ip->i_rdev;
+ struct cdrom_device_info *cdi = cdrom_find_device (dev);
+ struct cdrom_device_ops *cdo;
+
+ if (cdi == NULL)
+ return -ENODEV;
+ cdo = cdi->ops;
+ /* the first few commands do not deal with audio capabilities, but
+ only with routines in cdrom device operations. */
+ switch (cmd) {
+ /* maybe we should order cases after statistics of use? */
+
+ case CDROMMULTISESSION:
+ {
+ struct cdrom_multisession ms_info;
+ u_char requested_format;
+ if (!(cdo->capability & CDC_MULTI_SESSION))
+ return -EINVAL;
+ GETARG(struct cdrom_multisession, ms_info);
+ requested_format = ms_info.addr_format;
+ ms_info.addr_format = CDROM_LBA;
+ cdo->get_last_session(cdi, &ms_info);
+ sanitize_format(&ms_info.addr, &ms_info.addr_format,
+ requested_format);
+ PUTARG(struct cdrom_multisession, ms_info);
+ return 0;
+ }
+
+ case CDROMEJECT:
+ if (cdo->capability & ~cdi->mask & CDC_OPEN_TRAY) {
if (cdi->use_count == 1) {
- if (cdo->capability & ~cdi->mask & CDC_LOCK)
+ if (cdo->capability & ~cdi->mask & CDC_LOCK)
cdo->lock_door(cdi, 0);
return cdo->tray_move(cdi, 1);
} else
return -EBUSY;
} else
- return -EINVAL;
-
- case CDROMCLOSETRAY:
- if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
+ return -EINVAL;
+
+ case CDROMCLOSETRAY:
+ if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
return cdo->tray_move(cdi, 0);
- else
- return -EINVAL;
-
- case CDROMEJECT_SW:
- cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
- if (arg)
- cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
- return 0;
-
- case CDROM_MEDIA_CHANGED:
- if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) {
- if (arg == CDSL_CURRENT)
- return media_changed(cdi, 1);
- else if ((int)arg < cdi->capacity &&
- cdo->capability & ~cdi->mask
- &CDC_SELECT_DISC)
- return cdo->media_changed (cdi, arg);
- else
- return -EINVAL;
- }
- else
- return -EINVAL;
-
- case CDROM_SET_OPTIONS:
- cdi->options |= (int) arg;
- return cdi->options;
-
- case CDROM_CLEAR_OPTIONS:
- cdi->options &= ~(int) arg;
- return cdi->options;
-
- case CDROM_SELECT_SPEED:
- if ((int)arg <= cdi->speed &&
- cdo->capability & ~cdi->mask & CDC_SELECT_SPEED)
- return cdo->select_speed(cdi, arg);
- else
- return -EINVAL;
-
- case CDROM_SELECT_DISC:
- if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
- return cdo->select_disc(cdi, arg);
- if ((int)arg < cdi->capacity &&
- cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+ else
+ return -EINVAL;
+
+ case CDROMEJECT_SW:
+ cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+ if (arg)
+ cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+ return 0;
+
+ case CDROM_MEDIA_CHANGED:
+ if (cdo->capability & ~cdi->mask & CDC_MEDIA_CHANGED) {
+ if (!(cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+ || arg == CDSL_CURRENT)
+ /* cannot select disc or select current disc */
+ return media_changed(cdi, 1);
+ if ((unsigned int)arg < cdi->capacity)
+ return cdo->media_changed (cdi, arg);
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ case CDROM_SET_OPTIONS:
+ cdi->options |= (int) arg;
+ return cdi->options;
+
+ case CDROM_CLEAR_OPTIONS:
+ cdi->options &= ~(int) arg;
+ return cdi->options;
+
+ case CDROM_SELECT_SPEED:
+ if ((int)arg <= cdi->speed &&
+ cdo->capability & ~cdi->mask & CDC_SELECT_SPEED)
+ return cdo->select_speed(cdi, arg);
+ else
+ return -EINVAL;
+
+ case CDROM_SELECT_DISC:
+ if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
return cdo->select_disc(cdi, arg);
- else
+ if ((int)arg < cdi->capacity &&
+ cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+ return cdo->select_disc(cdi, arg);
+ else
return -EINVAL;
-
+
/* 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;
- if (!(cdo->capability & CDC_MCN))
- return -EINVAL;
- if (!cdo->get_mcn(cdi, &mcn)) {
- PUTARG(struct cdrom_mcn, mcn);
- return 0;
- }
- return -EINVAL;
- }
-
- case CDROM_DRIVE_STATUS:
- if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
- return cdo->drive_status(cdi, arg);
- if (cdo->drive_status == NULL ||
- ! (cdo->capability & ~cdi->mask & CDC_SELECT_DISC
- && (int)arg < cdi->capacity))
- return -EINVAL;
- else
+ case CDROM_GET_MCN: {
+ struct cdrom_mcn mcn;
+ if (!(cdo->capability & CDC_MCN))
+ return -EINVAL;
+ if (!cdo->get_mcn(cdi, &mcn)) {
+ PUTARG(struct cdrom_mcn, mcn);
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ case CDROM_DRIVE_STATUS:
+ if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE))
+ return cdo->drive_status(cdi, arg);
+ if (cdo->drive_status == NULL ||
+ ((cdo->capability & ~cdi->mask & CDC_SELECT_DISC)
+ && (int)arg >= cdi->capacity))
+ return -EINVAL;
+ else
return cdo->drive_status(cdi, arg);
-
- case CDROM_DISC_STATUS:
+
+ case CDROM_DISC_STATUS:
if (cdo->disc_status == NULL)
return -EINVAL;
else
return cdo->disc_status(cdi);
- case CDROM_CHANGER_NSLOTS:
- return cdi->capacity;
+ case CDROM_CHANGER_NSLOTS:
+ return cdi->capacity;
/* The following is not implemented, because there are too many
* different data type. We could support /1/ raw mode, that is large
* enough to hold everything.
*/
-
+
#if 0
- case CDROMREADMODE1: {
- struct cdrom_msf msf;
- char buf[CD_FRAMESIZE];
- GETARG(struct cdrom_msf, msf);
- if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) {
- PUTARG(char *, buf);
- return 0;
- }
- return -EINVAL;
- }
+ case CDROMREADMODE1: {
+ struct cdrom_msf msf;
+ char buf[CD_FRAMESIZE];
+ GETARG(struct cdrom_msf, msf);
+ if (!cdo->read_audio(dev, cmd, &msf, &buf, cdi)) {
+ PUTARG(char *, buf);
+ return 0;
+ }
+ return -EINVAL;
+ }
#endif
} /* switch */
-
+
/* Now all the audio-ioctls follow, they are all routed through the
same call audio_ioctl(). */
- if (cdo->capability & CDC_PLAY_AUDIO)
+#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
+
+ if (cdo->capability & CDC_PLAY_AUDIO) {
+ int ret;
switch (cmd) {
- case CDROMSUBCHNL:
- {
- struct cdrom_subchnl q;
- u_char requested, back;
- GETARG(struct cdrom_subchnl, q);
- requested = q.cdsc_format;
- q.cdsc_format = CDROM_MSF;
- if (!cdo->audio_ioctl(cdi, cmd, &q)) {
- back = q.cdsc_format; /* local copy */
- sanitize_format(&q.cdsc_absaddr, &back,
- requested);
- sanitize_format(&q.cdsc_reladdr,
- &q.cdsc_format, requested);
- PUTARG(struct cdrom_subchnl, q);
- return 0;
- } else
- return -EINVAL;
- }
- case CDROMREADTOCHDR: {
- struct cdrom_tochdr header;
- GETARG(struct cdrom_tochdr, header);
- if (!cdo->audio_ioctl(cdi, cmd, &header)) {
- PUTARG(struct cdrom_tochdr, header);
- return 0;
- } else
- return -EINVAL;
- }
- case CDROMREADTOCENTRY: {
- struct cdrom_tocentry entry;
- u_char requested_format;
- GETARG(struct cdrom_tocentry, entry);
- requested_format = entry.cdte_format;
- /* make interface to low-level uniform */
- entry.cdte_format = CDROM_MSF;
- if (!(cdo->audio_ioctl(cdi, cmd, &entry))) {
- sanitize_format(&entry.cdte_addr,
- &entry.cdte_format, requested_format);
- PUTARG(struct cdrom_tocentry, entry);
- return 0;
- } else
- return -EINVAL;
- }
- case CDROMPLAYMSF: {
- struct cdrom_msf msf;
- GETARG(struct cdrom_msf, msf);
- return cdo->audio_ioctl(cdi, cmd, &msf);
- }
- case CDROMPLAYTRKIND: {
- struct cdrom_ti track_index;
- GETARG(struct cdrom_ti, track_index);
- return cdo->audio_ioctl(cdi, cmd, &track_index);
- }
- case CDROMVOLCTRL: {
- struct cdrom_volctrl volume;
- GETARG(struct cdrom_volctrl, volume);
- return cdo->audio_ioctl(cdi, cmd, &volume);
- }
- case CDROMVOLREAD: {
- struct cdrom_volctrl volume;
- if (!cdo->audio_ioctl(cdi, cmd, &volume)) {
- PUTARG(struct cdrom_volctrl, volume);
- return 0;
- }
- return -EINVAL;
- }
- case CDROMSTART:
- case CDROMSTOP:
- case CDROMPAUSE:
- case CDROMRESUME:
+ case CDROMSUBCHNL:
+ {
+ struct cdrom_subchnl q;
+ u_char requested, back;
+ GETARG(struct cdrom_subchnl, q);
+ requested = q.cdsc_format;
+ q.cdsc_format = CDROM_MSF;
+ if (!cdo->audio_ioctl(cdi, cmd, &q)) {
+ back = q.cdsc_format; /* local copy */
+ sanitize_format(&q.cdsc_absaddr, &back,
+ requested);
+ sanitize_format(&q.cdsc_reladdr,
+ &q.cdsc_format, requested);
+ PUTARG(struct cdrom_subchnl, q);
+ return 0;
+ } else
+ return -EINVAL;
+ }
+ case CDROMREADTOCHDR: {
+ struct cdrom_tochdr header;
+ GETARG(struct cdrom_tochdr, header);
+ CHECKAUDIO;
+ if (!cdo->audio_ioctl(cdi, cmd, &header)) {
+ PUTARG(struct cdrom_tochdr, header);
+ return 0;
+ } else
+ return -EINVAL;
+ }
+ case CDROMREADTOCENTRY: {
+ struct cdrom_tocentry entry;
+ u_char requested_format;
+ GETARG(struct cdrom_tocentry, entry);
+ requested_format = entry.cdte_format;
+ /* make interface to low-level uniform */
+ entry.cdte_format = CDROM_MSF;
+ if (!(cdo->audio_ioctl(cdi, cmd, &entry))) {
+ sanitize_format(&entry.cdte_addr,
+ &entry.cdte_format, requested_format);
+ PUTARG(struct cdrom_tocentry, entry);
+ return 0;
+ } else
+ return -EINVAL;
+ }
+ case CDROMPLAYMSF: {
+ struct cdrom_msf msf;
+ GETARG(struct cdrom_msf, msf);
+ CHECKAUDIO;
+ return cdo->audio_ioctl(cdi, cmd, &msf);
+ }
+ case CDROMPLAYTRKIND: {
+ struct cdrom_ti track_index;
+ GETARG(struct cdrom_ti, track_index);
+ CHECKAUDIO;
+ return cdo->audio_ioctl(cdi, cmd, &track_index);
+ }
+ case CDROMVOLCTRL: {
+ struct cdrom_volctrl volume;
+ GETARG(struct cdrom_volctrl, volume);
+ return cdo->audio_ioctl(cdi, cmd, &volume);
+ }
+ case CDROMVOLREAD: {
+ struct cdrom_volctrl volume;
+ if (!cdo->audio_ioctl(cdi, cmd, &volume)) {
+ PUTARG(struct cdrom_volctrl, volume);
+ return 0;
+ }
+ return -EINVAL;
+ }
+ case CDROMSTART:
+ CHECKAUDIO;
+ case CDROMSTOP:
+ case CDROMPAUSE:
+ case CDROMRESUME:
return cdo->audio_ioctl(cdi, cmd, NULL);
} /* switch */
+ }
if (cdo->dev_ioctl != NULL) /* device specific ioctls? */
return cdo->dev_ioctl(cdi, cmd, arg);
return -EINVAL;
}
+/* This code is similar to that in open_for_data. The routine is called
+ in case a audio play operation is requested. It doesn't make much sense
+ do do this on a data disc.
+ */
+int check_for_audio_disc(struct cdrom_device_info * cdi,
+ struct cdrom_device_ops * cdo)
+{
+ if (!(cdi->options & CDO_CHECK_TYPE))
+ return 0;
+ if (cdo->drive_status != NULL) {
+ int ds = cdo->drive_status(cdi, CDSL_CURRENT);
+ if (ds == CDS_TRAY_OPEN) {
+ /* can/may i close it? */
+ if (cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY &&
+ cdi->options & CDO_AUTO_CLOSE) {
+ if (cdo->tray_move(cdi,0))
+ return -EIO;
+ } else
+ return -ENOMEDIUM; /* can't close: too bad */
+ ds = cdo->drive_status(cdi, CDSL_CURRENT);
+ if (ds == CDS_NO_DISC)
+ return -ENOMEDIUM;
+ }
+ if (cdo->disc_status != NULL) {
+ ds = cdo->disc_status(cdi);
+ if (ds == CDS_NO_DISC)
+ return -ENOMEDIUM;
+ if (ds != CDS_AUDIO)
+ return -EMEDIUMTYPE;
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(register_cdrom);
+EXPORT_SYMBOL(unregister_cdrom);
+EXPORT_SYMBOL(cdrom_fops);
+
#ifdef MODULE
int init_module(void)
{
- printk(KERN_INFO "Module inserted: " VERSION "\n");
+ printk(KERN_INFO "Module cdrom: Generic CDROM driver " REVISION "\n");
return 0;
}
@@ -564,6 +640,6 @@
/*
* Local variables:
* comment-column: 40
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I. -I/usr/src/linux-obj/include -Wall -Wstrict-prototypes -O2 -m486 -c cdrom.c -o cdrom.o"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cdrom.o cdrom.c"
* End:
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov