diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/cdrom/cdrom.c | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/cdrom/cdrom.c')
-rw-r--r-- | drivers/cdrom/cdrom.c | 787 |
1 files changed, 432 insertions, 355 deletions
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 9d5149655..1b55b5319 100644 --- a/drivers/cdrom/cdrom.c +++ b/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,32 +21,52 @@ #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); -static void cdrom_release(struct inode *ip, struct file *fp); +static int cdrom_release(struct inode *ip, struct file *fp); static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int cdrom_media_changed(kdev_t dev); struct file_operations cdrom_fops = { - NULL, /* lseek */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir */ - NULL, /* select */ - 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 @@ static struct cdrom_device_info *cdromdevs[MAX_BLKDEV] = { #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); - - 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; + struct cdrom_device_info *cdi, *prev; + int major = MAJOR (unreg->dev); + + 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; } 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,89 @@ static 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 -void cdrom_release(struct inode *ip, struct file *fp) +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; - 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; } /* We want to make media_changed accessible to the user through an @@ -229,37 +258,37 @@ void cdrom_release(struct inode *ip, struct file *fp) static int media_changed(struct cdrom_device_info *cdi, int queue) { - 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; + 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; } 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 @@ -270,22 +299,22 @@ int cdrom_media_changed(kdev_t dev) 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! @@ -295,7 +324,7 @@ void sanitize_format(union cdrom_addr *addr, * 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) { \ @@ -317,238 +346,286 @@ void sanitize_format(union cdrom_addr *addr, * 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); + if ((int)arg < cdi->capacity && + cdo->capability & ~cdi->mask & CDC_SELECT_DISC) return cdo->select_disc(cdi, arg); - else + 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); - - case CDROM_DISC_STATUS: + 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: 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; } @@ -563,6 +640,6 @@ void cleanup_module(void) /* * 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: */ |