/* linux/drivers/cdrom/cdrom.c Copyright (c) 1996, 1997 David A. van Leeuwen. Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org> Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk>
May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information.
Uniform CD-ROM driver for Linux. See Documentation/cdrom/cdrom-standard.rst for usage information.
The routines in the file provide a uniform interface between the software that uses CD-ROMs and the various low-level drivers that actually talk to the hardware. Suggestions are welcome. Patches that work are more welcome though. ;-)
Revision History ---------------------------------- 1.00 Date Unknown -- David van Leeuwen <david@tm.tno.nl> -- Initial version by David A. van Leeuwen. I don't have a detailed changelog for the 1.x series, David?
2.00 Dec 2, 1997 -- Erik Andersen <andersee@debian.org> -- New maintainer! As David A. van Leeuwen has been too busy to actively maintain and improve this driver, I am now carrying on the torch. If you have a problem with this driver, please feel free to contact me.
-- Added (rudimentary) sysctl interface. I realize this is really weak right now, and is _very_ badly implemented. It will be improved...
-- Modified CDROM_DISC_STATUS so that it is now incorporated into the Uniform CD-ROM driver via the cdrom_count_tracks function. The cdrom_count_tracks function helps resolve some of the false assumptions of the CDROM_DISC_STATUS ioctl, and is also used to check for the correct media type when mounting or playing audio from a CD.
-- Remove the calls to verify_area and only use the copy_from_user and copy_to_user stuff, since these calls now provide their own memory checking with the 2.1.x kernels.
-- Major update to return codes so that errors from low-level drivers are passed on through (thanks to Gerd Knorr for pointing out this problem).
-- Made it so if a function isn't implemented in a low-level driver, ENOSYS is now returned instead of EINVAL.
-- Simplified some complex logic so that the source code is easier to read.
-- Other stuff I probably forgot to mention (lots of changes).
2.01 to 2.11 Dec 1997-Jan 1998 -- TO-DO! Write changelogs for 2.01 to 2.12.
2.12 Jan 24, 1998 -- Erik Andersen <andersee@debian.org> -- Fixed a bug in the IOCTL_IN and IOCTL_OUT macros. It turns out that copy_*_user does not return EFAULT on error, but instead returns the number of bytes not copied. I was returning whatever non-zero stuff came back from the copy_*_user functions directly, which would result in strange errors.
2.13 July 17, 1998 -- Erik Andersen <andersee@debian.org> -- Fixed a bug in CDROM_SELECT_SPEED where you couldn't lower the speed of the drive. Thanks to Tobias Ringstr|m <tori@prosolvia.se> for pointing this out and providing a simple fix. -- Fixed the procfs-unload-module bug with the fill_inode procfs callback. thanks to Andrea Arcangeli -- Fixed it so that the /proc entry now also shows up when cdrom is compiled into the kernel. Before it only worked when loaded as a module.
2.14 August 17, 1998 -- Erik Andersen <andersee@debian.org> -- Fixed a bug in cdrom_media_changed and handling of reporting that the media had changed for devices that _don't_ implement media_changed. Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug. -- Made a few things more pedanticly correct.
2.50 Oct 19, 1998 - Jens Axboe <axboe@image.dk> -- New maintainers! Erik was too busy to continue the work on the driver, so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk> will do their best to follow in his footsteps 2.51 Dec 20, 1998 - Jens Axboe <axboe@image.dk> -- Check if drive is capable of doing what we ask before blindly changing cdi->options in various ioctl. -- Added version to proc entry. 2.52 Jan 16, 1999 - Jens Axboe <axboe@image.dk> -- Fixed an error in open_for_data where we would sometimes not return the correct error value. Thanks Huba Gaspar <huba@softcell.hu>. -- Fixed module usage count - usage was based on /proc/sys/dev instead of /proc/sys/dev/cdrom. This could lead to an oops when other modules had entries in dev. Feb 02 - real bug was in sysctl.c where dev would be removed even though it was used. cdrom.c just illuminated that bug. 2.53 Feb 22, 1999 - Jens Axboe <axboe@image.dk> -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has been "rewritten" because capabilities and options aren't in sync. They should be... -- Added CDROM_LOCKDOOR ioctl. Locks the door and keeps it that way. -- Added CDROM_RESET ioctl. -- Added CDROM_DEBUG ioctl. Enable debug messages on-the-fly. -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs from parsing /proc/sys/dev/cdrom/info. 2.54 Mar 15, 1999 - Jens Axboe <axboe@image.dk> -- Check capability mask from low level driver when counting tracks as per suggestion from Corey J. Scotts <cstotts@blue.weeg.uiowa.edu>. 2.55 Apr 25, 1999 - Jens Axboe <axboe@image.dk> -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of CDC_CLOSE_TRAY. -- proc info didn't mask against capabilities mask. 3.00 Aug 5, 1999 - Jens Axboe <axboe@image.dk> -- Unified audio ioctl handling across CD-ROM drivers. A lot of the code was duplicated before. Drives that support the generic packet interface are now being fed packets from here instead. -- First attempt at adding support for MMC2 commands - for DVD and CD-R(W) drives. Only the DVD parts are in now - the interface used is the same as for the audio ioctls. -- ioctl cleanups. if a drive couldn't play audio, it didn't get a change to perform device specific ioctls as well. -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities. -- Put in sysctl files for autoclose, autoeject, check_media, debug, and lock. -- /proc/sys/dev/cdrom/info has been updated to also contain info about CD-Rx and DVD capabilities. -- Now default to checking media type. -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for doing this anyway, with the generic_packet addition. 3.01 Aug 6, 1999 - Jens Axboe <axboe@image.dk> -- Fix up the sysctl handling so that the option flags get set correctly. -- Fix up ioctl handling so the device specific ones actually get called :). 3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk> -- Fixed volume control on SCSI drives (or others with longer audio page). -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath <andrewtv@usa.net> for telling me and for having defined the various DVD structures and ioctls in the first place! He designed the original DVD patches for ide-cd and while I rearranged and unified them, the interface is still the same. 3.03 Sep 1, 1999 - Jens Axboe <axboe@image.dk> -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only CDROMREADTOCENTRY and CDROMREADTOCHDR are left. -- Moved the CDROMREADxxx ioctls in here. -- Defined the cdrom_get_last_written and cdrom_get_next_block as ioctls and exported functions. -- Erik Andersen <andersen@xmission.com> modified all SCMD_ commands to now read GPCMD_ for the new generic packet interface. All low level drivers are updated as well. -- Various other cleanups.
3.04 Sep 12, 1999 - Jens Axboe <axboe@image.dk> -- Fixed a couple of possible memory leaks (if an operation failed and we didn't free the buffer before returning the error). -- Integrated Uniform CD Changer handling from Richard Sharman <rsharman@pobox.com>. -- Defined CD_DVD and CD_CHANGER log levels. -- Fixed the CDROMREADxxx ioctls. -- CDROMPLAYTRKIND uses the GPCMD_PLAY_AUDIO_MSF command - too few drives supported it. We lose the index part, however. -- Small modifications to accommodate opens of /dev/hdc1, required for ide-cd to handle multisession discs. -- Export cdrom_mode_sense and cdrom_mode_select. -- init_cdrom_command() for setting up a cgc command. 3.05 Oct 24, 1999 - Jens Axboe <axboe@image.dk> -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually impossible to send the drive data in a sensible way. -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and dvd_read_manufact. -- Added setup of write mode for packet writing. -- Fixed CDDA ripping with cdda2wav - accept much larger requests of number of frames and split the reads in blocks of 8.
3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk> -- Added support for changing the region of DVD drives. -- Added sense data to generic command.
3.07 Feb 2, 2000 - Jens Axboe <axboe@suse.de> -- Do same "read header length" trick in cdrom_get_disc_info() as we do in cdrom_get_track_info() -- some drive don't obey specs and fail if they can't supply the full Mt Fuji size table. -- Deleted stuff related to setting up write modes. It has a different home now. -- Clear header length in mode_select unconditionally. -- Removed the register_disk() that was added, not needed here.
3.08 May 1, 2000 - Jens Axboe <axboe@suse.de> -- Fix direction flag in setup_send_key and setup_report_key. This gave some SCSI adapters problems. -- Always return -EROFS for write opens -- Convert to module_init/module_exit style init and remove some of the #ifdef MODULE stuff -- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid, DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and dvd_do_auth passed uninitialized data to drive because init_cdrom_command did not clear a 0 sized buffer. 3.09 May 12, 2000 - Jens Axboe <axboe@suse.de> -- Fix Video-CD on SCSI drives that don't support READ_CD command. In that case switch block size and issue plain READ_10 again, then switch back.
3.10 Jun 10, 2000 - Jens Axboe <axboe@suse.de> -- Fix volume control on CD's - old SCSI-II drives now use their own code, as doing MODE6 stuff in here is really not my intention. -- Use READ_DISC_INFO for more reliable end-of-disc.
3.11 Jun 12, 2000 - Jens Axboe <axboe@suse.de> -- Fix bug in getting rpc phase 2 region info. -- Reinstate "correct" CDROMPLAYTRKIND
3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de> -- Use quiet bit on packet commands not known to work
3.20 Dec 17, 2003 - Jens Axboe <axboe@suse.de> -- Various fixes and lots of cleanups not listed :-) -- Locking fixes -- 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" #define VERSION "Id: cdrom.c 3.20 2003/12/17"
/* I use an error-log mask to give fine grain control over the type of
messages dumped to the system logs. The available masks include: */ #define CD_NOTHING 0x0 #define CD_WARNING 0x1 #define CD_REG_UNREG 0x2 #define CD_DO_IOCTL 0x4 #define CD_OPEN 0x8 #define CD_CLOSE 0x10 #define CD_COUNT_TRACKS 0x20 #define CD_CHANGER 0x40 #define CD_DVD 0x80
/* Define this to remove _all_ the debugging messages */ /* #define ERRLOGMASK CD_NOTHING */ #define ERRLOGMASK CD_WARNING /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */
#if (ERRLOGMASK != CD_NOTHING) #define cd_dbg(type, fmt, ...) \ do { \ if ((ERRLOGMASK & type) || debug == 1) \
pr_debug(fmt, ##__VA_ARGS__); \
} while (0) #else #define cd_dbg(type, fmt, ...) \ do { \ if (0 && (ERRLOGMASK & type) || debug == 1) \
pr_debug(fmt, ##__VA_ARGS__); \
} while (0) #endif
/* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in
a lot of places. This macro makes the code more clear. */ #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type))
/* * Another popular OS uses 7 seconds as the hard timeout for default * commands, so it is a good choice for us as well.
*/ #define CDROM_DEF_TIMEOUT (7 * HZ)
/* Not-exported routines. */
staticvoid cdrom_sysctl_register(void);
static LIST_HEAD(cdrom_list);
staticvoid signal_media_change(struct cdrom_device_info *cdi)
{
cdi->mc_flags = 0x3; /* set media changed bits, on both queues */
cdi->last_media_change_ms = ktime_to_ms(ktime_get());
}
/* set up command and get the disc info */
init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DISC_INFO;
cgc.cmd[8] = cgc.buflen = 2;
cgc.quiet = 1;
ret = cdo->generic_packet(cdi, &cgc); if (ret) return ret;
/* not all drives have the same disc_info length, so requeue * packet with the length the drive tells us it can supply
*/
buflen = be16_to_cpu(di->disc_information_length) + sizeof(di->disc_information_length);
if (buflen > sizeof(disc_information))
buflen = sizeof(disc_information);
cgc.cmd[8] = cgc.buflen = buflen;
ret = cdo->generic_packet(cdi, &cgc); if (ret) return ret;
/* return actual fill size */ return buflen;
}
/* 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 * change it here without gcc complaining at every line.
*/ #define ENSURE(cdo, call, bits) \ do { \ if (cdo->call == NULL) \
WARN_ON_ONCE((cdo)->capability & (bits)); \
} while (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
*/ staticint cdrom_mrw_probe_pc(struct cdrom_device_info *cdi)
{ struct packet_command cgc; char buffer[16];
staticint cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
{ struct rwrt_feature_desc rfd; int ret;
*write = 0;
if ((ret = cdrom_get_random_writable(cdi, &rfd))) return ret;
if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
*write = 1;
return 0;
}
staticint cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di; int ret;
ret = cdrom_get_disc_info(cdi, &di); if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) return -1;
return di.erasable;
}
/* * FIXME: check RO bit
*/ staticint cdrom_dvdram_open_write(struct cdrom_device_info *cdi)
{ int ret = cdrom_media_erasable(cdi);
/* * allow writable open if media info read worked and media is * erasable, _or_ if it fails since not all drives support it
*/ if (!ret) return 1;
return 0;
}
staticint cdrom_mrw_open_write(struct cdrom_device_info *cdi)
{
disc_information di; int ret;
/* * always reset to DMA lba space on open
*/ if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) {
pr_err("failed setting lba address space\n"); return 1;
}
ret = cdrom_get_disc_info(cdi, &di); if (ret < 0 || ret < offsetof(typeof(di),disc_type)) return 1;
if (!di.erasable) return 1;
/* * mrw_status * 0 - not MRW formatted * 1 - MRW bgformat started, but not running or complete * 2 - MRW bgformat in progress * 3 - MRW formatting complete
*/
ret = 0;
pr_info("open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); if (!di.mrw_status)
ret = 1; elseif (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE &&
mrw_format_restart)
ret = cdrom_mrw_bgformat(cdi, 1);
staticint cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
{ switch (cdi->mmc3_profile) { case 0x12: /* DVD-RAM */ case 0x1A: /* DVD+RW */ case 0x43: /* BD-RE */ return 0; default: return 1;
}
}
/* * returns 0 for ok to open write, non-0 to disallow
*/ staticint 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); elseif (CDROM_CAN(CDC_DVD_RAM))
ret = cdrom_dvdram_open_write(cdi); elseif (CDROM_CAN(CDC_RAM) &&
!CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE))
ret = cdrom_ram_open_write(cdi); elseif (CDROM_CAN(CDC_MO_DRIVE))
ret = mo_open_write(cdi); elseif (!cdrom_is_dvd_rw(cdi))
ret = 0;
/* badly broken, I know. Is due for a fixup anytime. */ staticvoid cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)
{ struct cdrom_tochdr header; struct cdrom_tocentry entry; int ret, i;
tracks->data = 0;
tracks->audio = 0;
tracks->cdi = 0;
tracks->xa = 0;
tracks->error = 0;
cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");
if (!CDROM_CAN(CDC_PLAY_AUDIO)) {
tracks->error = CDS_NO_INFO; return;
}
/* Grab the TOC header so we can see how many tracks there are */
ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); if (ret) { if (ret == -ENOMEDIUM)
tracks->error = CDS_NO_DISC; else
tracks->error = CDS_NO_INFO; return;
} /* check what type of tracks are on this disc */
entry.cdte_format = CDROM_MSF; for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) {
entry.cdte_track = i; if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) {
tracks->error = CDS_NO_INFO; return;
} if (entry.cdte_ctrl & CDROM_DATA_TRACK) { if (entry.cdte_format == 0x10)
tracks->cdi++; elseif (entry.cdte_format == 0x20)
tracks->xa++; else
tracks->data++;
} else {
tracks->audio++;
}
cd_dbg(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n",
i, entry.cdte_format, entry.cdte_ctrl);
}
cd_dbg(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n",
header.cdth_trk1, tracks->audio, tracks->data,
tracks->cdi, tracks->xa);
}
static int open_for_data(struct cdrom_device_info *cdi)
{ int ret; conststruct cdrom_device_ops *cdo = cdi->ops;
tracktype tracks;
cd_dbg(CD_OPEN, "entering open_for_data\n"); /* Check if the driver can report drive status. If it can, we
can do clever things. If it can't, well, we at least tried! */ if (cdo->drive_status != NULL) {
ret = cdo->drive_status(cdi, CDSL_CURRENT);
cd_dbg(CD_OPEN, "drive_status=%d\n", ret); if (ret == CDS_TRAY_OPEN) {
cd_dbg(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ if (CDROM_CAN(CDC_CLOSE_TRAY) &&
cdi->options & CDO_AUTO_CLOSE) {
cd_dbg(CD_OPEN, "trying to close the tray\n");
ret=cdo->tray_move(cdi,0); if (ret) {
cd_dbg(CD_OPEN, "bummer. tried to close the tray but failed.\n"); /* Ignore the error from the low level driver. We don't care why it couldn't close the tray. We only care that there is no disc in the drive,
since that is the _REAL_ problem here.*/
ret=-ENOMEDIUM; goto clean_up_and_return;
}
} else {
cd_dbg(CD_OPEN, "bummer. this drive can't close the tray.\n");
ret=-ENOMEDIUM; goto clean_up_and_return;
} /* Ok, the door should be closed now.. Check again */
ret = cdo->drive_status(cdi, CDSL_CURRENT); if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");
cd_dbg(CD_OPEN, "tray might not contain a medium\n");
ret=-ENOMEDIUM; goto clean_up_and_return;
}
cd_dbg(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;
}
}
cdrom_count_tracks(cdi, &tracks); if (tracks.error == CDS_NO_DISC) {
cd_dbg(CD_OPEN, "bummer. no disc.\n");
ret=-ENOMEDIUM; goto clean_up_and_return;
} /* CD-Players which don't use O_NONBLOCK, workman
* for example, need bit CDO_CHECK_TYPE cleared! */ if (tracks.data==0) { if (cdi->options & CDO_CHECK_TYPE) { /* give people a warning shot, now that CDO_CHECK_TYPE
is the default case! */
cd_dbg(CD_OPEN, "bummer. wrong media type.\n");
cd_dbg(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
(unsignedint)task_pid_nr(current));
ret=-EMEDIUMTYPE; goto clean_up_and_return;
} else {
cd_dbg(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set\n");
}
}
cd_dbg(CD_OPEN, "all seems well, opening the device\n");
/* all seems well, we can open the device */
ret = cdo->open(cdi, 0); /* open for data */
cd_dbg(CD_OPEN, "opening the device gave me %d\n", ret); /* After all this careful checking, we shouldn't have problems opening the device, but we don't want the device locked if
this somehow fails... */ if (ret) {
cd_dbg(CD_OPEN, "open device failed\n"); goto clean_up_and_return;
} if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) {
cdo->lock_door(cdi, 1);
cd_dbg(CD_OPEN, "door locked\n");
}
cd_dbg(CD_OPEN, "device opened successfully\n"); return ret;
/* Something failed. Try to unlock the drive, because some drivers (notably ide-cd) lock the drive after every command. This produced a nasty bug where after mount failed, the drive would remain locked! 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:
cd_dbg(CD_OPEN, "open failed\n"); if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
cdo->lock_door(cdi, 0);
cd_dbg(CD_OPEN, "door unlocked\n");
} return ret;
}
/* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. * * We hope that all cd-player programs will adopt this convention. It * is in their own interest: device control becomes a lot easier * this way.
*/ int cdrom_open(struct cdrom_device_info *cdi, blk_mode_t mode)
{ int ret;
cd_dbg(CD_OPEN, "entering cdrom_open\n");
/* if this was a O_NONBLOCK open and we should honor the flags,
* do a quick open without drive/disc integrity checks. */
cdi->use_count++; if ((mode & BLK_OPEN_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
ret = cdi->ops->open(cdi, 1);
} else {
ret = open_for_data(cdi); if (ret) goto err; if (CDROM_CAN(CDC_GENERIC_PACKET))
cdrom_mmc3_profile(cdi); if (mode & BLK_OPEN_WRITE) {
ret = -EROFS; if (cdrom_open_write(cdi)) goto err_release; if (!CDROM_CAN(CDC_RAM)) goto err_release;
ret = 0;
cdi->media_written = 0;
}
cdi->opened_for_data = true;
}
/* This code is similar to that in open_for_data. The routine is called whenever an audio play operation is requested.
*/ staticint check_for_audio_disc(struct cdrom_device_info *cdi, conststruct cdrom_device_ops *cdo)
{ int ret;
tracktype tracks;
cd_dbg(CD_OPEN, "entering check_for_audio_disc\n"); if (!(cdi->options & CDO_CHECK_TYPE)) return 0; if (cdo->drive_status != NULL) {
ret = cdo->drive_status(cdi, CDSL_CURRENT);
cd_dbg(CD_OPEN, "drive_status=%d\n", ret); if (ret == CDS_TRAY_OPEN) {
cd_dbg(CD_OPEN, "the tray is open...\n"); /* can/may i close it? */ if (CDROM_CAN(CDC_CLOSE_TRAY) &&
cdi->options & CDO_AUTO_CLOSE) {
cd_dbg(CD_OPEN, "trying to close the tray\n");
ret=cdo->tray_move(cdi,0); if (ret) {
cd_dbg(CD_OPEN, "bummer. tried to close tray but failed.\n"); /* Ignore the error from the low level driver. We don't care why it couldn't close the tray. We only care that there is no disc in the drive,
since that is the _REAL_ problem here.*/ return -ENOMEDIUM;
}
} else {
cd_dbg(CD_OPEN, "bummer. this driver can't close the tray.\n"); return -ENOMEDIUM;
} /* Ok, the door should be closed now.. Check again */
ret = cdo->drive_status(cdi, CDSL_CURRENT); if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n"); return -ENOMEDIUM;
} if (ret!=CDS_DISC_OK) {
cd_dbg(CD_OPEN, "bummer. disc isn't ready.\n"); return -EIO;
}
cd_dbg(CD_OPEN, "the tray is now closed\n");
}
}
cdrom_count_tracks(cdi, &tracks); if (tracks.error) return(tracks.error);
if (cdi->use_count == 0) {
cd_dbg(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n",
cdi->name);
cdrom_dvd_rw_close_write(cdi); if (CDROM_CAN(CDC_MRW_W))
cdrom_mrw_exit(cdi);
staticint cdrom_slot_status(struct cdrom_device_info *cdi, int slot)
{ struct cdrom_changer_info *info; int ret;
cd_dbg(CD_CHANGER, "entering cdrom_slot_status()\n"); if (cdi->sanyo_slot) return CDS_NO_INFO;
info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM;
if ((ret = cdrom_read_mech_status(cdi, info))) goto out_free;
if (info->slots[slot].disc_present)
ret = CDS_DISC_OK; else
ret = CDS_NO_DISC;
out_free:
kfree(info); return ret;
}
/* Return the number of slots for an ATAPI/SCSI cdrom, * return 1 if not a changer.
*/ int cdrom_number_of_slots(struct cdrom_device_info *cdi)
{ int nslots = 1; struct cdrom_changer_info *info;
cd_dbg(CD_CHANGER, "entering cdrom_number_of_slots()\n"); /* cdrom_read_mech_status requires a valid value for capacity: */
cdi->capacity = 0;
info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM;
if (cdrom_read_mech_status(cdi, info) == 0)
nslots = info->hdr.nslots;
/* If SLOT < 0, unload the current slot. Otherwise, try to load SLOT. */ staticint cdrom_load_unload(struct cdrom_device_info *cdi, int slot)
{ struct packet_command cgc;
/* The Sanyo 3 CD changer uses byte 7 of the GPCMD_TEST_UNIT_READY to command to switch CDs instead of
using the GPCMD_LOAD_UNLOAD opcode. */ if (cdi->sanyo_slot && -1 < slot) {
cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
cgc.cmd[7] = slot;
cgc.cmd[4] = cgc.cmd[8] = 0;
cdi->sanyo_slot = slot ? slot : 3;
}
return cdi->ops->generic_packet(cdi, &cgc);
}
staticint cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
{ struct cdrom_changer_info *info; int curslot; int ret;
cd_dbg(CD_CHANGER, "entering cdrom_select_disc()\n"); if (!CDROM_CAN(CDC_SELECT_DISC)) return -EDRIVE_CANT_DO_THIS;
if (cdi->ops->check_events)
cdi->ops->check_events(cdi, 0, slot);
if (slot == CDSL_NONE) {
signal_media_change(cdi); return cdrom_load_unload(cdi, -1);
}
info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM;
if ((ret = cdrom_read_mech_status(cdi, info))) {
kfree(info); return ret;
}
/* Specifying CDSL_CURRENT will attempt to load the currnet slot, which is useful if it had been previously unloaded. Whether it can or not, it returns the current slot. Similarly, if slot happens to be the current one, we still
try and load it. */ if (slot == CDSL_CURRENT)
slot = curslot;
/* set media changed bits on both queues */
signal_media_change(cdi); if ((ret = cdrom_load_unload(cdi, slot))) return ret;
return slot;
}
/* * As cdrom implements an extra ioctl consumer for media changed * event, it needs to buffer ->check_events() output, such that event * is not lost for both the usual VFS and ioctl paths. * cdi->{vfs|ioctl}_events are used to buffer pending events for each * path. * * XXX: Locking is non-existent. cdi->ops->check_events() can be * called in parallel and buffering fields are accessed without any * exclusion. The original media_changed code had the same problem. * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl * and remove this cruft altogether. It doesn't have much usefulness * at this point.
*/ staticvoid cdrom_update_events(struct cdrom_device_info *cdi, unsignedint clearing)
{ unsignedint events;
/* We want to make media_changed accessible to the user through an * ioctl. The main problem now is that we must double-buffer the * low-level implementation, to assure that the VFS and the user both * see a medium change once.
*/
static int media_changed(struct cdrom_device_info *cdi, int queue)
{ unsignedint mask = (1 << (queue & 1)); int ret = !!(cdi->mc_flags & mask); bool changed;
if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return ret;
/* changed since last call? */
BUG_ON(!queue); /* shouldn't be called from VFS path */
cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE);
changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE;
cdi->ioctl_events = 0;
if (changed) {
signal_media_change(cdi);
ret |= 1;
cdi->media_written = 0;
}
cdi->mc_flags &= ~mask; /* clear bit */ return ret;
}
/* Requests to the low-level drivers will /always/ be done in the following format convention:
CDROM_LBA: all data-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.
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 backward compatibility these format requests will be satisfied, but the requests to the low-level drivers will be sanitized in the more meaningful format indicated above.
*/
/* very generic interface for reading the various types of blocks */ staticint cdrom_read_block(struct cdrom_device_info *cdi, struct packet_command *cgc, int lba, int nblocks, int format, int blksize)
{ conststruct cdrom_device_ops *cdo = cdi->ops;
/* set the header info returned */ switch (blksize) { case CD_FRAMESIZE_RAW0 : cgc->cmd[9] = 0x58; break; case CD_FRAMESIZE_RAW1 : cgc->cmd[9] = 0x78; break; case CD_FRAMESIZE_RAW : cgc->cmd[9] = 0xf8; break; default : cgc->cmd[9] = 0x10;
}
return cdo->generic_packet(cdi, cgc);
}
staticint cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, int lba, int nframes)
{ struct packet_command cgc; int ret = 0; int nr;
cdi->last_sense = 0;
memset(&cgc, 0, sizeof(cgc));
/* * start with will ra.nframes size, back down if alloc fails
*/
nr = nframes; do {
cgc.buffer = kmalloc_array(nr, CD_FRAMESIZE_RAW, GFP_KERNEL); if (cgc.buffer) break;
nr >>= 1;
} while (nr);
if (!nr) return -ENOMEM;
cgc.data_direction = CGC_DATA_READ; while (nframes > 0) { if (nr > nframes)
nr = nframes;
ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); if (ret) break; if (copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) {
ret = -EFAULT; break;
}
ubuf += CD_FRAMESIZE_RAW * nr;
nframes -= nr;
lba += nr;
}
kfree(cgc.buffer); return ret;
}
staticint cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, int lba, int nframes)
{ int max_frames = (queue_max_sectors(cdi->disk->queue) << 9) /
CD_FRAMESIZE_RAW; int nr, ret = 0;
cdi->last_sense = 0;
while (nframes) { if (cdi->cdda_method == CDDA_BPC_SINGLE)
nr = 1; else
nr = min(nframes, max_frames);
ret = cdi->ops->read_cdda_bpc(cdi, ubuf, lba, nr,
&cdi->last_sense); if (ret) break;
staticint cdrom_read_cdda(struct cdrom_device_info *cdi, __u8 __user *ubuf, int lba, int nframes)
{ int ret;
if (cdi->cdda_method == CDDA_OLD) return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
retry: /* * for anything else than success and io error, we need to retry
*/
ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes); if (!ret || ret != -EIO) return ret;
/* * I've seen drives get sense 4/8/3 udma crc errors on multi * frame dma, so drop to single frame dma if we need to
*/ if (cdi->cdda_method == CDDA_BPC_FULL && nframes > 1) {
pr_info("dropping to single frame dma\n");
cdi->cdda_method = CDDA_BPC_SINGLE; goto retry;
}
/* * so we have an io error of some sort with multi frame dma. if the * condition wasn't a hardware error * problems, not for any error
*/ if (cdi->last_sense != 0x04 && cdi->last_sense != 0x0b) return ret;
pr_info("dropping to old style cdda (sense=%x)\n", cdi->last_sense);
cdi->cdda_method = CDDA_OLD; return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);
}
int cdrom_multisession(struct cdrom_device_info *cdi, struct cdrom_multisession *info)
{
u8 requested_format; int ret;
if (!(cdi->ops->capability & CDC_MULTI_SESSION)) return -ENOSYS;
if (copy_from_user(&info, argp, sizeof(info))) return -EFAULT;
ret = cdrom_multisession(cdi, &info); if (ret) return ret; if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT;
if (!CDROM_CAN(CDC_OPEN_TRAY)) return -ENOSYS; if (cdi->use_count != 1 || cdi->keeplocked) return -EBUSY; if (CDROM_CAN(CDC_LOCK)) { int ret = cdi->ops->lock_door(cdi, 0); if (ret) return ret;
}
if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS;
/* cannot select disc or select current disc */ if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) return media_changed(cdi, 1);
if (arg >= cdi->capacity) return -EINVAL;
/* Prevent arg from speculatively bypassing the length check */
arg = array_index_nospec(arg, cdi->capacity);
info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM;
ret = cdrom_read_mech_status(cdi, info); if (!ret)
ret = info->slots[arg].change;
kfree(info); return ret;
}
/* * Media change detection with timing information. * * arg is a pointer to a cdrom_timed_media_change_info struct. * arg->last_media_change may be set by calling code to signal * the timestamp (in ms) of the last known media change (by the caller). * Upon successful return, ioctl call will set arg->last_media_change * to the latest media change timestamp known by the kernel/driver * and set arg->has_changed to 1 if that timestamp is more recent * than the timestamp set by the caller.
*/ staticint cdrom_ioctl_timed_media_change(struct cdrom_device_info *cdi, unsignedlong arg)
{ int ret; struct cdrom_timed_media_change_info __user *info; struct cdrom_timed_media_change_info tmp_info;
if (!CDROM_CAN(CDC_MEDIA_CHANGED)) return -ENOSYS;
info = (struct cdrom_timed_media_change_info __user *)arg;
cd_dbg(CD_DO_IOCTL, "entering CDROM_TIMED_MEDIA_CHANGE\n");
ret = cdrom_ioctl_media_changed(cdi, CDSL_CURRENT); if (ret < 0) return ret;
if (copy_from_user(&tmp_info, info, sizeof(tmp_info)) != 0) return -EFAULT;
tmp_info.media_flags = 0; if (cdi->last_media_change_ms > tmp_info.last_media_change)
tmp_info.media_flags |= MEDIA_CHANGED_FLAG;
/* * 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;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.