1*1da177e4SLinus Torvalds /* linux/drivers/cdrom/cdrom.c. 2*1da177e4SLinus Torvalds Copyright (c) 1996, 1997 David A. van Leeuwen. 3*1da177e4SLinus Torvalds Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org> 4*1da177e4SLinus Torvalds Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk> 5*1da177e4SLinus Torvalds 6*1da177e4SLinus Torvalds May be copied or modified under the terms of the GNU General Public 7*1da177e4SLinus Torvalds License. See linux/COPYING for more information. 8*1da177e4SLinus Torvalds 9*1da177e4SLinus Torvalds Uniform CD-ROM driver for Linux. 10*1da177e4SLinus Torvalds See Documentation/cdrom/cdrom-standard.tex for usage information. 11*1da177e4SLinus Torvalds 12*1da177e4SLinus Torvalds The routines in the file provide a uniform interface between the 13*1da177e4SLinus Torvalds software that uses CD-ROMs and the various low-level drivers that 14*1da177e4SLinus Torvalds actually talk to the hardware. Suggestions are welcome. 15*1da177e4SLinus Torvalds Patches that work are more welcome though. ;-) 16*1da177e4SLinus Torvalds 17*1da177e4SLinus Torvalds To Do List: 18*1da177e4SLinus Torvalds ---------------------------------- 19*1da177e4SLinus Torvalds 20*1da177e4SLinus Torvalds -- Modify sysctl/proc interface. I plan on having one directory per 21*1da177e4SLinus Torvalds drive, with entries for outputing general drive information, and sysctl 22*1da177e4SLinus Torvalds based tunable parameters such as whether the tray should auto-close for 23*1da177e4SLinus Torvalds that drive. Suggestions (or patches) for this welcome! 24*1da177e4SLinus Torvalds 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds Revision History 27*1da177e4SLinus Torvalds ---------------------------------- 28*1da177e4SLinus Torvalds 1.00 Date Unknown -- David van Leeuwen <david@tm.tno.nl> 29*1da177e4SLinus Torvalds -- Initial version by David A. van Leeuwen. I don't have a detailed 30*1da177e4SLinus Torvalds changelog for the 1.x series, David? 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds 2.00 Dec 2, 1997 -- Erik Andersen <andersee@debian.org> 33*1da177e4SLinus Torvalds -- New maintainer! As David A. van Leeuwen has been too busy to activly 34*1da177e4SLinus Torvalds maintain and improve this driver, I am now carrying on the torch. If 35*1da177e4SLinus Torvalds you have a problem with this driver, please feel free to contact me. 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds -- Added (rudimentary) sysctl interface. I realize this is really weak 38*1da177e4SLinus Torvalds right now, and is _very_ badly implemented. It will be improved... 39*1da177e4SLinus Torvalds 40*1da177e4SLinus Torvalds -- Modified CDROM_DISC_STATUS so that it is now incorporated into 41*1da177e4SLinus Torvalds the Uniform CD-ROM driver via the cdrom_count_tracks function. 42*1da177e4SLinus Torvalds The cdrom_count_tracks function helps resolve some of the false 43*1da177e4SLinus Torvalds assumptions of the CDROM_DISC_STATUS ioctl, and is also used to check 44*1da177e4SLinus Torvalds for the correct media type when mounting or playing audio from a CD. 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds -- Remove the calls to verify_area and only use the copy_from_user and 47*1da177e4SLinus Torvalds copy_to_user stuff, since these calls now provide their own memory 48*1da177e4SLinus Torvalds checking with the 2.1.x kernels. 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds -- Major update to return codes so that errors from low-level drivers 51*1da177e4SLinus Torvalds are passed on through (thanks to Gerd Knorr for pointing out this 52*1da177e4SLinus Torvalds problem). 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds -- Made it so if a function isn't implemented in a low-level driver, 55*1da177e4SLinus Torvalds ENOSYS is now returned instead of EINVAL. 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds -- Simplified some complex logic so that the source code is easier to read. 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds -- Other stuff I probably forgot to mention (lots of changes). 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds 2.01 to 2.11 Dec 1997-Jan 1998 62*1da177e4SLinus Torvalds -- TO-DO! Write changelogs for 2.01 to 2.12. 63*1da177e4SLinus Torvalds 64*1da177e4SLinus Torvalds 2.12 Jan 24, 1998 -- Erik Andersen <andersee@debian.org> 65*1da177e4SLinus Torvalds -- Fixed a bug in the IOCTL_IN and IOCTL_OUT macros. It turns out that 66*1da177e4SLinus Torvalds copy_*_user does not return EFAULT on error, but instead returns the number 67*1da177e4SLinus Torvalds of bytes not copied. I was returning whatever non-zero stuff came back from 68*1da177e4SLinus Torvalds the copy_*_user functions directly, which would result in strange errors. 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds 2.13 July 17, 1998 -- Erik Andersen <andersee@debian.org> 71*1da177e4SLinus Torvalds -- Fixed a bug in CDROM_SELECT_SPEED where you couldn't lower the speed 72*1da177e4SLinus Torvalds of the drive. Thanks to Tobias Ringstr|m <tori@prosolvia.se> for pointing 73*1da177e4SLinus Torvalds this out and providing a simple fix. 74*1da177e4SLinus Torvalds -- Fixed the procfs-unload-module bug with the fill_inode procfs callback. 75*1da177e4SLinus Torvalds thanks to Andrea Arcangeli 76*1da177e4SLinus Torvalds -- Fixed it so that the /proc entry now also shows up when cdrom is 77*1da177e4SLinus Torvalds compiled into the kernel. Before it only worked when loaded as a module. 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds 2.14 August 17, 1998 -- Erik Andersen <andersee@debian.org> 80*1da177e4SLinus Torvalds -- Fixed a bug in cdrom_media_changed and handling of reporting that 81*1da177e4SLinus Torvalds the media had changed for devices that _don't_ implement media_changed. 82*1da177e4SLinus Torvalds Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug. 83*1da177e4SLinus Torvalds -- Made a few things more pedanticly correct. 84*1da177e4SLinus Torvalds 85*1da177e4SLinus Torvalds 2.50 Oct 19, 1998 - Jens Axboe <axboe@image.dk> 86*1da177e4SLinus Torvalds -- New maintainers! Erik was too busy to continue the work on the driver, 87*1da177e4SLinus Torvalds so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk> 88*1da177e4SLinus Torvalds will do their best to follow in his footsteps 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds 2.51 Dec 20, 1998 - Jens Axboe <axboe@image.dk> 91*1da177e4SLinus Torvalds -- Check if drive is capable of doing what we ask before blindly changing 92*1da177e4SLinus Torvalds cdi->options in various ioctl. 93*1da177e4SLinus Torvalds -- Added version to proc entry. 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds 2.52 Jan 16, 1999 - Jens Axboe <axboe@image.dk> 96*1da177e4SLinus Torvalds -- Fixed an error in open_for_data where we would sometimes not return 97*1da177e4SLinus Torvalds the correct error value. Thanks Huba Gaspar <huba@softcell.hu>. 98*1da177e4SLinus Torvalds -- Fixed module usage count - usage was based on /proc/sys/dev 99*1da177e4SLinus Torvalds instead of /proc/sys/dev/cdrom. This could lead to an oops when other 100*1da177e4SLinus Torvalds modules had entries in dev. Feb 02 - real bug was in sysctl.c where 101*1da177e4SLinus Torvalds dev would be removed even though it was used. cdrom.c just illuminated 102*1da177e4SLinus Torvalds that bug. 103*1da177e4SLinus Torvalds 104*1da177e4SLinus Torvalds 2.53 Feb 22, 1999 - Jens Axboe <axboe@image.dk> 105*1da177e4SLinus Torvalds -- Fixup of several ioctl calls, in particular CDROM_SET_OPTIONS has 106*1da177e4SLinus Torvalds been "rewritten" because capabilities and options aren't in sync. They 107*1da177e4SLinus Torvalds should be... 108*1da177e4SLinus Torvalds -- Added CDROM_LOCKDOOR ioctl. Locks the door and keeps it that way. 109*1da177e4SLinus Torvalds -- Added CDROM_RESET ioctl. 110*1da177e4SLinus Torvalds -- Added CDROM_DEBUG ioctl. Enable debug messages on-the-fly. 111*1da177e4SLinus Torvalds -- Added CDROM_GET_CAPABILITY ioctl. This relieves userspace programs 112*1da177e4SLinus Torvalds from parsing /proc/sys/dev/cdrom/info. 113*1da177e4SLinus Torvalds 114*1da177e4SLinus Torvalds 2.54 Mar 15, 1999 - Jens Axboe <axboe@image.dk> 115*1da177e4SLinus Torvalds -- Check capability mask from low level driver when counting tracks as 116*1da177e4SLinus Torvalds per suggestion from Corey J. Scotts <cstotts@blue.weeg.uiowa.edu>. 117*1da177e4SLinus Torvalds 118*1da177e4SLinus Torvalds 2.55 Apr 25, 1999 - Jens Axboe <axboe@image.dk> 119*1da177e4SLinus Torvalds -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of 120*1da177e4SLinus Torvalds CDC_CLOSE_TRAY. 121*1da177e4SLinus Torvalds -- proc info didn't mask against capabilities mask. 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds 3.00 Aug 5, 1999 - Jens Axboe <axboe@image.dk> 124*1da177e4SLinus Torvalds -- Unified audio ioctl handling across CD-ROM drivers. A lot of the 125*1da177e4SLinus Torvalds code was duplicated before. Drives that support the generic packet 126*1da177e4SLinus Torvalds interface are now being fed packets from here instead. 127*1da177e4SLinus Torvalds -- First attempt at adding support for MMC2 commands - for DVD and 128*1da177e4SLinus Torvalds CD-R(W) drives. Only the DVD parts are in now - the interface used is 129*1da177e4SLinus Torvalds the same as for the audio ioctls. 130*1da177e4SLinus Torvalds -- ioctl cleanups. if a drive couldn't play audio, it didn't get 131*1da177e4SLinus Torvalds a change to perform device specific ioctls as well. 132*1da177e4SLinus Torvalds -- Defined CDROM_CAN(CDC_XXX) for checking the capabilities. 133*1da177e4SLinus Torvalds -- Put in sysctl files for autoclose, autoeject, check_media, debug, 134*1da177e4SLinus Torvalds and lock. 135*1da177e4SLinus Torvalds -- /proc/sys/dev/cdrom/info has been updated to also contain info about 136*1da177e4SLinus Torvalds CD-Rx and DVD capabilities. 137*1da177e4SLinus Torvalds -- Now default to checking media type. 138*1da177e4SLinus Torvalds -- CDROM_SEND_PACKET ioctl added. The infrastructure was in place for 139*1da177e4SLinus Torvalds doing this anyway, with the generic_packet addition. 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds 3.01 Aug 6, 1999 - Jens Axboe <axboe@image.dk> 142*1da177e4SLinus Torvalds -- Fix up the sysctl handling so that the option flags get set 143*1da177e4SLinus Torvalds correctly. 144*1da177e4SLinus Torvalds -- Fix up ioctl handling so the device specific ones actually get 145*1da177e4SLinus Torvalds called :). 146*1da177e4SLinus Torvalds 147*1da177e4SLinus Torvalds 3.02 Aug 8, 1999 - Jens Axboe <axboe@image.dk> 148*1da177e4SLinus Torvalds -- Fixed volume control on SCSI drives (or others with longer audio 149*1da177e4SLinus Torvalds page). 150*1da177e4SLinus Torvalds -- Fixed a couple of DVD minors. Thanks to Andrew T. Veliath 151*1da177e4SLinus Torvalds <andrewtv@usa.net> for telling me and for having defined the various 152*1da177e4SLinus Torvalds DVD structures and ioctls in the first place! He designed the original 153*1da177e4SLinus Torvalds DVD patches for ide-cd and while I rearranged and unified them, the 154*1da177e4SLinus Torvalds interface is still the same. 155*1da177e4SLinus Torvalds 156*1da177e4SLinus Torvalds 3.03 Sep 1, 1999 - Jens Axboe <axboe@image.dk> 157*1da177e4SLinus Torvalds -- Moved the rest of the audio ioctls from the CD-ROM drivers here. Only 158*1da177e4SLinus Torvalds CDROMREADTOCENTRY and CDROMREADTOCHDR are left. 159*1da177e4SLinus Torvalds -- Moved the CDROMREADxxx ioctls in here. 160*1da177e4SLinus Torvalds -- Defined the cdrom_get_last_written and cdrom_get_next_block as ioctls 161*1da177e4SLinus Torvalds and exported functions. 162*1da177e4SLinus Torvalds -- Erik Andersen <andersen@xmission.com> modified all SCMD_ commands 163*1da177e4SLinus Torvalds to now read GPCMD_ for the new generic packet interface. All low level 164*1da177e4SLinus Torvalds drivers are updated as well. 165*1da177e4SLinus Torvalds -- Various other cleanups. 166*1da177e4SLinus Torvalds 167*1da177e4SLinus Torvalds 3.04 Sep 12, 1999 - Jens Axboe <axboe@image.dk> 168*1da177e4SLinus Torvalds -- Fixed a couple of possible memory leaks (if an operation failed and 169*1da177e4SLinus Torvalds we didn't free the buffer before returning the error). 170*1da177e4SLinus Torvalds -- Integrated Uniform CD Changer handling from Richard Sharman 171*1da177e4SLinus Torvalds <rsharman@pobox.com>. 172*1da177e4SLinus Torvalds -- Defined CD_DVD and CD_CHANGER log levels. 173*1da177e4SLinus Torvalds -- Fixed the CDROMREADxxx ioctls. 174*1da177e4SLinus Torvalds -- CDROMPLAYTRKIND uses the GPCMD_PLAY_AUDIO_MSF command - too few 175*1da177e4SLinus Torvalds drives supported it. We lose the index part, however. 176*1da177e4SLinus Torvalds -- Small modifications to accommodate opens of /dev/hdc1, required 177*1da177e4SLinus Torvalds for ide-cd to handle multisession discs. 178*1da177e4SLinus Torvalds -- Export cdrom_mode_sense and cdrom_mode_select. 179*1da177e4SLinus Torvalds -- init_cdrom_command() for setting up a cgc command. 180*1da177e4SLinus Torvalds 181*1da177e4SLinus Torvalds 3.05 Oct 24, 1999 - Jens Axboe <axboe@image.dk> 182*1da177e4SLinus Torvalds -- Changed the interface for CDROM_SEND_PACKET. Before it was virtually 183*1da177e4SLinus Torvalds impossible to send the drive data in a sensible way. 184*1da177e4SLinus Torvalds -- Lowered stack usage in mmc_ioctl(), dvd_read_disckey(), and 185*1da177e4SLinus Torvalds dvd_read_manufact. 186*1da177e4SLinus Torvalds -- Added setup of write mode for packet writing. 187*1da177e4SLinus Torvalds -- Fixed CDDA ripping with cdda2wav - accept much larger requests of 188*1da177e4SLinus Torvalds number of frames and split the reads in blocks of 8. 189*1da177e4SLinus Torvalds 190*1da177e4SLinus Torvalds 3.06 Dec 13, 1999 - Jens Axboe <axboe@image.dk> 191*1da177e4SLinus Torvalds -- Added support for changing the region of DVD drives. 192*1da177e4SLinus Torvalds -- Added sense data to generic command. 193*1da177e4SLinus Torvalds 194*1da177e4SLinus Torvalds 3.07 Feb 2, 2000 - Jens Axboe <axboe@suse.de> 195*1da177e4SLinus Torvalds -- Do same "read header length" trick in cdrom_get_disc_info() as 196*1da177e4SLinus Torvalds we do in cdrom_get_track_info() -- some drive don't obey specs and 197*1da177e4SLinus Torvalds fail if they can't supply the full Mt Fuji size table. 198*1da177e4SLinus Torvalds -- Deleted stuff related to setting up write modes. It has a different 199*1da177e4SLinus Torvalds home now. 200*1da177e4SLinus Torvalds -- Clear header length in mode_select unconditionally. 201*1da177e4SLinus Torvalds -- Removed the register_disk() that was added, not needed here. 202*1da177e4SLinus Torvalds 203*1da177e4SLinus Torvalds 3.08 May 1, 2000 - Jens Axboe <axboe@suse.de> 204*1da177e4SLinus Torvalds -- Fix direction flag in setup_send_key and setup_report_key. This 205*1da177e4SLinus Torvalds gave some SCSI adapters problems. 206*1da177e4SLinus Torvalds -- Always return -EROFS for write opens 207*1da177e4SLinus Torvalds -- Convert to module_init/module_exit style init and remove some 208*1da177e4SLinus Torvalds of the #ifdef MODULE stuff 209*1da177e4SLinus Torvalds -- Fix several dvd errors - DVD_LU_SEND_ASF should pass agid, 210*1da177e4SLinus Torvalds DVD_HOST_SEND_RPC_STATE did not set buffer size in cdb, and 211*1da177e4SLinus Torvalds dvd_do_auth passed uninitialized data to drive because init_cdrom_command 212*1da177e4SLinus Torvalds did not clear a 0 sized buffer. 213*1da177e4SLinus Torvalds 214*1da177e4SLinus Torvalds 3.09 May 12, 2000 - Jens Axboe <axboe@suse.de> 215*1da177e4SLinus Torvalds -- Fix Video-CD on SCSI drives that don't support READ_CD command. In 216*1da177e4SLinus Torvalds that case switch block size and issue plain READ_10 again, then switch 217*1da177e4SLinus Torvalds back. 218*1da177e4SLinus Torvalds 219*1da177e4SLinus Torvalds 3.10 Jun 10, 2000 - Jens Axboe <axboe@suse.de> 220*1da177e4SLinus Torvalds -- Fix volume control on CD's - old SCSI-II drives now use their own 221*1da177e4SLinus Torvalds code, as doing MODE6 stuff in here is really not my intention. 222*1da177e4SLinus Torvalds -- Use READ_DISC_INFO for more reliable end-of-disc. 223*1da177e4SLinus Torvalds 224*1da177e4SLinus Torvalds 3.11 Jun 12, 2000 - Jens Axboe <axboe@suse.de> 225*1da177e4SLinus Torvalds -- Fix bug in getting rpc phase 2 region info. 226*1da177e4SLinus Torvalds -- Reinstate "correct" CDROMPLAYTRKIND 227*1da177e4SLinus Torvalds 228*1da177e4SLinus Torvalds 3.12 Oct 18, 2000 - Jens Axboe <axboe@suse.de> 229*1da177e4SLinus Torvalds -- Use quiet bit on packet commands not known to work 230*1da177e4SLinus Torvalds 231*1da177e4SLinus Torvalds 3.20 Dec 17, 2003 - Jens Axboe <axboe@suse.de> 232*1da177e4SLinus Torvalds -- Various fixes and lots of cleanups not listed :-) 233*1da177e4SLinus Torvalds -- Locking fixes 234*1da177e4SLinus Torvalds -- Mt Rainier support 235*1da177e4SLinus Torvalds -- DVD-RAM write open fixes 236*1da177e4SLinus Torvalds 237*1da177e4SLinus Torvalds Nov 5 2001, Aug 8 2002. Modified by Andy Polyakov 238*1da177e4SLinus Torvalds <appro@fy.chalmers.se> to support MMC-3 compliant DVD+RW units. 239*1da177e4SLinus Torvalds 240*1da177e4SLinus Torvalds Modified by Nigel Kukard <nkukard@lbsd.net> - support DVD+RW 241*1da177e4SLinus Torvalds 2.4.x patch by Andy Polyakov <appro@fy.chalmers.se> 242*1da177e4SLinus Torvalds 243*1da177e4SLinus Torvalds -------------------------------------------------------------------------*/ 244*1da177e4SLinus Torvalds 245*1da177e4SLinus Torvalds #define REVISION "Revision: 3.20" 246*1da177e4SLinus Torvalds #define VERSION "Id: cdrom.c 3.20 2003/12/17" 247*1da177e4SLinus Torvalds 248*1da177e4SLinus Torvalds /* I use an error-log mask to give fine grain control over the type of 249*1da177e4SLinus Torvalds messages dumped to the system logs. The available masks include: */ 250*1da177e4SLinus Torvalds #define CD_NOTHING 0x0 251*1da177e4SLinus Torvalds #define CD_WARNING 0x1 252*1da177e4SLinus Torvalds #define CD_REG_UNREG 0x2 253*1da177e4SLinus Torvalds #define CD_DO_IOCTL 0x4 254*1da177e4SLinus Torvalds #define CD_OPEN 0x8 255*1da177e4SLinus Torvalds #define CD_CLOSE 0x10 256*1da177e4SLinus Torvalds #define CD_COUNT_TRACKS 0x20 257*1da177e4SLinus Torvalds #define CD_CHANGER 0x40 258*1da177e4SLinus Torvalds #define CD_DVD 0x80 259*1da177e4SLinus Torvalds 260*1da177e4SLinus Torvalds /* Define this to remove _all_ the debugging messages */ 261*1da177e4SLinus Torvalds /* #define ERRLOGMASK CD_NOTHING */ 262*1da177e4SLinus Torvalds #define ERRLOGMASK CD_WARNING 263*1da177e4SLinus Torvalds /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */ 264*1da177e4SLinus Torvalds /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */ 265*1da177e4SLinus Torvalds 266*1da177e4SLinus Torvalds #include <linux/config.h> 267*1da177e4SLinus Torvalds #include <linux/module.h> 268*1da177e4SLinus Torvalds #include <linux/fs.h> 269*1da177e4SLinus Torvalds #include <linux/buffer_head.h> 270*1da177e4SLinus Torvalds #include <linux/major.h> 271*1da177e4SLinus Torvalds #include <linux/types.h> 272*1da177e4SLinus Torvalds #include <linux/errno.h> 273*1da177e4SLinus Torvalds #include <linux/kernel.h> 274*1da177e4SLinus Torvalds #include <linux/mm.h> 275*1da177e4SLinus Torvalds #include <linux/slab.h> 276*1da177e4SLinus Torvalds #include <linux/cdrom.h> 277*1da177e4SLinus Torvalds #include <linux/sysctl.h> 278*1da177e4SLinus Torvalds #include <linux/proc_fs.h> 279*1da177e4SLinus Torvalds #include <linux/blkpg.h> 280*1da177e4SLinus Torvalds #include <linux/init.h> 281*1da177e4SLinus Torvalds #include <linux/fcntl.h> 282*1da177e4SLinus Torvalds #include <linux/blkdev.h> 283*1da177e4SLinus Torvalds #include <linux/times.h> 284*1da177e4SLinus Torvalds 285*1da177e4SLinus Torvalds #include <asm/uaccess.h> 286*1da177e4SLinus Torvalds 287*1da177e4SLinus Torvalds /* used to tell the module to turn on full debugging messages */ 288*1da177e4SLinus Torvalds static int debug; 289*1da177e4SLinus Torvalds /* used to keep tray locked at all times */ 290*1da177e4SLinus Torvalds static int keeplocked; 291*1da177e4SLinus Torvalds /* default compatibility mode */ 292*1da177e4SLinus Torvalds static int autoclose=1; 293*1da177e4SLinus Torvalds static int autoeject; 294*1da177e4SLinus Torvalds static int lockdoor = 1; 295*1da177e4SLinus Torvalds /* will we ever get to use this... sigh. */ 296*1da177e4SLinus Torvalds static int check_media_type; 297*1da177e4SLinus Torvalds /* automatically restart mrw format */ 298*1da177e4SLinus Torvalds static int mrw_format_restart = 1; 299*1da177e4SLinus Torvalds module_param(debug, bool, 0); 300*1da177e4SLinus Torvalds module_param(autoclose, bool, 0); 301*1da177e4SLinus Torvalds module_param(autoeject, bool, 0); 302*1da177e4SLinus Torvalds module_param(lockdoor, bool, 0); 303*1da177e4SLinus Torvalds module_param(check_media_type, bool, 0); 304*1da177e4SLinus Torvalds module_param(mrw_format_restart, bool, 0); 305*1da177e4SLinus Torvalds 306*1da177e4SLinus Torvalds static DEFINE_SPINLOCK(cdrom_lock); 307*1da177e4SLinus Torvalds 308*1da177e4SLinus Torvalds static const char *mrw_format_status[] = { 309*1da177e4SLinus Torvalds "not mrw", 310*1da177e4SLinus Torvalds "bgformat inactive", 311*1da177e4SLinus Torvalds "bgformat active", 312*1da177e4SLinus Torvalds "mrw complete", 313*1da177e4SLinus Torvalds }; 314*1da177e4SLinus Torvalds 315*1da177e4SLinus Torvalds static const char *mrw_address_space[] = { "DMA", "GAA" }; 316*1da177e4SLinus Torvalds 317*1da177e4SLinus Torvalds #if (ERRLOGMASK!=CD_NOTHING) 318*1da177e4SLinus Torvalds #define cdinfo(type, fmt, args...) \ 319*1da177e4SLinus Torvalds if ((ERRLOGMASK & type) || debug==1 ) \ 320*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: " fmt, ## args) 321*1da177e4SLinus Torvalds #else 322*1da177e4SLinus Torvalds #define cdinfo(type, fmt, args...) 323*1da177e4SLinus Torvalds #endif 324*1da177e4SLinus Torvalds 325*1da177e4SLinus Torvalds /* These are used to simplify getting data in from and back to user land */ 326*1da177e4SLinus Torvalds #define IOCTL_IN(arg, type, in) \ 327*1da177e4SLinus Torvalds if (copy_from_user(&(in), (type __user *) (arg), sizeof (in))) \ 328*1da177e4SLinus Torvalds return -EFAULT; 329*1da177e4SLinus Torvalds 330*1da177e4SLinus Torvalds #define IOCTL_OUT(arg, type, out) \ 331*1da177e4SLinus Torvalds if (copy_to_user((type __user *) (arg), &(out), sizeof (out))) \ 332*1da177e4SLinus Torvalds return -EFAULT; 333*1da177e4SLinus Torvalds 334*1da177e4SLinus Torvalds /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in 335*1da177e4SLinus Torvalds a lot of places. This macro makes the code more clear. */ 336*1da177e4SLinus Torvalds #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type)) 337*1da177e4SLinus Torvalds 338*1da177e4SLinus Torvalds /* used in the audio ioctls */ 339*1da177e4SLinus Torvalds #define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret 340*1da177e4SLinus Torvalds 341*1da177e4SLinus Torvalds /* Not-exported routines. */ 342*1da177e4SLinus Torvalds static int open_for_data(struct cdrom_device_info * cdi); 343*1da177e4SLinus Torvalds static int check_for_audio_disc(struct cdrom_device_info * cdi, 344*1da177e4SLinus Torvalds struct cdrom_device_ops * cdo); 345*1da177e4SLinus Torvalds static void sanitize_format(union cdrom_addr *addr, 346*1da177e4SLinus Torvalds u_char * curr, u_char requested); 347*1da177e4SLinus Torvalds static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, 348*1da177e4SLinus Torvalds unsigned long arg); 349*1da177e4SLinus Torvalds 350*1da177e4SLinus Torvalds int cdrom_get_last_written(struct cdrom_device_info *, long *); 351*1da177e4SLinus Torvalds static int cdrom_get_next_writable(struct cdrom_device_info *, long *); 352*1da177e4SLinus Torvalds static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); 353*1da177e4SLinus Torvalds 354*1da177e4SLinus Torvalds static int cdrom_mrw_exit(struct cdrom_device_info *cdi); 355*1da177e4SLinus Torvalds 356*1da177e4SLinus Torvalds static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di); 357*1da177e4SLinus Torvalds 358*1da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 359*1da177e4SLinus Torvalds static void cdrom_sysctl_register(void); 360*1da177e4SLinus Torvalds #endif /* CONFIG_SYSCTL */ 361*1da177e4SLinus Torvalds static struct cdrom_device_info *topCdromPtr; 362*1da177e4SLinus Torvalds 363*1da177e4SLinus Torvalds static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, 364*1da177e4SLinus Torvalds struct packet_command *cgc) 365*1da177e4SLinus Torvalds { 366*1da177e4SLinus Torvalds if (cgc->sense) { 367*1da177e4SLinus Torvalds cgc->sense->sense_key = 0x05; 368*1da177e4SLinus Torvalds cgc->sense->asc = 0x20; 369*1da177e4SLinus Torvalds cgc->sense->ascq = 0x00; 370*1da177e4SLinus Torvalds } 371*1da177e4SLinus Torvalds 372*1da177e4SLinus Torvalds cgc->stat = -EIO; 373*1da177e4SLinus Torvalds return -EIO; 374*1da177e4SLinus Torvalds } 375*1da177e4SLinus Torvalds 376*1da177e4SLinus Torvalds /* This macro makes sure we don't have to check on cdrom_device_ops 377*1da177e4SLinus Torvalds * existence in the run-time routines below. Change_capability is a 378*1da177e4SLinus Torvalds * hack to have the capability flags defined const, while we can still 379*1da177e4SLinus Torvalds * change it here without gcc complaining at every line. 380*1da177e4SLinus Torvalds */ 381*1da177e4SLinus Torvalds #define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) 382*1da177e4SLinus Torvalds 383*1da177e4SLinus Torvalds int register_cdrom(struct cdrom_device_info *cdi) 384*1da177e4SLinus Torvalds { 385*1da177e4SLinus Torvalds static char banner_printed; 386*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 387*1da177e4SLinus Torvalds int *change_capability = (int *)&cdo->capability; /* hack */ 388*1da177e4SLinus Torvalds 389*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "entering register_cdrom\n"); 390*1da177e4SLinus Torvalds 391*1da177e4SLinus Torvalds if (cdo->open == NULL || cdo->release == NULL) 392*1da177e4SLinus Torvalds return -2; 393*1da177e4SLinus Torvalds if (!banner_printed) { 394*1da177e4SLinus Torvalds printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); 395*1da177e4SLinus Torvalds banner_printed = 1; 396*1da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 397*1da177e4SLinus Torvalds cdrom_sysctl_register(); 398*1da177e4SLinus Torvalds #endif /* CONFIG_SYSCTL */ 399*1da177e4SLinus Torvalds } 400*1da177e4SLinus Torvalds 401*1da177e4SLinus Torvalds ENSURE(drive_status, CDC_DRIVE_STATUS ); 402*1da177e4SLinus Torvalds ENSURE(media_changed, CDC_MEDIA_CHANGED); 403*1da177e4SLinus Torvalds ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); 404*1da177e4SLinus Torvalds ENSURE(lock_door, CDC_LOCK); 405*1da177e4SLinus Torvalds ENSURE(select_speed, CDC_SELECT_SPEED); 406*1da177e4SLinus Torvalds ENSURE(get_last_session, CDC_MULTI_SESSION); 407*1da177e4SLinus Torvalds ENSURE(get_mcn, CDC_MCN); 408*1da177e4SLinus Torvalds ENSURE(reset, CDC_RESET); 409*1da177e4SLinus Torvalds ENSURE(audio_ioctl, CDC_PLAY_AUDIO); 410*1da177e4SLinus Torvalds ENSURE(dev_ioctl, CDC_IOCTLS); 411*1da177e4SLinus Torvalds ENSURE(generic_packet, CDC_GENERIC_PACKET); 412*1da177e4SLinus Torvalds cdi->mc_flags = 0; 413*1da177e4SLinus Torvalds cdo->n_minors = 0; 414*1da177e4SLinus Torvalds cdi->options = CDO_USE_FFLAGS; 415*1da177e4SLinus Torvalds 416*1da177e4SLinus Torvalds if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) 417*1da177e4SLinus Torvalds cdi->options |= (int) CDO_AUTO_CLOSE; 418*1da177e4SLinus Torvalds if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY)) 419*1da177e4SLinus Torvalds cdi->options |= (int) CDO_AUTO_EJECT; 420*1da177e4SLinus Torvalds if (lockdoor==1) 421*1da177e4SLinus Torvalds cdi->options |= (int) CDO_LOCK; 422*1da177e4SLinus Torvalds if (check_media_type==1) 423*1da177e4SLinus Torvalds cdi->options |= (int) CDO_CHECK_TYPE; 424*1da177e4SLinus Torvalds 425*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_MRW_W)) 426*1da177e4SLinus Torvalds cdi->exit = cdrom_mrw_exit; 427*1da177e4SLinus Torvalds 428*1da177e4SLinus Torvalds if (cdi->disk) 429*1da177e4SLinus Torvalds cdi->cdda_method = CDDA_BPC_FULL; 430*1da177e4SLinus Torvalds else 431*1da177e4SLinus Torvalds cdi->cdda_method = CDDA_OLD; 432*1da177e4SLinus Torvalds 433*1da177e4SLinus Torvalds if (!cdo->generic_packet) 434*1da177e4SLinus Torvalds cdo->generic_packet = cdrom_dummy_generic_packet; 435*1da177e4SLinus Torvalds 436*1da177e4SLinus Torvalds cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); 437*1da177e4SLinus Torvalds spin_lock(&cdrom_lock); 438*1da177e4SLinus Torvalds cdi->next = topCdromPtr; 439*1da177e4SLinus Torvalds topCdromPtr = cdi; 440*1da177e4SLinus Torvalds spin_unlock(&cdrom_lock); 441*1da177e4SLinus Torvalds return 0; 442*1da177e4SLinus Torvalds } 443*1da177e4SLinus Torvalds #undef ENSURE 444*1da177e4SLinus Torvalds 445*1da177e4SLinus Torvalds int unregister_cdrom(struct cdrom_device_info *unreg) 446*1da177e4SLinus Torvalds { 447*1da177e4SLinus Torvalds struct cdrom_device_info *cdi, *prev; 448*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 449*1da177e4SLinus Torvalds 450*1da177e4SLinus Torvalds prev = NULL; 451*1da177e4SLinus Torvalds spin_lock(&cdrom_lock); 452*1da177e4SLinus Torvalds cdi = topCdromPtr; 453*1da177e4SLinus Torvalds while (cdi && cdi != unreg) { 454*1da177e4SLinus Torvalds prev = cdi; 455*1da177e4SLinus Torvalds cdi = cdi->next; 456*1da177e4SLinus Torvalds } 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds if (cdi == NULL) { 459*1da177e4SLinus Torvalds spin_unlock(&cdrom_lock); 460*1da177e4SLinus Torvalds return -2; 461*1da177e4SLinus Torvalds } 462*1da177e4SLinus Torvalds if (prev) 463*1da177e4SLinus Torvalds prev->next = cdi->next; 464*1da177e4SLinus Torvalds else 465*1da177e4SLinus Torvalds topCdromPtr = cdi->next; 466*1da177e4SLinus Torvalds 467*1da177e4SLinus Torvalds spin_unlock(&cdrom_lock); 468*1da177e4SLinus Torvalds 469*1da177e4SLinus Torvalds if (cdi->exit) 470*1da177e4SLinus Torvalds cdi->exit(cdi); 471*1da177e4SLinus Torvalds 472*1da177e4SLinus Torvalds cdi->ops->n_minors--; 473*1da177e4SLinus Torvalds cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); 474*1da177e4SLinus Torvalds return 0; 475*1da177e4SLinus Torvalds } 476*1da177e4SLinus Torvalds 477*1da177e4SLinus Torvalds int cdrom_get_media_event(struct cdrom_device_info *cdi, 478*1da177e4SLinus Torvalds struct media_event_desc *med) 479*1da177e4SLinus Torvalds { 480*1da177e4SLinus Torvalds struct packet_command cgc; 481*1da177e4SLinus Torvalds unsigned char buffer[8]; 482*1da177e4SLinus Torvalds struct event_header *eh = (struct event_header *) buffer; 483*1da177e4SLinus Torvalds 484*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 485*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; 486*1da177e4SLinus Torvalds cgc.cmd[1] = 1; /* IMMED */ 487*1da177e4SLinus Torvalds cgc.cmd[4] = 1 << 4; /* media event */ 488*1da177e4SLinus Torvalds cgc.cmd[8] = sizeof(buffer); 489*1da177e4SLinus Torvalds cgc.quiet = 1; 490*1da177e4SLinus Torvalds 491*1da177e4SLinus Torvalds if (cdi->ops->generic_packet(cdi, &cgc)) 492*1da177e4SLinus Torvalds return 1; 493*1da177e4SLinus Torvalds 494*1da177e4SLinus Torvalds if (be16_to_cpu(eh->data_len) < sizeof(*med)) 495*1da177e4SLinus Torvalds return 1; 496*1da177e4SLinus Torvalds 497*1da177e4SLinus Torvalds if (eh->nea || eh->notification_class != 0x4) 498*1da177e4SLinus Torvalds return 1; 499*1da177e4SLinus Torvalds 500*1da177e4SLinus Torvalds memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); 501*1da177e4SLinus Torvalds return 0; 502*1da177e4SLinus Torvalds } 503*1da177e4SLinus Torvalds 504*1da177e4SLinus Torvalds /* 505*1da177e4SLinus Torvalds * the first prototypes used 0x2c as the page code for the mrw mode page, 506*1da177e4SLinus Torvalds * subsequently this was changed to 0x03. probe the one used by this drive 507*1da177e4SLinus Torvalds */ 508*1da177e4SLinus Torvalds static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) 509*1da177e4SLinus Torvalds { 510*1da177e4SLinus Torvalds struct packet_command cgc; 511*1da177e4SLinus Torvalds char buffer[16]; 512*1da177e4SLinus Torvalds 513*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 514*1da177e4SLinus Torvalds 515*1da177e4SLinus Torvalds cgc.timeout = HZ; 516*1da177e4SLinus Torvalds cgc.quiet = 1; 517*1da177e4SLinus Torvalds 518*1da177e4SLinus Torvalds if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { 519*1da177e4SLinus Torvalds cdi->mrw_mode_page = MRW_MODE_PC; 520*1da177e4SLinus Torvalds return 0; 521*1da177e4SLinus Torvalds } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { 522*1da177e4SLinus Torvalds cdi->mrw_mode_page = MRW_MODE_PC_PRE1; 523*1da177e4SLinus Torvalds return 0; 524*1da177e4SLinus Torvalds } 525*1da177e4SLinus Torvalds 526*1da177e4SLinus Torvalds return 1; 527*1da177e4SLinus Torvalds } 528*1da177e4SLinus Torvalds 529*1da177e4SLinus Torvalds static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) 530*1da177e4SLinus Torvalds { 531*1da177e4SLinus Torvalds struct packet_command cgc; 532*1da177e4SLinus Torvalds struct mrw_feature_desc *mfd; 533*1da177e4SLinus Torvalds unsigned char buffer[16]; 534*1da177e4SLinus Torvalds int ret; 535*1da177e4SLinus Torvalds 536*1da177e4SLinus Torvalds *write = 0; 537*1da177e4SLinus Torvalds 538*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 539*1da177e4SLinus Torvalds 540*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_GET_CONFIGURATION; 541*1da177e4SLinus Torvalds cgc.cmd[3] = CDF_MRW; 542*1da177e4SLinus Torvalds cgc.cmd[8] = sizeof(buffer); 543*1da177e4SLinus Torvalds cgc.quiet = 1; 544*1da177e4SLinus Torvalds 545*1da177e4SLinus Torvalds if ((ret = cdi->ops->generic_packet(cdi, &cgc))) 546*1da177e4SLinus Torvalds return ret; 547*1da177e4SLinus Torvalds 548*1da177e4SLinus Torvalds mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; 549*1da177e4SLinus Torvalds if (be16_to_cpu(mfd->feature_code) != CDF_MRW) 550*1da177e4SLinus Torvalds return 1; 551*1da177e4SLinus Torvalds *write = mfd->write; 552*1da177e4SLinus Torvalds 553*1da177e4SLinus Torvalds if ((ret = cdrom_mrw_probe_pc(cdi))) { 554*1da177e4SLinus Torvalds *write = 0; 555*1da177e4SLinus Torvalds return ret; 556*1da177e4SLinus Torvalds } 557*1da177e4SLinus Torvalds 558*1da177e4SLinus Torvalds return 0; 559*1da177e4SLinus Torvalds } 560*1da177e4SLinus Torvalds 561*1da177e4SLinus Torvalds static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) 562*1da177e4SLinus Torvalds { 563*1da177e4SLinus Torvalds struct packet_command cgc; 564*1da177e4SLinus Torvalds unsigned char buffer[12]; 565*1da177e4SLinus Torvalds int ret; 566*1da177e4SLinus Torvalds 567*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); 568*1da177e4SLinus Torvalds 569*1da177e4SLinus Torvalds /* 570*1da177e4SLinus Torvalds * FmtData bit set (bit 4), format type is 1 571*1da177e4SLinus Torvalds */ 572*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); 573*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_FORMAT_UNIT; 574*1da177e4SLinus Torvalds cgc.cmd[1] = (1 << 4) | 1; 575*1da177e4SLinus Torvalds 576*1da177e4SLinus Torvalds cgc.timeout = 5 * 60 * HZ; 577*1da177e4SLinus Torvalds 578*1da177e4SLinus Torvalds /* 579*1da177e4SLinus Torvalds * 4 byte format list header, 8 byte format list descriptor 580*1da177e4SLinus Torvalds */ 581*1da177e4SLinus Torvalds buffer[1] = 1 << 1; 582*1da177e4SLinus Torvalds buffer[3] = 8; 583*1da177e4SLinus Torvalds 584*1da177e4SLinus Torvalds /* 585*1da177e4SLinus Torvalds * nr_blocks field 586*1da177e4SLinus Torvalds */ 587*1da177e4SLinus Torvalds buffer[4] = 0xff; 588*1da177e4SLinus Torvalds buffer[5] = 0xff; 589*1da177e4SLinus Torvalds buffer[6] = 0xff; 590*1da177e4SLinus Torvalds buffer[7] = 0xff; 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds buffer[8] = 0x24 << 2; 593*1da177e4SLinus Torvalds buffer[11] = cont; 594*1da177e4SLinus Torvalds 595*1da177e4SLinus Torvalds ret = cdi->ops->generic_packet(cdi, &cgc); 596*1da177e4SLinus Torvalds if (ret) 597*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: bgformat failed\n"); 598*1da177e4SLinus Torvalds 599*1da177e4SLinus Torvalds return ret; 600*1da177e4SLinus Torvalds } 601*1da177e4SLinus Torvalds 602*1da177e4SLinus Torvalds static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed) 603*1da177e4SLinus Torvalds { 604*1da177e4SLinus Torvalds struct packet_command cgc; 605*1da177e4SLinus Torvalds 606*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 607*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_CLOSE_TRACK; 608*1da177e4SLinus Torvalds 609*1da177e4SLinus Torvalds /* 610*1da177e4SLinus Torvalds * Session = 1, Track = 0 611*1da177e4SLinus Torvalds */ 612*1da177e4SLinus Torvalds cgc.cmd[1] = !!immed; 613*1da177e4SLinus Torvalds cgc.cmd[2] = 1 << 1; 614*1da177e4SLinus Torvalds 615*1da177e4SLinus Torvalds cgc.timeout = 5 * 60 * HZ; 616*1da177e4SLinus Torvalds 617*1da177e4SLinus Torvalds return cdi->ops->generic_packet(cdi, &cgc); 618*1da177e4SLinus Torvalds } 619*1da177e4SLinus Torvalds 620*1da177e4SLinus Torvalds static int cdrom_flush_cache(struct cdrom_device_info *cdi) 621*1da177e4SLinus Torvalds { 622*1da177e4SLinus Torvalds struct packet_command cgc; 623*1da177e4SLinus Torvalds 624*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 625*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_FLUSH_CACHE; 626*1da177e4SLinus Torvalds 627*1da177e4SLinus Torvalds cgc.timeout = 5 * 60 * HZ; 628*1da177e4SLinus Torvalds 629*1da177e4SLinus Torvalds return cdi->ops->generic_packet(cdi, &cgc); 630*1da177e4SLinus Torvalds } 631*1da177e4SLinus Torvalds 632*1da177e4SLinus Torvalds static int cdrom_mrw_exit(struct cdrom_device_info *cdi) 633*1da177e4SLinus Torvalds { 634*1da177e4SLinus Torvalds disc_information di; 635*1da177e4SLinus Torvalds int ret; 636*1da177e4SLinus Torvalds 637*1da177e4SLinus Torvalds ret = cdrom_get_disc_info(cdi, &di); 638*1da177e4SLinus Torvalds if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type)) 639*1da177e4SLinus Torvalds return 1; 640*1da177e4SLinus Torvalds 641*1da177e4SLinus Torvalds ret = 0; 642*1da177e4SLinus Torvalds if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { 643*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: issuing MRW back ground " 644*1da177e4SLinus Torvalds "format suspend\n"); 645*1da177e4SLinus Torvalds ret = cdrom_mrw_bgformat_susp(cdi, 0); 646*1da177e4SLinus Torvalds } 647*1da177e4SLinus Torvalds 648*1da177e4SLinus Torvalds if (!ret) 649*1da177e4SLinus Torvalds ret = cdrom_flush_cache(cdi); 650*1da177e4SLinus Torvalds 651*1da177e4SLinus Torvalds return ret; 652*1da177e4SLinus Torvalds } 653*1da177e4SLinus Torvalds 654*1da177e4SLinus Torvalds static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) 655*1da177e4SLinus Torvalds { 656*1da177e4SLinus Torvalds struct packet_command cgc; 657*1da177e4SLinus Torvalds struct mode_page_header *mph; 658*1da177e4SLinus Torvalds char buffer[16]; 659*1da177e4SLinus Torvalds int ret, offset, size; 660*1da177e4SLinus Torvalds 661*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 662*1da177e4SLinus Torvalds 663*1da177e4SLinus Torvalds cgc.buffer = buffer; 664*1da177e4SLinus Torvalds cgc.buflen = sizeof(buffer); 665*1da177e4SLinus Torvalds 666*1da177e4SLinus Torvalds if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) 667*1da177e4SLinus Torvalds return ret; 668*1da177e4SLinus Torvalds 669*1da177e4SLinus Torvalds mph = (struct mode_page_header *) buffer; 670*1da177e4SLinus Torvalds offset = be16_to_cpu(mph->desc_length); 671*1da177e4SLinus Torvalds size = be16_to_cpu(mph->mode_data_length) + 2; 672*1da177e4SLinus Torvalds 673*1da177e4SLinus Torvalds buffer[offset + 3] = space; 674*1da177e4SLinus Torvalds cgc.buflen = size; 675*1da177e4SLinus Torvalds 676*1da177e4SLinus Torvalds if ((ret = cdrom_mode_select(cdi, &cgc))) 677*1da177e4SLinus Torvalds return ret; 678*1da177e4SLinus Torvalds 679*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); 680*1da177e4SLinus Torvalds return 0; 681*1da177e4SLinus Torvalds } 682*1da177e4SLinus Torvalds 683*1da177e4SLinus Torvalds static int cdrom_get_random_writable(struct cdrom_device_info *cdi, 684*1da177e4SLinus Torvalds struct rwrt_feature_desc *rfd) 685*1da177e4SLinus Torvalds { 686*1da177e4SLinus Torvalds struct packet_command cgc; 687*1da177e4SLinus Torvalds char buffer[24]; 688*1da177e4SLinus Torvalds int ret; 689*1da177e4SLinus Torvalds 690*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 691*1da177e4SLinus Torvalds 692*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ 693*1da177e4SLinus Torvalds cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */ 694*1da177e4SLinus Torvalds cgc.cmd[8] = sizeof(buffer); /* often 0x18 */ 695*1da177e4SLinus Torvalds cgc.quiet = 1; 696*1da177e4SLinus Torvalds 697*1da177e4SLinus Torvalds if ((ret = cdi->ops->generic_packet(cdi, &cgc))) 698*1da177e4SLinus Torvalds return ret; 699*1da177e4SLinus Torvalds 700*1da177e4SLinus Torvalds memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); 701*1da177e4SLinus Torvalds return 0; 702*1da177e4SLinus Torvalds } 703*1da177e4SLinus Torvalds 704*1da177e4SLinus Torvalds static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) 705*1da177e4SLinus Torvalds { 706*1da177e4SLinus Torvalds struct packet_command cgc; 707*1da177e4SLinus Torvalds char buffer[16]; 708*1da177e4SLinus Torvalds __u16 *feature_code; 709*1da177e4SLinus Torvalds int ret; 710*1da177e4SLinus Torvalds 711*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 712*1da177e4SLinus Torvalds 713*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_GET_CONFIGURATION; 714*1da177e4SLinus Torvalds cgc.cmd[3] = CDF_HWDM; 715*1da177e4SLinus Torvalds cgc.cmd[8] = sizeof(buffer); 716*1da177e4SLinus Torvalds cgc.quiet = 1; 717*1da177e4SLinus Torvalds 718*1da177e4SLinus Torvalds if ((ret = cdi->ops->generic_packet(cdi, &cgc))) 719*1da177e4SLinus Torvalds return ret; 720*1da177e4SLinus Torvalds 721*1da177e4SLinus Torvalds feature_code = (__u16 *) &buffer[sizeof(struct feature_header)]; 722*1da177e4SLinus Torvalds if (be16_to_cpu(*feature_code) == CDF_HWDM) 723*1da177e4SLinus Torvalds return 0; 724*1da177e4SLinus Torvalds 725*1da177e4SLinus Torvalds return 1; 726*1da177e4SLinus Torvalds } 727*1da177e4SLinus Torvalds 728*1da177e4SLinus Torvalds 729*1da177e4SLinus Torvalds static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write) 730*1da177e4SLinus Torvalds { 731*1da177e4SLinus Torvalds struct rwrt_feature_desc rfd; 732*1da177e4SLinus Torvalds int ret; 733*1da177e4SLinus Torvalds 734*1da177e4SLinus Torvalds *write = 0; 735*1da177e4SLinus Torvalds 736*1da177e4SLinus Torvalds if ((ret = cdrom_get_random_writable(cdi, &rfd))) 737*1da177e4SLinus Torvalds return ret; 738*1da177e4SLinus Torvalds 739*1da177e4SLinus Torvalds if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) 740*1da177e4SLinus Torvalds *write = 1; 741*1da177e4SLinus Torvalds 742*1da177e4SLinus Torvalds return 0; 743*1da177e4SLinus Torvalds } 744*1da177e4SLinus Torvalds 745*1da177e4SLinus Torvalds static int cdrom_media_erasable(struct cdrom_device_info *cdi) 746*1da177e4SLinus Torvalds { 747*1da177e4SLinus Torvalds disc_information di; 748*1da177e4SLinus Torvalds int ret; 749*1da177e4SLinus Torvalds 750*1da177e4SLinus Torvalds ret = cdrom_get_disc_info(cdi, &di); 751*1da177e4SLinus Torvalds if (ret < 0 || ret < offsetof(typeof(di), n_first_track)) 752*1da177e4SLinus Torvalds return -1; 753*1da177e4SLinus Torvalds 754*1da177e4SLinus Torvalds return di.erasable; 755*1da177e4SLinus Torvalds } 756*1da177e4SLinus Torvalds 757*1da177e4SLinus Torvalds /* 758*1da177e4SLinus Torvalds * FIXME: check RO bit 759*1da177e4SLinus Torvalds */ 760*1da177e4SLinus Torvalds static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi) 761*1da177e4SLinus Torvalds { 762*1da177e4SLinus Torvalds int ret = cdrom_media_erasable(cdi); 763*1da177e4SLinus Torvalds 764*1da177e4SLinus Torvalds /* 765*1da177e4SLinus Torvalds * allow writable open if media info read worked and media is 766*1da177e4SLinus Torvalds * erasable, _or_ if it fails since not all drives support it 767*1da177e4SLinus Torvalds */ 768*1da177e4SLinus Torvalds if (!ret) 769*1da177e4SLinus Torvalds return 1; 770*1da177e4SLinus Torvalds 771*1da177e4SLinus Torvalds return 0; 772*1da177e4SLinus Torvalds } 773*1da177e4SLinus Torvalds 774*1da177e4SLinus Torvalds static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) 775*1da177e4SLinus Torvalds { 776*1da177e4SLinus Torvalds disc_information di; 777*1da177e4SLinus Torvalds int ret; 778*1da177e4SLinus Torvalds 779*1da177e4SLinus Torvalds /* 780*1da177e4SLinus Torvalds * always reset to DMA lba space on open 781*1da177e4SLinus Torvalds */ 782*1da177e4SLinus Torvalds if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) { 783*1da177e4SLinus Torvalds printk(KERN_ERR "cdrom: failed setting lba address space\n"); 784*1da177e4SLinus Torvalds return 1; 785*1da177e4SLinus Torvalds } 786*1da177e4SLinus Torvalds 787*1da177e4SLinus Torvalds ret = cdrom_get_disc_info(cdi, &di); 788*1da177e4SLinus Torvalds if (ret < 0 || ret < offsetof(typeof(di),disc_type)) 789*1da177e4SLinus Torvalds return 1; 790*1da177e4SLinus Torvalds 791*1da177e4SLinus Torvalds if (!di.erasable) 792*1da177e4SLinus Torvalds return 1; 793*1da177e4SLinus Torvalds 794*1da177e4SLinus Torvalds /* 795*1da177e4SLinus Torvalds * mrw_status 796*1da177e4SLinus Torvalds * 0 - not MRW formatted 797*1da177e4SLinus Torvalds * 1 - MRW bgformat started, but not running or complete 798*1da177e4SLinus Torvalds * 2 - MRW bgformat in progress 799*1da177e4SLinus Torvalds * 3 - MRW formatting complete 800*1da177e4SLinus Torvalds */ 801*1da177e4SLinus Torvalds ret = 0; 802*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom open: mrw_status '%s'\n", 803*1da177e4SLinus Torvalds mrw_format_status[di.mrw_status]); 804*1da177e4SLinus Torvalds if (!di.mrw_status) 805*1da177e4SLinus Torvalds ret = 1; 806*1da177e4SLinus Torvalds else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && 807*1da177e4SLinus Torvalds mrw_format_restart) 808*1da177e4SLinus Torvalds ret = cdrom_mrw_bgformat(cdi, 1); 809*1da177e4SLinus Torvalds 810*1da177e4SLinus Torvalds return ret; 811*1da177e4SLinus Torvalds } 812*1da177e4SLinus Torvalds 813*1da177e4SLinus Torvalds static int mo_open_write(struct cdrom_device_info *cdi) 814*1da177e4SLinus Torvalds { 815*1da177e4SLinus Torvalds struct packet_command cgc; 816*1da177e4SLinus Torvalds char buffer[255]; 817*1da177e4SLinus Torvalds int ret; 818*1da177e4SLinus Torvalds 819*1da177e4SLinus Torvalds init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); 820*1da177e4SLinus Torvalds cgc.quiet = 1; 821*1da177e4SLinus Torvalds 822*1da177e4SLinus Torvalds /* 823*1da177e4SLinus Torvalds * obtain write protect information as per 824*1da177e4SLinus Torvalds * drivers/scsi/sd.c:sd_read_write_protect_flag 825*1da177e4SLinus Torvalds */ 826*1da177e4SLinus Torvalds 827*1da177e4SLinus Torvalds ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); 828*1da177e4SLinus Torvalds if (ret) 829*1da177e4SLinus Torvalds ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0); 830*1da177e4SLinus Torvalds if (ret) { 831*1da177e4SLinus Torvalds cgc.buflen = 255; 832*1da177e4SLinus Torvalds ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0); 833*1da177e4SLinus Torvalds } 834*1da177e4SLinus Torvalds 835*1da177e4SLinus Torvalds /* drive gave us no info, let the user go ahead */ 836*1da177e4SLinus Torvalds if (ret) 837*1da177e4SLinus Torvalds return 0; 838*1da177e4SLinus Torvalds 839*1da177e4SLinus Torvalds return buffer[3] & 0x80; 840*1da177e4SLinus Torvalds } 841*1da177e4SLinus Torvalds 842*1da177e4SLinus Torvalds static int cdrom_ram_open_write(struct cdrom_device_info *cdi) 843*1da177e4SLinus Torvalds { 844*1da177e4SLinus Torvalds struct rwrt_feature_desc rfd; 845*1da177e4SLinus Torvalds int ret; 846*1da177e4SLinus Torvalds 847*1da177e4SLinus Torvalds if ((ret = cdrom_has_defect_mgt(cdi))) 848*1da177e4SLinus Torvalds return ret; 849*1da177e4SLinus Torvalds 850*1da177e4SLinus Torvalds if ((ret = cdrom_get_random_writable(cdi, &rfd))) 851*1da177e4SLinus Torvalds return ret; 852*1da177e4SLinus Torvalds else if (CDF_RWRT == be16_to_cpu(rfd.feature_code)) 853*1da177e4SLinus Torvalds ret = !rfd.curr; 854*1da177e4SLinus Torvalds 855*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "can open for random write\n"); 856*1da177e4SLinus Torvalds return ret; 857*1da177e4SLinus Torvalds } 858*1da177e4SLinus Torvalds 859*1da177e4SLinus Torvalds static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) 860*1da177e4SLinus Torvalds { 861*1da177e4SLinus Torvalds struct packet_command cgc; 862*1da177e4SLinus Torvalds char buffer[32]; 863*1da177e4SLinus Torvalds int ret, mmc3_profile; 864*1da177e4SLinus Torvalds 865*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); 866*1da177e4SLinus Torvalds 867*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_GET_CONFIGURATION; 868*1da177e4SLinus Torvalds cgc.cmd[1] = 0; 869*1da177e4SLinus Torvalds cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ 870*1da177e4SLinus Torvalds cgc.cmd[8] = sizeof(buffer); /* Allocation Length */ 871*1da177e4SLinus Torvalds cgc.quiet = 1; 872*1da177e4SLinus Torvalds 873*1da177e4SLinus Torvalds if ((ret = cdi->ops->generic_packet(cdi, &cgc))) 874*1da177e4SLinus Torvalds mmc3_profile = 0xffff; 875*1da177e4SLinus Torvalds else 876*1da177e4SLinus Torvalds mmc3_profile = (buffer[6] << 8) | buffer[7]; 877*1da177e4SLinus Torvalds 878*1da177e4SLinus Torvalds cdi->mmc3_profile = mmc3_profile; 879*1da177e4SLinus Torvalds } 880*1da177e4SLinus Torvalds 881*1da177e4SLinus Torvalds static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) 882*1da177e4SLinus Torvalds { 883*1da177e4SLinus Torvalds switch (cdi->mmc3_profile) { 884*1da177e4SLinus Torvalds case 0x12: /* DVD-RAM */ 885*1da177e4SLinus Torvalds case 0x1A: /* DVD+RW */ 886*1da177e4SLinus Torvalds return 0; 887*1da177e4SLinus Torvalds default: 888*1da177e4SLinus Torvalds return 1; 889*1da177e4SLinus Torvalds } 890*1da177e4SLinus Torvalds } 891*1da177e4SLinus Torvalds 892*1da177e4SLinus Torvalds /* 893*1da177e4SLinus Torvalds * returns 0 for ok to open write, non-0 to disallow 894*1da177e4SLinus Torvalds */ 895*1da177e4SLinus Torvalds static int cdrom_open_write(struct cdrom_device_info *cdi) 896*1da177e4SLinus Torvalds { 897*1da177e4SLinus Torvalds int mrw, mrw_write, ram_write; 898*1da177e4SLinus Torvalds int ret = 1; 899*1da177e4SLinus Torvalds 900*1da177e4SLinus Torvalds mrw = 0; 901*1da177e4SLinus Torvalds if (!cdrom_is_mrw(cdi, &mrw_write)) 902*1da177e4SLinus Torvalds mrw = 1; 903*1da177e4SLinus Torvalds 904*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_MO_DRIVE)) 905*1da177e4SLinus Torvalds ram_write = 1; 906*1da177e4SLinus Torvalds else 907*1da177e4SLinus Torvalds (void) cdrom_is_random_writable(cdi, &ram_write); 908*1da177e4SLinus Torvalds 909*1da177e4SLinus Torvalds if (mrw) 910*1da177e4SLinus Torvalds cdi->mask &= ~CDC_MRW; 911*1da177e4SLinus Torvalds else 912*1da177e4SLinus Torvalds cdi->mask |= CDC_MRW; 913*1da177e4SLinus Torvalds 914*1da177e4SLinus Torvalds if (mrw_write) 915*1da177e4SLinus Torvalds cdi->mask &= ~CDC_MRW_W; 916*1da177e4SLinus Torvalds else 917*1da177e4SLinus Torvalds cdi->mask |= CDC_MRW_W; 918*1da177e4SLinus Torvalds 919*1da177e4SLinus Torvalds if (ram_write) 920*1da177e4SLinus Torvalds cdi->mask &= ~CDC_RAM; 921*1da177e4SLinus Torvalds else 922*1da177e4SLinus Torvalds cdi->mask |= CDC_RAM; 923*1da177e4SLinus Torvalds 924*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_MRW_W)) 925*1da177e4SLinus Torvalds ret = cdrom_mrw_open_write(cdi); 926*1da177e4SLinus Torvalds else if (CDROM_CAN(CDC_DVD_RAM)) 927*1da177e4SLinus Torvalds ret = cdrom_dvdram_open_write(cdi); 928*1da177e4SLinus Torvalds else if (CDROM_CAN(CDC_RAM) && 929*1da177e4SLinus Torvalds !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE)) 930*1da177e4SLinus Torvalds ret = cdrom_ram_open_write(cdi); 931*1da177e4SLinus Torvalds else if (CDROM_CAN(CDC_MO_DRIVE)) 932*1da177e4SLinus Torvalds ret = mo_open_write(cdi); 933*1da177e4SLinus Torvalds else if (!cdrom_is_dvd_rw(cdi)) 934*1da177e4SLinus Torvalds ret = 0; 935*1da177e4SLinus Torvalds 936*1da177e4SLinus Torvalds return ret; 937*1da177e4SLinus Torvalds } 938*1da177e4SLinus Torvalds 939*1da177e4SLinus Torvalds static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi) 940*1da177e4SLinus Torvalds { 941*1da177e4SLinus Torvalds struct packet_command cgc; 942*1da177e4SLinus Torvalds 943*1da177e4SLinus Torvalds if (cdi->mmc3_profile != 0x1a) { 944*1da177e4SLinus Torvalds cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name); 945*1da177e4SLinus Torvalds return; 946*1da177e4SLinus Torvalds } 947*1da177e4SLinus Torvalds 948*1da177e4SLinus Torvalds if (!cdi->media_written) { 949*1da177e4SLinus Torvalds cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name); 950*1da177e4SLinus Torvalds return; 951*1da177e4SLinus Torvalds } 952*1da177e4SLinus Torvalds 953*1da177e4SLinus Torvalds printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n", 954*1da177e4SLinus Torvalds cdi->name); 955*1da177e4SLinus Torvalds 956*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 957*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_FLUSH_CACHE; 958*1da177e4SLinus Torvalds cgc.timeout = 30*HZ; 959*1da177e4SLinus Torvalds cdi->ops->generic_packet(cdi, &cgc); 960*1da177e4SLinus Torvalds 961*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 962*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_CLOSE_TRACK; 963*1da177e4SLinus Torvalds cgc.timeout = 3000*HZ; 964*1da177e4SLinus Torvalds cgc.quiet = 1; 965*1da177e4SLinus Torvalds cdi->ops->generic_packet(cdi, &cgc); 966*1da177e4SLinus Torvalds 967*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 968*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_CLOSE_TRACK; 969*1da177e4SLinus Torvalds cgc.cmd[2] = 2; /* Close session */ 970*1da177e4SLinus Torvalds cgc.quiet = 1; 971*1da177e4SLinus Torvalds cgc.timeout = 3000*HZ; 972*1da177e4SLinus Torvalds cdi->ops->generic_packet(cdi, &cgc); 973*1da177e4SLinus Torvalds 974*1da177e4SLinus Torvalds cdi->media_written = 0; 975*1da177e4SLinus Torvalds } 976*1da177e4SLinus Torvalds 977*1da177e4SLinus Torvalds static int cdrom_close_write(struct cdrom_device_info *cdi) 978*1da177e4SLinus Torvalds { 979*1da177e4SLinus Torvalds #if 0 980*1da177e4SLinus Torvalds return cdrom_flush_cache(cdi); 981*1da177e4SLinus Torvalds #else 982*1da177e4SLinus Torvalds return 0; 983*1da177e4SLinus Torvalds #endif 984*1da177e4SLinus Torvalds } 985*1da177e4SLinus Torvalds 986*1da177e4SLinus Torvalds /* We use the open-option O_NONBLOCK to indicate that the 987*1da177e4SLinus Torvalds * purpose of opening is only for subsequent ioctl() calls; no device 988*1da177e4SLinus Torvalds * integrity checks are performed. 989*1da177e4SLinus Torvalds * 990*1da177e4SLinus Torvalds * We hope that all cd-player programs will adopt this convention. It 991*1da177e4SLinus Torvalds * is in their own interest: device control becomes a lot easier 992*1da177e4SLinus Torvalds * this way. 993*1da177e4SLinus Torvalds */ 994*1da177e4SLinus Torvalds int cdrom_open(struct cdrom_device_info *cdi, struct inode *ip, struct file *fp) 995*1da177e4SLinus Torvalds { 996*1da177e4SLinus Torvalds int ret; 997*1da177e4SLinus Torvalds 998*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "entering cdrom_open\n"); 999*1da177e4SLinus Torvalds 1000*1da177e4SLinus Torvalds /* if this was a O_NONBLOCK open and we should honor the flags, 1001*1da177e4SLinus Torvalds * do a quick open without drive/disc integrity checks. */ 1002*1da177e4SLinus Torvalds cdi->use_count++; 1003*1da177e4SLinus Torvalds if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) { 1004*1da177e4SLinus Torvalds ret = cdi->ops->open(cdi, 1); 1005*1da177e4SLinus Torvalds } else { 1006*1da177e4SLinus Torvalds ret = open_for_data(cdi); 1007*1da177e4SLinus Torvalds if (ret) 1008*1da177e4SLinus Torvalds goto err; 1009*1da177e4SLinus Torvalds cdrom_mmc3_profile(cdi); 1010*1da177e4SLinus Torvalds if (fp->f_mode & FMODE_WRITE) { 1011*1da177e4SLinus Torvalds ret = -EROFS; 1012*1da177e4SLinus Torvalds if (cdrom_open_write(cdi)) 1013*1da177e4SLinus Torvalds goto err; 1014*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_RAM)) 1015*1da177e4SLinus Torvalds goto err; 1016*1da177e4SLinus Torvalds ret = 0; 1017*1da177e4SLinus Torvalds cdi->media_written = 0; 1018*1da177e4SLinus Torvalds } 1019*1da177e4SLinus Torvalds } 1020*1da177e4SLinus Torvalds 1021*1da177e4SLinus Torvalds if (ret) 1022*1da177e4SLinus Torvalds goto err; 1023*1da177e4SLinus Torvalds 1024*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", 1025*1da177e4SLinus Torvalds cdi->name, cdi->use_count); 1026*1da177e4SLinus Torvalds /* Do this on open. Don't wait for mount, because they might 1027*1da177e4SLinus Torvalds not be mounting, but opening with O_NONBLOCK */ 1028*1da177e4SLinus Torvalds check_disk_change(ip->i_bdev); 1029*1da177e4SLinus Torvalds return 0; 1030*1da177e4SLinus Torvalds err: 1031*1da177e4SLinus Torvalds cdi->use_count--; 1032*1da177e4SLinus Torvalds return ret; 1033*1da177e4SLinus Torvalds } 1034*1da177e4SLinus Torvalds 1035*1da177e4SLinus Torvalds static 1036*1da177e4SLinus Torvalds int open_for_data(struct cdrom_device_info * cdi) 1037*1da177e4SLinus Torvalds { 1038*1da177e4SLinus Torvalds int ret; 1039*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1040*1da177e4SLinus Torvalds tracktype tracks; 1041*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "entering open_for_data\n"); 1042*1da177e4SLinus Torvalds /* Check if the driver can report drive status. If it can, we 1043*1da177e4SLinus Torvalds can do clever things. If it can't, well, we at least tried! */ 1044*1da177e4SLinus Torvalds if (cdo->drive_status != NULL) { 1045*1da177e4SLinus Torvalds ret = cdo->drive_status(cdi, CDSL_CURRENT); 1046*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "drive_status=%d\n", ret); 1047*1da177e4SLinus Torvalds if (ret == CDS_TRAY_OPEN) { 1048*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "the tray is open...\n"); 1049*1da177e4SLinus Torvalds /* can/may i close it? */ 1050*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_CLOSE_TRAY) && 1051*1da177e4SLinus Torvalds cdi->options & CDO_AUTO_CLOSE) { 1052*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "trying to close the tray.\n"); 1053*1da177e4SLinus Torvalds ret=cdo->tray_move(cdi,0); 1054*1da177e4SLinus Torvalds if (ret) { 1055*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); 1056*1da177e4SLinus Torvalds /* Ignore the error from the low 1057*1da177e4SLinus Torvalds level driver. We don't care why it 1058*1da177e4SLinus Torvalds couldn't close the tray. We only care 1059*1da177e4SLinus Torvalds that there is no disc in the drive, 1060*1da177e4SLinus Torvalds since that is the _REAL_ problem here.*/ 1061*1da177e4SLinus Torvalds ret=-ENOMEDIUM; 1062*1da177e4SLinus Torvalds goto clean_up_and_return; 1063*1da177e4SLinus Torvalds } 1064*1da177e4SLinus Torvalds } else { 1065*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n"); 1066*1da177e4SLinus Torvalds ret=-ENOMEDIUM; 1067*1da177e4SLinus Torvalds goto clean_up_and_return; 1068*1da177e4SLinus Torvalds } 1069*1da177e4SLinus Torvalds /* Ok, the door should be closed now.. Check again */ 1070*1da177e4SLinus Torvalds ret = cdo->drive_status(cdi, CDSL_CURRENT); 1071*1da177e4SLinus Torvalds if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { 1072*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 1073*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "tray might not contain a medium.\n"); 1074*1da177e4SLinus Torvalds ret=-ENOMEDIUM; 1075*1da177e4SLinus Torvalds goto clean_up_and_return; 1076*1da177e4SLinus Torvalds } 1077*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "the tray is now closed.\n"); 1078*1da177e4SLinus Torvalds } 1079*1da177e4SLinus Torvalds /* the door should be closed now, check for the disc */ 1080*1da177e4SLinus Torvalds ret = cdo->drive_status(cdi, CDSL_CURRENT); 1081*1da177e4SLinus Torvalds if (ret!=CDS_DISC_OK) { 1082*1da177e4SLinus Torvalds ret = -ENOMEDIUM; 1083*1da177e4SLinus Torvalds goto clean_up_and_return; 1084*1da177e4SLinus Torvalds } 1085*1da177e4SLinus Torvalds } 1086*1da177e4SLinus Torvalds cdrom_count_tracks(cdi, &tracks); 1087*1da177e4SLinus Torvalds if (tracks.error == CDS_NO_DISC) { 1088*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. no disc.\n"); 1089*1da177e4SLinus Torvalds ret=-ENOMEDIUM; 1090*1da177e4SLinus Torvalds goto clean_up_and_return; 1091*1da177e4SLinus Torvalds } 1092*1da177e4SLinus Torvalds /* CD-Players which don't use O_NONBLOCK, workman 1093*1da177e4SLinus Torvalds * for example, need bit CDO_CHECK_TYPE cleared! */ 1094*1da177e4SLinus Torvalds if (tracks.data==0) { 1095*1da177e4SLinus Torvalds if (cdi->options & CDO_CHECK_TYPE) { 1096*1da177e4SLinus Torvalds /* give people a warning shot, now that CDO_CHECK_TYPE 1097*1da177e4SLinus Torvalds is the default case! */ 1098*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 1099*1da177e4SLinus Torvalds cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", 1100*1da177e4SLinus Torvalds (unsigned int)current->pid); 1101*1da177e4SLinus Torvalds ret=-EMEDIUMTYPE; 1102*1da177e4SLinus Torvalds goto clean_up_and_return; 1103*1da177e4SLinus Torvalds } 1104*1da177e4SLinus Torvalds else { 1105*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n"); 1106*1da177e4SLinus Torvalds } 1107*1da177e4SLinus Torvalds } 1108*1da177e4SLinus Torvalds 1109*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "all seems well, opening the device.\n"); 1110*1da177e4SLinus Torvalds 1111*1da177e4SLinus Torvalds /* all seems well, we can open the device */ 1112*1da177e4SLinus Torvalds ret = cdo->open(cdi, 0); /* open for data */ 1113*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret); 1114*1da177e4SLinus Torvalds /* After all this careful checking, we shouldn't have problems 1115*1da177e4SLinus Torvalds opening the device, but we don't want the device locked if 1116*1da177e4SLinus Torvalds this somehow fails... */ 1117*1da177e4SLinus Torvalds if (ret) { 1118*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "open device failed.\n"); 1119*1da177e4SLinus Torvalds goto clean_up_and_return; 1120*1da177e4SLinus Torvalds } 1121*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) { 1122*1da177e4SLinus Torvalds cdo->lock_door(cdi, 1); 1123*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "door locked.\n"); 1124*1da177e4SLinus Torvalds } 1125*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "device opened successfully.\n"); 1126*1da177e4SLinus Torvalds return ret; 1127*1da177e4SLinus Torvalds 1128*1da177e4SLinus Torvalds /* Something failed. Try to unlock the drive, because some drivers 1129*1da177e4SLinus Torvalds (notably ide-cd) lock the drive after every command. This produced 1130*1da177e4SLinus Torvalds a nasty bug where after mount failed, the drive would remain locked! 1131*1da177e4SLinus Torvalds This ensures that the drive gets unlocked after a mount fails. This 1132*1da177e4SLinus Torvalds is a goto to avoid bloating the driver with redundant code. */ 1133*1da177e4SLinus Torvalds clean_up_and_return: 1134*1da177e4SLinus Torvalds cdinfo(CD_WARNING, "open failed.\n"); 1135*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { 1136*1da177e4SLinus Torvalds cdo->lock_door(cdi, 0); 1137*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "door unlocked.\n"); 1138*1da177e4SLinus Torvalds } 1139*1da177e4SLinus Torvalds return ret; 1140*1da177e4SLinus Torvalds } 1141*1da177e4SLinus Torvalds 1142*1da177e4SLinus Torvalds /* This code is similar to that in open_for_data. The routine is called 1143*1da177e4SLinus Torvalds whenever an audio play operation is requested. 1144*1da177e4SLinus Torvalds */ 1145*1da177e4SLinus Torvalds int check_for_audio_disc(struct cdrom_device_info * cdi, 1146*1da177e4SLinus Torvalds struct cdrom_device_ops * cdo) 1147*1da177e4SLinus Torvalds { 1148*1da177e4SLinus Torvalds int ret; 1149*1da177e4SLinus Torvalds tracktype tracks; 1150*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "entering check_for_audio_disc\n"); 1151*1da177e4SLinus Torvalds if (!(cdi->options & CDO_CHECK_TYPE)) 1152*1da177e4SLinus Torvalds return 0; 1153*1da177e4SLinus Torvalds if (cdo->drive_status != NULL) { 1154*1da177e4SLinus Torvalds ret = cdo->drive_status(cdi, CDSL_CURRENT); 1155*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "drive_status=%d\n", ret); 1156*1da177e4SLinus Torvalds if (ret == CDS_TRAY_OPEN) { 1157*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "the tray is open...\n"); 1158*1da177e4SLinus Torvalds /* can/may i close it? */ 1159*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_CLOSE_TRAY) && 1160*1da177e4SLinus Torvalds cdi->options & CDO_AUTO_CLOSE) { 1161*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "trying to close the tray.\n"); 1162*1da177e4SLinus Torvalds ret=cdo->tray_move(cdi,0); 1163*1da177e4SLinus Torvalds if (ret) { 1164*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); 1165*1da177e4SLinus Torvalds /* Ignore the error from the low 1166*1da177e4SLinus Torvalds level driver. We don't care why it 1167*1da177e4SLinus Torvalds couldn't close the tray. We only care 1168*1da177e4SLinus Torvalds that there is no disc in the drive, 1169*1da177e4SLinus Torvalds since that is the _REAL_ problem here.*/ 1170*1da177e4SLinus Torvalds return -ENOMEDIUM; 1171*1da177e4SLinus Torvalds } 1172*1da177e4SLinus Torvalds } else { 1173*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); 1174*1da177e4SLinus Torvalds return -ENOMEDIUM; 1175*1da177e4SLinus Torvalds } 1176*1da177e4SLinus Torvalds /* Ok, the door should be closed now.. Check again */ 1177*1da177e4SLinus Torvalds ret = cdo->drive_status(cdi, CDSL_CURRENT); 1178*1da177e4SLinus Torvalds if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { 1179*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 1180*1da177e4SLinus Torvalds return -ENOMEDIUM; 1181*1da177e4SLinus Torvalds } 1182*1da177e4SLinus Torvalds if (ret!=CDS_DISC_OK) { 1183*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); 1184*1da177e4SLinus Torvalds return -EIO; 1185*1da177e4SLinus Torvalds } 1186*1da177e4SLinus Torvalds cdinfo(CD_OPEN, "the tray is now closed.\n"); 1187*1da177e4SLinus Torvalds } 1188*1da177e4SLinus Torvalds } 1189*1da177e4SLinus Torvalds cdrom_count_tracks(cdi, &tracks); 1190*1da177e4SLinus Torvalds if (tracks.error) 1191*1da177e4SLinus Torvalds return(tracks.error); 1192*1da177e4SLinus Torvalds 1193*1da177e4SLinus Torvalds if (tracks.audio==0) 1194*1da177e4SLinus Torvalds return -EMEDIUMTYPE; 1195*1da177e4SLinus Torvalds 1196*1da177e4SLinus Torvalds return 0; 1197*1da177e4SLinus Torvalds } 1198*1da177e4SLinus Torvalds 1199*1da177e4SLinus Torvalds /* Admittedly, the logic below could be performed in a nicer way. */ 1200*1da177e4SLinus Torvalds int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) 1201*1da177e4SLinus Torvalds { 1202*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1203*1da177e4SLinus Torvalds int opened_for_data; 1204*1da177e4SLinus Torvalds 1205*1da177e4SLinus Torvalds cdinfo(CD_CLOSE, "entering cdrom_release\n"); 1206*1da177e4SLinus Torvalds 1207*1da177e4SLinus Torvalds if (cdi->use_count > 0) 1208*1da177e4SLinus Torvalds cdi->use_count--; 1209*1da177e4SLinus Torvalds if (cdi->use_count == 0) 1210*1da177e4SLinus Torvalds cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); 1211*1da177e4SLinus Torvalds if (cdi->use_count == 0) 1212*1da177e4SLinus Torvalds cdrom_dvd_rw_close_write(cdi); 1213*1da177e4SLinus Torvalds if (cdi->use_count == 0 && 1214*1da177e4SLinus Torvalds (cdo->capability & CDC_LOCK) && !keeplocked) { 1215*1da177e4SLinus Torvalds cdinfo(CD_CLOSE, "Unlocking door!\n"); 1216*1da177e4SLinus Torvalds cdo->lock_door(cdi, 0); 1217*1da177e4SLinus Torvalds } 1218*1da177e4SLinus Torvalds opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || 1219*1da177e4SLinus Torvalds !(fp && fp->f_flags & O_NONBLOCK); 1220*1da177e4SLinus Torvalds 1221*1da177e4SLinus Torvalds /* 1222*1da177e4SLinus Torvalds * flush cache on last write release 1223*1da177e4SLinus Torvalds */ 1224*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_RAM) && !cdi->use_count && cdi->for_data) 1225*1da177e4SLinus Torvalds cdrom_close_write(cdi); 1226*1da177e4SLinus Torvalds 1227*1da177e4SLinus Torvalds cdo->release(cdi); 1228*1da177e4SLinus Torvalds if (cdi->use_count == 0) { /* last process that closes dev*/ 1229*1da177e4SLinus Torvalds if (opened_for_data && 1230*1da177e4SLinus Torvalds cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) 1231*1da177e4SLinus Torvalds cdo->tray_move(cdi, 1); 1232*1da177e4SLinus Torvalds } 1233*1da177e4SLinus Torvalds return 0; 1234*1da177e4SLinus Torvalds } 1235*1da177e4SLinus Torvalds 1236*1da177e4SLinus Torvalds static int cdrom_read_mech_status(struct cdrom_device_info *cdi, 1237*1da177e4SLinus Torvalds struct cdrom_changer_info *buf) 1238*1da177e4SLinus Torvalds { 1239*1da177e4SLinus Torvalds struct packet_command cgc; 1240*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1241*1da177e4SLinus Torvalds int length; 1242*1da177e4SLinus Torvalds 1243*1da177e4SLinus Torvalds /* 1244*1da177e4SLinus Torvalds * Sanyo changer isn't spec compliant (doesn't use regular change 1245*1da177e4SLinus Torvalds * LOAD_UNLOAD command, and it doesn't implement the mech status 1246*1da177e4SLinus Torvalds * command below 1247*1da177e4SLinus Torvalds */ 1248*1da177e4SLinus Torvalds if (cdi->sanyo_slot) { 1249*1da177e4SLinus Torvalds buf->hdr.nslots = 3; 1250*1da177e4SLinus Torvalds buf->hdr.curslot = cdi->sanyo_slot == 3 ? 0 : cdi->sanyo_slot; 1251*1da177e4SLinus Torvalds for (length = 0; length < 3; length++) { 1252*1da177e4SLinus Torvalds buf->slots[length].disc_present = 1; 1253*1da177e4SLinus Torvalds buf->slots[length].change = 0; 1254*1da177e4SLinus Torvalds } 1255*1da177e4SLinus Torvalds return 0; 1256*1da177e4SLinus Torvalds } 1257*1da177e4SLinus Torvalds 1258*1da177e4SLinus Torvalds length = sizeof(struct cdrom_mechstat_header) + 1259*1da177e4SLinus Torvalds cdi->capacity * sizeof(struct cdrom_slot); 1260*1da177e4SLinus Torvalds 1261*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, length, CGC_DATA_READ); 1262*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_MECHANISM_STATUS; 1263*1da177e4SLinus Torvalds cgc.cmd[8] = (length >> 8) & 0xff; 1264*1da177e4SLinus Torvalds cgc.cmd[9] = length & 0xff; 1265*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 1266*1da177e4SLinus Torvalds } 1267*1da177e4SLinus Torvalds 1268*1da177e4SLinus Torvalds static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot) 1269*1da177e4SLinus Torvalds { 1270*1da177e4SLinus Torvalds struct cdrom_changer_info *info; 1271*1da177e4SLinus Torvalds int ret; 1272*1da177e4SLinus Torvalds 1273*1da177e4SLinus Torvalds cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); 1274*1da177e4SLinus Torvalds if (cdi->sanyo_slot) 1275*1da177e4SLinus Torvalds return CDS_NO_INFO; 1276*1da177e4SLinus Torvalds 1277*1da177e4SLinus Torvalds info = kmalloc(sizeof(*info), GFP_KERNEL); 1278*1da177e4SLinus Torvalds if (!info) 1279*1da177e4SLinus Torvalds return -ENOMEM; 1280*1da177e4SLinus Torvalds 1281*1da177e4SLinus Torvalds if ((ret = cdrom_read_mech_status(cdi, info))) 1282*1da177e4SLinus Torvalds goto out_free; 1283*1da177e4SLinus Torvalds 1284*1da177e4SLinus Torvalds if (info->slots[slot].disc_present) 1285*1da177e4SLinus Torvalds ret = CDS_DISC_OK; 1286*1da177e4SLinus Torvalds else 1287*1da177e4SLinus Torvalds ret = CDS_NO_DISC; 1288*1da177e4SLinus Torvalds 1289*1da177e4SLinus Torvalds out_free: 1290*1da177e4SLinus Torvalds kfree(info); 1291*1da177e4SLinus Torvalds return ret; 1292*1da177e4SLinus Torvalds } 1293*1da177e4SLinus Torvalds 1294*1da177e4SLinus Torvalds /* Return the number of slots for an ATAPI/SCSI cdrom, 1295*1da177e4SLinus Torvalds * return 1 if not a changer. 1296*1da177e4SLinus Torvalds */ 1297*1da177e4SLinus Torvalds int cdrom_number_of_slots(struct cdrom_device_info *cdi) 1298*1da177e4SLinus Torvalds { 1299*1da177e4SLinus Torvalds int status; 1300*1da177e4SLinus Torvalds int nslots = 1; 1301*1da177e4SLinus Torvalds struct cdrom_changer_info *info; 1302*1da177e4SLinus Torvalds 1303*1da177e4SLinus Torvalds cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); 1304*1da177e4SLinus Torvalds /* cdrom_read_mech_status requires a valid value for capacity: */ 1305*1da177e4SLinus Torvalds cdi->capacity = 0; 1306*1da177e4SLinus Torvalds 1307*1da177e4SLinus Torvalds info = kmalloc(sizeof(*info), GFP_KERNEL); 1308*1da177e4SLinus Torvalds if (!info) 1309*1da177e4SLinus Torvalds return -ENOMEM; 1310*1da177e4SLinus Torvalds 1311*1da177e4SLinus Torvalds if ((status = cdrom_read_mech_status(cdi, info)) == 0) 1312*1da177e4SLinus Torvalds nslots = info->hdr.nslots; 1313*1da177e4SLinus Torvalds 1314*1da177e4SLinus Torvalds kfree(info); 1315*1da177e4SLinus Torvalds return nslots; 1316*1da177e4SLinus Torvalds } 1317*1da177e4SLinus Torvalds 1318*1da177e4SLinus Torvalds 1319*1da177e4SLinus Torvalds /* If SLOT < 0, unload the current slot. Otherwise, try to load SLOT. */ 1320*1da177e4SLinus Torvalds static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot) 1321*1da177e4SLinus Torvalds { 1322*1da177e4SLinus Torvalds struct packet_command cgc; 1323*1da177e4SLinus Torvalds 1324*1da177e4SLinus Torvalds cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); 1325*1da177e4SLinus Torvalds if (cdi->sanyo_slot && slot < 0) 1326*1da177e4SLinus Torvalds return 0; 1327*1da177e4SLinus Torvalds 1328*1da177e4SLinus Torvalds init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); 1329*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_LOAD_UNLOAD; 1330*1da177e4SLinus Torvalds cgc.cmd[4] = 2 + (slot >= 0); 1331*1da177e4SLinus Torvalds cgc.cmd[8] = slot; 1332*1da177e4SLinus Torvalds cgc.timeout = 60 * HZ; 1333*1da177e4SLinus Torvalds 1334*1da177e4SLinus Torvalds /* The Sanyo 3 CD changer uses byte 7 of the 1335*1da177e4SLinus Torvalds GPCMD_TEST_UNIT_READY to command to switch CDs instead of 1336*1da177e4SLinus Torvalds using the GPCMD_LOAD_UNLOAD opcode. */ 1337*1da177e4SLinus Torvalds if (cdi->sanyo_slot && -1 < slot) { 1338*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_TEST_UNIT_READY; 1339*1da177e4SLinus Torvalds cgc.cmd[7] = slot; 1340*1da177e4SLinus Torvalds cgc.cmd[4] = cgc.cmd[8] = 0; 1341*1da177e4SLinus Torvalds cdi->sanyo_slot = slot ? slot : 3; 1342*1da177e4SLinus Torvalds } 1343*1da177e4SLinus Torvalds 1344*1da177e4SLinus Torvalds return cdi->ops->generic_packet(cdi, &cgc); 1345*1da177e4SLinus Torvalds } 1346*1da177e4SLinus Torvalds 1347*1da177e4SLinus Torvalds static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot) 1348*1da177e4SLinus Torvalds { 1349*1da177e4SLinus Torvalds struct cdrom_changer_info *info; 1350*1da177e4SLinus Torvalds int curslot; 1351*1da177e4SLinus Torvalds int ret; 1352*1da177e4SLinus Torvalds 1353*1da177e4SLinus Torvalds cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); 1354*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_SELECT_DISC)) 1355*1da177e4SLinus Torvalds return -EDRIVE_CANT_DO_THIS; 1356*1da177e4SLinus Torvalds 1357*1da177e4SLinus Torvalds (void) cdi->ops->media_changed(cdi, slot); 1358*1da177e4SLinus Torvalds 1359*1da177e4SLinus Torvalds if (slot == CDSL_NONE) { 1360*1da177e4SLinus Torvalds /* set media changed bits, on both queues */ 1361*1da177e4SLinus Torvalds cdi->mc_flags = 0x3; 1362*1da177e4SLinus Torvalds return cdrom_load_unload(cdi, -1); 1363*1da177e4SLinus Torvalds } 1364*1da177e4SLinus Torvalds 1365*1da177e4SLinus Torvalds info = kmalloc(sizeof(*info), GFP_KERNEL); 1366*1da177e4SLinus Torvalds if (!info) 1367*1da177e4SLinus Torvalds return -ENOMEM; 1368*1da177e4SLinus Torvalds 1369*1da177e4SLinus Torvalds if ((ret = cdrom_read_mech_status(cdi, info))) { 1370*1da177e4SLinus Torvalds kfree(info); 1371*1da177e4SLinus Torvalds return ret; 1372*1da177e4SLinus Torvalds } 1373*1da177e4SLinus Torvalds 1374*1da177e4SLinus Torvalds curslot = info->hdr.curslot; 1375*1da177e4SLinus Torvalds kfree(info); 1376*1da177e4SLinus Torvalds 1377*1da177e4SLinus Torvalds if (cdi->use_count > 1 || keeplocked) { 1378*1da177e4SLinus Torvalds if (slot == CDSL_CURRENT) { 1379*1da177e4SLinus Torvalds return curslot; 1380*1da177e4SLinus Torvalds } else { 1381*1da177e4SLinus Torvalds return -EBUSY; 1382*1da177e4SLinus Torvalds } 1383*1da177e4SLinus Torvalds } 1384*1da177e4SLinus Torvalds 1385*1da177e4SLinus Torvalds /* Specifying CDSL_CURRENT will attempt to load the currnet slot, 1386*1da177e4SLinus Torvalds which is useful if it had been previously unloaded. 1387*1da177e4SLinus Torvalds Whether it can or not, it returns the current slot. 1388*1da177e4SLinus Torvalds Similarly, if slot happens to be the current one, we still 1389*1da177e4SLinus Torvalds try and load it. */ 1390*1da177e4SLinus Torvalds if (slot == CDSL_CURRENT) 1391*1da177e4SLinus Torvalds slot = curslot; 1392*1da177e4SLinus Torvalds 1393*1da177e4SLinus Torvalds /* set media changed bits on both queues */ 1394*1da177e4SLinus Torvalds cdi->mc_flags = 0x3; 1395*1da177e4SLinus Torvalds if ((ret = cdrom_load_unload(cdi, slot))) 1396*1da177e4SLinus Torvalds return ret; 1397*1da177e4SLinus Torvalds 1398*1da177e4SLinus Torvalds return slot; 1399*1da177e4SLinus Torvalds } 1400*1da177e4SLinus Torvalds 1401*1da177e4SLinus Torvalds /* We want to make media_changed accessible to the user through an 1402*1da177e4SLinus Torvalds * ioctl. The main problem now is that we must double-buffer the 1403*1da177e4SLinus Torvalds * low-level implementation, to assure that the VFS and the user both 1404*1da177e4SLinus Torvalds * see a medium change once. 1405*1da177e4SLinus Torvalds */ 1406*1da177e4SLinus Torvalds 1407*1da177e4SLinus Torvalds static 1408*1da177e4SLinus Torvalds int media_changed(struct cdrom_device_info *cdi, int queue) 1409*1da177e4SLinus Torvalds { 1410*1da177e4SLinus Torvalds unsigned int mask = (1 << (queue & 1)); 1411*1da177e4SLinus Torvalds int ret = !!(cdi->mc_flags & mask); 1412*1da177e4SLinus Torvalds 1413*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 1414*1da177e4SLinus Torvalds return ret; 1415*1da177e4SLinus Torvalds /* changed since last call? */ 1416*1da177e4SLinus Torvalds if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { 1417*1da177e4SLinus Torvalds cdi->mc_flags = 0x3; /* set bit on both queues */ 1418*1da177e4SLinus Torvalds ret |= 1; 1419*1da177e4SLinus Torvalds cdi->media_written = 0; 1420*1da177e4SLinus Torvalds } 1421*1da177e4SLinus Torvalds cdi->mc_flags &= ~mask; /* clear bit */ 1422*1da177e4SLinus Torvalds return ret; 1423*1da177e4SLinus Torvalds } 1424*1da177e4SLinus Torvalds 1425*1da177e4SLinus Torvalds int cdrom_media_changed(struct cdrom_device_info *cdi) 1426*1da177e4SLinus Torvalds { 1427*1da177e4SLinus Torvalds /* This talks to the VFS, which doesn't like errors - just 1 or 0. 1428*1da177e4SLinus Torvalds * Returning "0" is always safe (media hasn't been changed). Do that 1429*1da177e4SLinus Torvalds * if the low-level cdrom driver dosn't support media changed. */ 1430*1da177e4SLinus Torvalds if (cdi == NULL || cdi->ops->media_changed == NULL) 1431*1da177e4SLinus Torvalds return 0; 1432*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 1433*1da177e4SLinus Torvalds return 0; 1434*1da177e4SLinus Torvalds return media_changed(cdi, 0); 1435*1da177e4SLinus Torvalds } 1436*1da177e4SLinus Torvalds 1437*1da177e4SLinus Torvalds /* badly broken, I know. Is due for a fixup anytime. */ 1438*1da177e4SLinus Torvalds static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) 1439*1da177e4SLinus Torvalds { 1440*1da177e4SLinus Torvalds struct cdrom_tochdr header; 1441*1da177e4SLinus Torvalds struct cdrom_tocentry entry; 1442*1da177e4SLinus Torvalds int ret, i; 1443*1da177e4SLinus Torvalds tracks->data=0; 1444*1da177e4SLinus Torvalds tracks->audio=0; 1445*1da177e4SLinus Torvalds tracks->cdi=0; 1446*1da177e4SLinus Torvalds tracks->xa=0; 1447*1da177e4SLinus Torvalds tracks->error=0; 1448*1da177e4SLinus Torvalds cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); 1449*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) { 1450*1da177e4SLinus Torvalds tracks->error=CDS_NO_INFO; 1451*1da177e4SLinus Torvalds return; 1452*1da177e4SLinus Torvalds } 1453*1da177e4SLinus Torvalds /* Grab the TOC header so we can see how many tracks there are */ 1454*1da177e4SLinus Torvalds if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { 1455*1da177e4SLinus Torvalds if (ret == -ENOMEDIUM) 1456*1da177e4SLinus Torvalds tracks->error = CDS_NO_DISC; 1457*1da177e4SLinus Torvalds else 1458*1da177e4SLinus Torvalds tracks->error = CDS_NO_INFO; 1459*1da177e4SLinus Torvalds return; 1460*1da177e4SLinus Torvalds } 1461*1da177e4SLinus Torvalds /* check what type of tracks are on this disc */ 1462*1da177e4SLinus Torvalds entry.cdte_format = CDROM_MSF; 1463*1da177e4SLinus Torvalds for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { 1464*1da177e4SLinus Torvalds entry.cdte_track = i; 1465*1da177e4SLinus Torvalds if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { 1466*1da177e4SLinus Torvalds tracks->error=CDS_NO_INFO; 1467*1da177e4SLinus Torvalds return; 1468*1da177e4SLinus Torvalds } 1469*1da177e4SLinus Torvalds if (entry.cdte_ctrl & CDROM_DATA_TRACK) { 1470*1da177e4SLinus Torvalds if (entry.cdte_format == 0x10) 1471*1da177e4SLinus Torvalds tracks->cdi++; 1472*1da177e4SLinus Torvalds else if (entry.cdte_format == 0x20) 1473*1da177e4SLinus Torvalds tracks->xa++; 1474*1da177e4SLinus Torvalds else 1475*1da177e4SLinus Torvalds tracks->data++; 1476*1da177e4SLinus Torvalds } else 1477*1da177e4SLinus Torvalds tracks->audio++; 1478*1da177e4SLinus Torvalds cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", 1479*1da177e4SLinus Torvalds i, entry.cdte_format, entry.cdte_ctrl); 1480*1da177e4SLinus Torvalds } 1481*1da177e4SLinus Torvalds cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", 1482*1da177e4SLinus Torvalds header.cdth_trk1, tracks->audio, tracks->data, 1483*1da177e4SLinus Torvalds tracks->cdi, tracks->xa); 1484*1da177e4SLinus Torvalds } 1485*1da177e4SLinus Torvalds 1486*1da177e4SLinus Torvalds /* Requests to the low-level drivers will /always/ be done in the 1487*1da177e4SLinus Torvalds following format convention: 1488*1da177e4SLinus Torvalds 1489*1da177e4SLinus Torvalds CDROM_LBA: all data-related requests. 1490*1da177e4SLinus Torvalds CDROM_MSF: all audio-related requests. 1491*1da177e4SLinus Torvalds 1492*1da177e4SLinus Torvalds However, a low-level implementation is allowed to refuse this 1493*1da177e4SLinus Torvalds request, and return information in its own favorite format. 1494*1da177e4SLinus Torvalds 1495*1da177e4SLinus Torvalds It doesn't make sense /at all/ to ask for a play_audio in LBA 1496*1da177e4SLinus Torvalds format, or ask for multi-session info in MSF format. However, for 1497*1da177e4SLinus Torvalds backward compatibility these format requests will be satisfied, but 1498*1da177e4SLinus Torvalds the requests to the low-level drivers will be sanitized in the more 1499*1da177e4SLinus Torvalds meaningful format indicated above. 1500*1da177e4SLinus Torvalds */ 1501*1da177e4SLinus Torvalds 1502*1da177e4SLinus Torvalds static 1503*1da177e4SLinus Torvalds void sanitize_format(union cdrom_addr *addr, 1504*1da177e4SLinus Torvalds u_char * curr, u_char requested) 1505*1da177e4SLinus Torvalds { 1506*1da177e4SLinus Torvalds if (*curr == requested) 1507*1da177e4SLinus Torvalds return; /* nothing to be done! */ 1508*1da177e4SLinus Torvalds if (requested == CDROM_LBA) { 1509*1da177e4SLinus Torvalds addr->lba = (int) addr->msf.frame + 1510*1da177e4SLinus Torvalds 75 * (addr->msf.second - 2 + 60 * addr->msf.minute); 1511*1da177e4SLinus Torvalds } else { /* CDROM_MSF */ 1512*1da177e4SLinus Torvalds int lba = addr->lba; 1513*1da177e4SLinus Torvalds addr->msf.frame = lba % 75; 1514*1da177e4SLinus Torvalds lba /= 75; 1515*1da177e4SLinus Torvalds lba += 2; 1516*1da177e4SLinus Torvalds addr->msf.second = lba % 60; 1517*1da177e4SLinus Torvalds addr->msf.minute = lba / 60; 1518*1da177e4SLinus Torvalds } 1519*1da177e4SLinus Torvalds *curr = requested; 1520*1da177e4SLinus Torvalds } 1521*1da177e4SLinus Torvalds 1522*1da177e4SLinus Torvalds void init_cdrom_command(struct packet_command *cgc, void *buf, int len, 1523*1da177e4SLinus Torvalds int type) 1524*1da177e4SLinus Torvalds { 1525*1da177e4SLinus Torvalds memset(cgc, 0, sizeof(struct packet_command)); 1526*1da177e4SLinus Torvalds if (buf) 1527*1da177e4SLinus Torvalds memset(buf, 0, len); 1528*1da177e4SLinus Torvalds cgc->buffer = (char *) buf; 1529*1da177e4SLinus Torvalds cgc->buflen = len; 1530*1da177e4SLinus Torvalds cgc->data_direction = type; 1531*1da177e4SLinus Torvalds cgc->timeout = 5*HZ; 1532*1da177e4SLinus Torvalds } 1533*1da177e4SLinus Torvalds 1534*1da177e4SLinus Torvalds /* DVD handling */ 1535*1da177e4SLinus Torvalds 1536*1da177e4SLinus Torvalds #define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key)) 1537*1da177e4SLinus Torvalds #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge)) 1538*1da177e4SLinus Torvalds 1539*1da177e4SLinus Torvalds static void setup_report_key(struct packet_command *cgc, unsigned agid, unsigned type) 1540*1da177e4SLinus Torvalds { 1541*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_REPORT_KEY; 1542*1da177e4SLinus Torvalds cgc->cmd[10] = type | (agid << 6); 1543*1da177e4SLinus Torvalds switch (type) { 1544*1da177e4SLinus Torvalds case 0: case 8: case 5: { 1545*1da177e4SLinus Torvalds cgc->buflen = 8; 1546*1da177e4SLinus Torvalds break; 1547*1da177e4SLinus Torvalds } 1548*1da177e4SLinus Torvalds case 1: { 1549*1da177e4SLinus Torvalds cgc->buflen = 16; 1550*1da177e4SLinus Torvalds break; 1551*1da177e4SLinus Torvalds } 1552*1da177e4SLinus Torvalds case 2: case 4: { 1553*1da177e4SLinus Torvalds cgc->buflen = 12; 1554*1da177e4SLinus Torvalds break; 1555*1da177e4SLinus Torvalds } 1556*1da177e4SLinus Torvalds } 1557*1da177e4SLinus Torvalds cgc->cmd[9] = cgc->buflen; 1558*1da177e4SLinus Torvalds cgc->data_direction = CGC_DATA_READ; 1559*1da177e4SLinus Torvalds } 1560*1da177e4SLinus Torvalds 1561*1da177e4SLinus Torvalds static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned type) 1562*1da177e4SLinus Torvalds { 1563*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_SEND_KEY; 1564*1da177e4SLinus Torvalds cgc->cmd[10] = type | (agid << 6); 1565*1da177e4SLinus Torvalds switch (type) { 1566*1da177e4SLinus Torvalds case 1: { 1567*1da177e4SLinus Torvalds cgc->buflen = 16; 1568*1da177e4SLinus Torvalds break; 1569*1da177e4SLinus Torvalds } 1570*1da177e4SLinus Torvalds case 3: { 1571*1da177e4SLinus Torvalds cgc->buflen = 12; 1572*1da177e4SLinus Torvalds break; 1573*1da177e4SLinus Torvalds } 1574*1da177e4SLinus Torvalds case 6: { 1575*1da177e4SLinus Torvalds cgc->buflen = 8; 1576*1da177e4SLinus Torvalds break; 1577*1da177e4SLinus Torvalds } 1578*1da177e4SLinus Torvalds } 1579*1da177e4SLinus Torvalds cgc->cmd[9] = cgc->buflen; 1580*1da177e4SLinus Torvalds cgc->data_direction = CGC_DATA_WRITE; 1581*1da177e4SLinus Torvalds } 1582*1da177e4SLinus Torvalds 1583*1da177e4SLinus Torvalds static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) 1584*1da177e4SLinus Torvalds { 1585*1da177e4SLinus Torvalds int ret; 1586*1da177e4SLinus Torvalds u_char buf[20]; 1587*1da177e4SLinus Torvalds struct packet_command cgc; 1588*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1589*1da177e4SLinus Torvalds rpc_state_t rpc_state; 1590*1da177e4SLinus Torvalds 1591*1da177e4SLinus Torvalds memset(buf, 0, sizeof(buf)); 1592*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); 1593*1da177e4SLinus Torvalds 1594*1da177e4SLinus Torvalds switch (ai->type) { 1595*1da177e4SLinus Torvalds /* LU data send */ 1596*1da177e4SLinus Torvalds case DVD_LU_SEND_AGID: 1597*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); 1598*1da177e4SLinus Torvalds cgc.quiet = 1; 1599*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lsa.agid, 0); 1600*1da177e4SLinus Torvalds 1601*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1602*1da177e4SLinus Torvalds return ret; 1603*1da177e4SLinus Torvalds 1604*1da177e4SLinus Torvalds ai->lsa.agid = buf[7] >> 6; 1605*1da177e4SLinus Torvalds /* Returning data, let host change state */ 1606*1da177e4SLinus Torvalds break; 1607*1da177e4SLinus Torvalds 1608*1da177e4SLinus Torvalds case DVD_LU_SEND_KEY1: 1609*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); 1610*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lsk.agid, 2); 1611*1da177e4SLinus Torvalds 1612*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1613*1da177e4SLinus Torvalds return ret; 1614*1da177e4SLinus Torvalds 1615*1da177e4SLinus Torvalds copy_key(ai->lsk.key, &buf[4]); 1616*1da177e4SLinus Torvalds /* Returning data, let host change state */ 1617*1da177e4SLinus Torvalds break; 1618*1da177e4SLinus Torvalds 1619*1da177e4SLinus Torvalds case DVD_LU_SEND_CHALLENGE: 1620*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); 1621*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lsc.agid, 1); 1622*1da177e4SLinus Torvalds 1623*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1624*1da177e4SLinus Torvalds return ret; 1625*1da177e4SLinus Torvalds 1626*1da177e4SLinus Torvalds copy_chal(ai->lsc.chal, &buf[4]); 1627*1da177e4SLinus Torvalds /* Returning data, let host change state */ 1628*1da177e4SLinus Torvalds break; 1629*1da177e4SLinus Torvalds 1630*1da177e4SLinus Torvalds /* Post-auth key */ 1631*1da177e4SLinus Torvalds case DVD_LU_SEND_TITLE_KEY: 1632*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); 1633*1da177e4SLinus Torvalds cgc.quiet = 1; 1634*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lstk.agid, 4); 1635*1da177e4SLinus Torvalds cgc.cmd[5] = ai->lstk.lba; 1636*1da177e4SLinus Torvalds cgc.cmd[4] = ai->lstk.lba >> 8; 1637*1da177e4SLinus Torvalds cgc.cmd[3] = ai->lstk.lba >> 16; 1638*1da177e4SLinus Torvalds cgc.cmd[2] = ai->lstk.lba >> 24; 1639*1da177e4SLinus Torvalds 1640*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1641*1da177e4SLinus Torvalds return ret; 1642*1da177e4SLinus Torvalds 1643*1da177e4SLinus Torvalds ai->lstk.cpm = (buf[4] >> 7) & 1; 1644*1da177e4SLinus Torvalds ai->lstk.cp_sec = (buf[4] >> 6) & 1; 1645*1da177e4SLinus Torvalds ai->lstk.cgms = (buf[4] >> 4) & 3; 1646*1da177e4SLinus Torvalds copy_key(ai->lstk.title_key, &buf[5]); 1647*1da177e4SLinus Torvalds /* Returning data, let host change state */ 1648*1da177e4SLinus Torvalds break; 1649*1da177e4SLinus Torvalds 1650*1da177e4SLinus Torvalds case DVD_LU_SEND_ASF: 1651*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); 1652*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lsasf.agid, 5); 1653*1da177e4SLinus Torvalds 1654*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1655*1da177e4SLinus Torvalds return ret; 1656*1da177e4SLinus Torvalds 1657*1da177e4SLinus Torvalds ai->lsasf.asf = buf[7] & 1; 1658*1da177e4SLinus Torvalds break; 1659*1da177e4SLinus Torvalds 1660*1da177e4SLinus Torvalds /* LU data receive (LU changes state) */ 1661*1da177e4SLinus Torvalds case DVD_HOST_SEND_CHALLENGE: 1662*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); 1663*1da177e4SLinus Torvalds setup_send_key(&cgc, ai->hsc.agid, 1); 1664*1da177e4SLinus Torvalds buf[1] = 0xe; 1665*1da177e4SLinus Torvalds copy_chal(&buf[4], ai->hsc.chal); 1666*1da177e4SLinus Torvalds 1667*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1668*1da177e4SLinus Torvalds return ret; 1669*1da177e4SLinus Torvalds 1670*1da177e4SLinus Torvalds ai->type = DVD_LU_SEND_KEY1; 1671*1da177e4SLinus Torvalds break; 1672*1da177e4SLinus Torvalds 1673*1da177e4SLinus Torvalds case DVD_HOST_SEND_KEY2: 1674*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); 1675*1da177e4SLinus Torvalds setup_send_key(&cgc, ai->hsk.agid, 3); 1676*1da177e4SLinus Torvalds buf[1] = 0xa; 1677*1da177e4SLinus Torvalds copy_key(&buf[4], ai->hsk.key); 1678*1da177e4SLinus Torvalds 1679*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) { 1680*1da177e4SLinus Torvalds ai->type = DVD_AUTH_FAILURE; 1681*1da177e4SLinus Torvalds return ret; 1682*1da177e4SLinus Torvalds } 1683*1da177e4SLinus Torvalds ai->type = DVD_AUTH_ESTABLISHED; 1684*1da177e4SLinus Torvalds break; 1685*1da177e4SLinus Torvalds 1686*1da177e4SLinus Torvalds /* Misc */ 1687*1da177e4SLinus Torvalds case DVD_INVALIDATE_AGID: 1688*1da177e4SLinus Torvalds cgc.quiet = 1; 1689*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 1690*1da177e4SLinus Torvalds setup_report_key(&cgc, ai->lsa.agid, 0x3f); 1691*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1692*1da177e4SLinus Torvalds return ret; 1693*1da177e4SLinus Torvalds break; 1694*1da177e4SLinus Torvalds 1695*1da177e4SLinus Torvalds /* Get region settings */ 1696*1da177e4SLinus Torvalds case DVD_LU_SEND_RPC_STATE: 1697*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); 1698*1da177e4SLinus Torvalds setup_report_key(&cgc, 0, 8); 1699*1da177e4SLinus Torvalds memset(&rpc_state, 0, sizeof(rpc_state_t)); 1700*1da177e4SLinus Torvalds cgc.buffer = (char *) &rpc_state; 1701*1da177e4SLinus Torvalds 1702*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1703*1da177e4SLinus Torvalds return ret; 1704*1da177e4SLinus Torvalds 1705*1da177e4SLinus Torvalds ai->lrpcs.type = rpc_state.type_code; 1706*1da177e4SLinus Torvalds ai->lrpcs.vra = rpc_state.vra; 1707*1da177e4SLinus Torvalds ai->lrpcs.ucca = rpc_state.ucca; 1708*1da177e4SLinus Torvalds ai->lrpcs.region_mask = rpc_state.region_mask; 1709*1da177e4SLinus Torvalds ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; 1710*1da177e4SLinus Torvalds break; 1711*1da177e4SLinus Torvalds 1712*1da177e4SLinus Torvalds /* Set region settings */ 1713*1da177e4SLinus Torvalds case DVD_HOST_SEND_RPC_STATE: 1714*1da177e4SLinus Torvalds cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); 1715*1da177e4SLinus Torvalds setup_send_key(&cgc, 0, 6); 1716*1da177e4SLinus Torvalds buf[1] = 6; 1717*1da177e4SLinus Torvalds buf[4] = ai->hrpcs.pdrc; 1718*1da177e4SLinus Torvalds 1719*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1720*1da177e4SLinus Torvalds return ret; 1721*1da177e4SLinus Torvalds break; 1722*1da177e4SLinus Torvalds 1723*1da177e4SLinus Torvalds default: 1724*1da177e4SLinus Torvalds cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); 1725*1da177e4SLinus Torvalds return -ENOTTY; 1726*1da177e4SLinus Torvalds } 1727*1da177e4SLinus Torvalds 1728*1da177e4SLinus Torvalds return 0; 1729*1da177e4SLinus Torvalds } 1730*1da177e4SLinus Torvalds 1731*1da177e4SLinus Torvalds static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) 1732*1da177e4SLinus Torvalds { 1733*1da177e4SLinus Torvalds unsigned char buf[21], *base; 1734*1da177e4SLinus Torvalds struct dvd_layer *layer; 1735*1da177e4SLinus Torvalds struct packet_command cgc; 1736*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1737*1da177e4SLinus Torvalds int ret, layer_num = s->physical.layer_num; 1738*1da177e4SLinus Torvalds 1739*1da177e4SLinus Torvalds if (layer_num >= DVD_LAYERS) 1740*1da177e4SLinus Torvalds return -EINVAL; 1741*1da177e4SLinus Torvalds 1742*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); 1743*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; 1744*1da177e4SLinus Torvalds cgc.cmd[6] = layer_num; 1745*1da177e4SLinus Torvalds cgc.cmd[7] = s->type; 1746*1da177e4SLinus Torvalds cgc.cmd[9] = cgc.buflen & 0xff; 1747*1da177e4SLinus Torvalds 1748*1da177e4SLinus Torvalds /* 1749*1da177e4SLinus Torvalds * refrain from reporting errors on non-existing layers (mainly) 1750*1da177e4SLinus Torvalds */ 1751*1da177e4SLinus Torvalds cgc.quiet = 1; 1752*1da177e4SLinus Torvalds 1753*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1754*1da177e4SLinus Torvalds return ret; 1755*1da177e4SLinus Torvalds 1756*1da177e4SLinus Torvalds base = &buf[4]; 1757*1da177e4SLinus Torvalds layer = &s->physical.layer[layer_num]; 1758*1da177e4SLinus Torvalds 1759*1da177e4SLinus Torvalds /* 1760*1da177e4SLinus Torvalds * place the data... really ugly, but at least we won't have to 1761*1da177e4SLinus Torvalds * worry about endianess in userspace. 1762*1da177e4SLinus Torvalds */ 1763*1da177e4SLinus Torvalds memset(layer, 0, sizeof(*layer)); 1764*1da177e4SLinus Torvalds layer->book_version = base[0] & 0xf; 1765*1da177e4SLinus Torvalds layer->book_type = base[0] >> 4; 1766*1da177e4SLinus Torvalds layer->min_rate = base[1] & 0xf; 1767*1da177e4SLinus Torvalds layer->disc_size = base[1] >> 4; 1768*1da177e4SLinus Torvalds layer->layer_type = base[2] & 0xf; 1769*1da177e4SLinus Torvalds layer->track_path = (base[2] >> 4) & 1; 1770*1da177e4SLinus Torvalds layer->nlayers = (base[2] >> 5) & 3; 1771*1da177e4SLinus Torvalds layer->track_density = base[3] & 0xf; 1772*1da177e4SLinus Torvalds layer->linear_density = base[3] >> 4; 1773*1da177e4SLinus Torvalds layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; 1774*1da177e4SLinus Torvalds layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; 1775*1da177e4SLinus Torvalds layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; 1776*1da177e4SLinus Torvalds layer->bca = base[16] >> 7; 1777*1da177e4SLinus Torvalds 1778*1da177e4SLinus Torvalds return 0; 1779*1da177e4SLinus Torvalds } 1780*1da177e4SLinus Torvalds 1781*1da177e4SLinus Torvalds static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) 1782*1da177e4SLinus Torvalds { 1783*1da177e4SLinus Torvalds int ret; 1784*1da177e4SLinus Torvalds u_char buf[8]; 1785*1da177e4SLinus Torvalds struct packet_command cgc; 1786*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1787*1da177e4SLinus Torvalds 1788*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); 1789*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; 1790*1da177e4SLinus Torvalds cgc.cmd[6] = s->copyright.layer_num; 1791*1da177e4SLinus Torvalds cgc.cmd[7] = s->type; 1792*1da177e4SLinus Torvalds cgc.cmd[8] = cgc.buflen >> 8; 1793*1da177e4SLinus Torvalds cgc.cmd[9] = cgc.buflen & 0xff; 1794*1da177e4SLinus Torvalds 1795*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1796*1da177e4SLinus Torvalds return ret; 1797*1da177e4SLinus Torvalds 1798*1da177e4SLinus Torvalds s->copyright.cpst = buf[4]; 1799*1da177e4SLinus Torvalds s->copyright.rmi = buf[5]; 1800*1da177e4SLinus Torvalds 1801*1da177e4SLinus Torvalds return 0; 1802*1da177e4SLinus Torvalds } 1803*1da177e4SLinus Torvalds 1804*1da177e4SLinus Torvalds static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) 1805*1da177e4SLinus Torvalds { 1806*1da177e4SLinus Torvalds int ret, size; 1807*1da177e4SLinus Torvalds u_char *buf; 1808*1da177e4SLinus Torvalds struct packet_command cgc; 1809*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1810*1da177e4SLinus Torvalds 1811*1da177e4SLinus Torvalds size = sizeof(s->disckey.value) + 4; 1812*1da177e4SLinus Torvalds 1813*1da177e4SLinus Torvalds if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) 1814*1da177e4SLinus Torvalds return -ENOMEM; 1815*1da177e4SLinus Torvalds 1816*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); 1817*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; 1818*1da177e4SLinus Torvalds cgc.cmd[7] = s->type; 1819*1da177e4SLinus Torvalds cgc.cmd[8] = size >> 8; 1820*1da177e4SLinus Torvalds cgc.cmd[9] = size & 0xff; 1821*1da177e4SLinus Torvalds cgc.cmd[10] = s->disckey.agid << 6; 1822*1da177e4SLinus Torvalds 1823*1da177e4SLinus Torvalds if (!(ret = cdo->generic_packet(cdi, &cgc))) 1824*1da177e4SLinus Torvalds memcpy(s->disckey.value, &buf[4], sizeof(s->disckey.value)); 1825*1da177e4SLinus Torvalds 1826*1da177e4SLinus Torvalds kfree(buf); 1827*1da177e4SLinus Torvalds return ret; 1828*1da177e4SLinus Torvalds } 1829*1da177e4SLinus Torvalds 1830*1da177e4SLinus Torvalds static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) 1831*1da177e4SLinus Torvalds { 1832*1da177e4SLinus Torvalds int ret; 1833*1da177e4SLinus Torvalds u_char buf[4 + 188]; 1834*1da177e4SLinus Torvalds struct packet_command cgc; 1835*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1836*1da177e4SLinus Torvalds 1837*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); 1838*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; 1839*1da177e4SLinus Torvalds cgc.cmd[7] = s->type; 1840*1da177e4SLinus Torvalds cgc.cmd[9] = cgc.buflen = 0xff; 1841*1da177e4SLinus Torvalds 1842*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1843*1da177e4SLinus Torvalds return ret; 1844*1da177e4SLinus Torvalds 1845*1da177e4SLinus Torvalds s->bca.len = buf[0] << 8 | buf[1]; 1846*1da177e4SLinus Torvalds if (s->bca.len < 12 || s->bca.len > 188) { 1847*1da177e4SLinus Torvalds cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); 1848*1da177e4SLinus Torvalds return -EIO; 1849*1da177e4SLinus Torvalds } 1850*1da177e4SLinus Torvalds memcpy(s->bca.value, &buf[4], s->bca.len); 1851*1da177e4SLinus Torvalds 1852*1da177e4SLinus Torvalds return 0; 1853*1da177e4SLinus Torvalds } 1854*1da177e4SLinus Torvalds 1855*1da177e4SLinus Torvalds static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) 1856*1da177e4SLinus Torvalds { 1857*1da177e4SLinus Torvalds int ret = 0, size; 1858*1da177e4SLinus Torvalds u_char *buf; 1859*1da177e4SLinus Torvalds struct packet_command cgc; 1860*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1861*1da177e4SLinus Torvalds 1862*1da177e4SLinus Torvalds size = sizeof(s->manufact.value) + 4; 1863*1da177e4SLinus Torvalds 1864*1da177e4SLinus Torvalds if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL) 1865*1da177e4SLinus Torvalds return -ENOMEM; 1866*1da177e4SLinus Torvalds 1867*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buf, size, CGC_DATA_READ); 1868*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; 1869*1da177e4SLinus Torvalds cgc.cmd[7] = s->type; 1870*1da177e4SLinus Torvalds cgc.cmd[8] = size >> 8; 1871*1da177e4SLinus Torvalds cgc.cmd[9] = size & 0xff; 1872*1da177e4SLinus Torvalds 1873*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) { 1874*1da177e4SLinus Torvalds kfree(buf); 1875*1da177e4SLinus Torvalds return ret; 1876*1da177e4SLinus Torvalds } 1877*1da177e4SLinus Torvalds 1878*1da177e4SLinus Torvalds s->manufact.len = buf[0] << 8 | buf[1]; 1879*1da177e4SLinus Torvalds if (s->manufact.len < 0 || s->manufact.len > 2048) { 1880*1da177e4SLinus Torvalds cdinfo(CD_WARNING, "Received invalid manufacture info length" 1881*1da177e4SLinus Torvalds " (%d)\n", s->manufact.len); 1882*1da177e4SLinus Torvalds ret = -EIO; 1883*1da177e4SLinus Torvalds } else { 1884*1da177e4SLinus Torvalds memcpy(s->manufact.value, &buf[4], s->manufact.len); 1885*1da177e4SLinus Torvalds } 1886*1da177e4SLinus Torvalds 1887*1da177e4SLinus Torvalds kfree(buf); 1888*1da177e4SLinus Torvalds return ret; 1889*1da177e4SLinus Torvalds } 1890*1da177e4SLinus Torvalds 1891*1da177e4SLinus Torvalds static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s) 1892*1da177e4SLinus Torvalds { 1893*1da177e4SLinus Torvalds switch (s->type) { 1894*1da177e4SLinus Torvalds case DVD_STRUCT_PHYSICAL: 1895*1da177e4SLinus Torvalds return dvd_read_physical(cdi, s); 1896*1da177e4SLinus Torvalds 1897*1da177e4SLinus Torvalds case DVD_STRUCT_COPYRIGHT: 1898*1da177e4SLinus Torvalds return dvd_read_copyright(cdi, s); 1899*1da177e4SLinus Torvalds 1900*1da177e4SLinus Torvalds case DVD_STRUCT_DISCKEY: 1901*1da177e4SLinus Torvalds return dvd_read_disckey(cdi, s); 1902*1da177e4SLinus Torvalds 1903*1da177e4SLinus Torvalds case DVD_STRUCT_BCA: 1904*1da177e4SLinus Torvalds return dvd_read_bca(cdi, s); 1905*1da177e4SLinus Torvalds 1906*1da177e4SLinus Torvalds case DVD_STRUCT_MANUFACT: 1907*1da177e4SLinus Torvalds return dvd_read_manufact(cdi, s); 1908*1da177e4SLinus Torvalds 1909*1da177e4SLinus Torvalds default: 1910*1da177e4SLinus Torvalds cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", 1911*1da177e4SLinus Torvalds s->type); 1912*1da177e4SLinus Torvalds return -EINVAL; 1913*1da177e4SLinus Torvalds } 1914*1da177e4SLinus Torvalds } 1915*1da177e4SLinus Torvalds 1916*1da177e4SLinus Torvalds int cdrom_mode_sense(struct cdrom_device_info *cdi, 1917*1da177e4SLinus Torvalds struct packet_command *cgc, 1918*1da177e4SLinus Torvalds int page_code, int page_control) 1919*1da177e4SLinus Torvalds { 1920*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1921*1da177e4SLinus Torvalds 1922*1da177e4SLinus Torvalds memset(cgc->cmd, 0, sizeof(cgc->cmd)); 1923*1da177e4SLinus Torvalds 1924*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_MODE_SENSE_10; 1925*1da177e4SLinus Torvalds cgc->cmd[2] = page_code | (page_control << 6); 1926*1da177e4SLinus Torvalds cgc->cmd[7] = cgc->buflen >> 8; 1927*1da177e4SLinus Torvalds cgc->cmd[8] = cgc->buflen & 0xff; 1928*1da177e4SLinus Torvalds cgc->data_direction = CGC_DATA_READ; 1929*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, cgc); 1930*1da177e4SLinus Torvalds } 1931*1da177e4SLinus Torvalds 1932*1da177e4SLinus Torvalds int cdrom_mode_select(struct cdrom_device_info *cdi, 1933*1da177e4SLinus Torvalds struct packet_command *cgc) 1934*1da177e4SLinus Torvalds { 1935*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1936*1da177e4SLinus Torvalds 1937*1da177e4SLinus Torvalds memset(cgc->cmd, 0, sizeof(cgc->cmd)); 1938*1da177e4SLinus Torvalds memset(cgc->buffer, 0, 2); 1939*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_MODE_SELECT_10; 1940*1da177e4SLinus Torvalds cgc->cmd[1] = 0x10; /* PF */ 1941*1da177e4SLinus Torvalds cgc->cmd[7] = cgc->buflen >> 8; 1942*1da177e4SLinus Torvalds cgc->cmd[8] = cgc->buflen & 0xff; 1943*1da177e4SLinus Torvalds cgc->data_direction = CGC_DATA_WRITE; 1944*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, cgc); 1945*1da177e4SLinus Torvalds } 1946*1da177e4SLinus Torvalds 1947*1da177e4SLinus Torvalds static int cdrom_read_subchannel(struct cdrom_device_info *cdi, 1948*1da177e4SLinus Torvalds struct cdrom_subchnl *subchnl, int mcn) 1949*1da177e4SLinus Torvalds { 1950*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1951*1da177e4SLinus Torvalds struct packet_command cgc; 1952*1da177e4SLinus Torvalds char buffer[32]; 1953*1da177e4SLinus Torvalds int ret; 1954*1da177e4SLinus Torvalds 1955*1da177e4SLinus Torvalds init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); 1956*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; 1957*1da177e4SLinus Torvalds cgc.cmd[1] = 2; /* MSF addressing */ 1958*1da177e4SLinus Torvalds cgc.cmd[2] = 0x40; /* request subQ data */ 1959*1da177e4SLinus Torvalds cgc.cmd[3] = mcn ? 2 : 1; 1960*1da177e4SLinus Torvalds cgc.cmd[8] = 16; 1961*1da177e4SLinus Torvalds 1962*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 1963*1da177e4SLinus Torvalds return ret; 1964*1da177e4SLinus Torvalds 1965*1da177e4SLinus Torvalds subchnl->cdsc_audiostatus = cgc.buffer[1]; 1966*1da177e4SLinus Torvalds subchnl->cdsc_format = CDROM_MSF; 1967*1da177e4SLinus Torvalds subchnl->cdsc_ctrl = cgc.buffer[5] & 0xf; 1968*1da177e4SLinus Torvalds subchnl->cdsc_trk = cgc.buffer[6]; 1969*1da177e4SLinus Torvalds subchnl->cdsc_ind = cgc.buffer[7]; 1970*1da177e4SLinus Torvalds 1971*1da177e4SLinus Torvalds subchnl->cdsc_reladdr.msf.minute = cgc.buffer[13]; 1972*1da177e4SLinus Torvalds subchnl->cdsc_reladdr.msf.second = cgc.buffer[14]; 1973*1da177e4SLinus Torvalds subchnl->cdsc_reladdr.msf.frame = cgc.buffer[15]; 1974*1da177e4SLinus Torvalds subchnl->cdsc_absaddr.msf.minute = cgc.buffer[9]; 1975*1da177e4SLinus Torvalds subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; 1976*1da177e4SLinus Torvalds subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; 1977*1da177e4SLinus Torvalds 1978*1da177e4SLinus Torvalds return 0; 1979*1da177e4SLinus Torvalds } 1980*1da177e4SLinus Torvalds 1981*1da177e4SLinus Torvalds /* 1982*1da177e4SLinus Torvalds * Specific READ_10 interface 1983*1da177e4SLinus Torvalds */ 1984*1da177e4SLinus Torvalds static int cdrom_read_cd(struct cdrom_device_info *cdi, 1985*1da177e4SLinus Torvalds struct packet_command *cgc, int lba, 1986*1da177e4SLinus Torvalds int blocksize, int nblocks) 1987*1da177e4SLinus Torvalds { 1988*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 1989*1da177e4SLinus Torvalds 1990*1da177e4SLinus Torvalds memset(&cgc->cmd, 0, sizeof(cgc->cmd)); 1991*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_READ_10; 1992*1da177e4SLinus Torvalds cgc->cmd[2] = (lba >> 24) & 0xff; 1993*1da177e4SLinus Torvalds cgc->cmd[3] = (lba >> 16) & 0xff; 1994*1da177e4SLinus Torvalds cgc->cmd[4] = (lba >> 8) & 0xff; 1995*1da177e4SLinus Torvalds cgc->cmd[5] = lba & 0xff; 1996*1da177e4SLinus Torvalds cgc->cmd[6] = (nblocks >> 16) & 0xff; 1997*1da177e4SLinus Torvalds cgc->cmd[7] = (nblocks >> 8) & 0xff; 1998*1da177e4SLinus Torvalds cgc->cmd[8] = nblocks & 0xff; 1999*1da177e4SLinus Torvalds cgc->buflen = blocksize * nblocks; 2000*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, cgc); 2001*1da177e4SLinus Torvalds } 2002*1da177e4SLinus Torvalds 2003*1da177e4SLinus Torvalds /* very generic interface for reading the various types of blocks */ 2004*1da177e4SLinus Torvalds static int cdrom_read_block(struct cdrom_device_info *cdi, 2005*1da177e4SLinus Torvalds struct packet_command *cgc, 2006*1da177e4SLinus Torvalds int lba, int nblocks, int format, int blksize) 2007*1da177e4SLinus Torvalds { 2008*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2009*1da177e4SLinus Torvalds 2010*1da177e4SLinus Torvalds memset(&cgc->cmd, 0, sizeof(cgc->cmd)); 2011*1da177e4SLinus Torvalds cgc->cmd[0] = GPCMD_READ_CD; 2012*1da177e4SLinus Torvalds /* expected sector size - cdda,mode1,etc. */ 2013*1da177e4SLinus Torvalds cgc->cmd[1] = format << 2; 2014*1da177e4SLinus Torvalds /* starting address */ 2015*1da177e4SLinus Torvalds cgc->cmd[2] = (lba >> 24) & 0xff; 2016*1da177e4SLinus Torvalds cgc->cmd[3] = (lba >> 16) & 0xff; 2017*1da177e4SLinus Torvalds cgc->cmd[4] = (lba >> 8) & 0xff; 2018*1da177e4SLinus Torvalds cgc->cmd[5] = lba & 0xff; 2019*1da177e4SLinus Torvalds /* number of blocks */ 2020*1da177e4SLinus Torvalds cgc->cmd[6] = (nblocks >> 16) & 0xff; 2021*1da177e4SLinus Torvalds cgc->cmd[7] = (nblocks >> 8) & 0xff; 2022*1da177e4SLinus Torvalds cgc->cmd[8] = nblocks & 0xff; 2023*1da177e4SLinus Torvalds cgc->buflen = blksize * nblocks; 2024*1da177e4SLinus Torvalds 2025*1da177e4SLinus Torvalds /* set the header info returned */ 2026*1da177e4SLinus Torvalds switch (blksize) { 2027*1da177e4SLinus Torvalds case CD_FRAMESIZE_RAW0 : cgc->cmd[9] = 0x58; break; 2028*1da177e4SLinus Torvalds case CD_FRAMESIZE_RAW1 : cgc->cmd[9] = 0x78; break; 2029*1da177e4SLinus Torvalds case CD_FRAMESIZE_RAW : cgc->cmd[9] = 0xf8; break; 2030*1da177e4SLinus Torvalds default : cgc->cmd[9] = 0x10; 2031*1da177e4SLinus Torvalds } 2032*1da177e4SLinus Torvalds 2033*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, cgc); 2034*1da177e4SLinus Torvalds } 2035*1da177e4SLinus Torvalds 2036*1da177e4SLinus Torvalds static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, 2037*1da177e4SLinus Torvalds int lba, int nframes) 2038*1da177e4SLinus Torvalds { 2039*1da177e4SLinus Torvalds struct packet_command cgc; 2040*1da177e4SLinus Torvalds int ret = 0; 2041*1da177e4SLinus Torvalds int nr; 2042*1da177e4SLinus Torvalds 2043*1da177e4SLinus Torvalds cdi->last_sense = 0; 2044*1da177e4SLinus Torvalds 2045*1da177e4SLinus Torvalds memset(&cgc, 0, sizeof(cgc)); 2046*1da177e4SLinus Torvalds 2047*1da177e4SLinus Torvalds /* 2048*1da177e4SLinus Torvalds * start with will ra.nframes size, back down if alloc fails 2049*1da177e4SLinus Torvalds */ 2050*1da177e4SLinus Torvalds nr = nframes; 2051*1da177e4SLinus Torvalds do { 2052*1da177e4SLinus Torvalds cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); 2053*1da177e4SLinus Torvalds if (cgc.buffer) 2054*1da177e4SLinus Torvalds break; 2055*1da177e4SLinus Torvalds 2056*1da177e4SLinus Torvalds nr >>= 1; 2057*1da177e4SLinus Torvalds } while (nr); 2058*1da177e4SLinus Torvalds 2059*1da177e4SLinus Torvalds if (!nr) 2060*1da177e4SLinus Torvalds return -ENOMEM; 2061*1da177e4SLinus Torvalds 2062*1da177e4SLinus Torvalds if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { 2063*1da177e4SLinus Torvalds ret = -EFAULT; 2064*1da177e4SLinus Torvalds goto out; 2065*1da177e4SLinus Torvalds } 2066*1da177e4SLinus Torvalds 2067*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_READ; 2068*1da177e4SLinus Torvalds while (nframes > 0) { 2069*1da177e4SLinus Torvalds if (nr > nframes) 2070*1da177e4SLinus Torvalds nr = nframes; 2071*1da177e4SLinus Torvalds 2072*1da177e4SLinus Torvalds ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); 2073*1da177e4SLinus Torvalds if (ret) 2074*1da177e4SLinus Torvalds break; 2075*1da177e4SLinus Torvalds if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { 2076*1da177e4SLinus Torvalds ret = -EFAULT; 2077*1da177e4SLinus Torvalds break; 2078*1da177e4SLinus Torvalds } 2079*1da177e4SLinus Torvalds ubuf += CD_FRAMESIZE_RAW * nr; 2080*1da177e4SLinus Torvalds nframes -= nr; 2081*1da177e4SLinus Torvalds lba += nr; 2082*1da177e4SLinus Torvalds } 2083*1da177e4SLinus Torvalds out: 2084*1da177e4SLinus Torvalds kfree(cgc.buffer); 2085*1da177e4SLinus Torvalds return ret; 2086*1da177e4SLinus Torvalds } 2087*1da177e4SLinus Torvalds 2088*1da177e4SLinus Torvalds static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, 2089*1da177e4SLinus Torvalds int lba, int nframes) 2090*1da177e4SLinus Torvalds { 2091*1da177e4SLinus Torvalds request_queue_t *q = cdi->disk->queue; 2092*1da177e4SLinus Torvalds struct request *rq; 2093*1da177e4SLinus Torvalds struct bio *bio; 2094*1da177e4SLinus Torvalds unsigned int len; 2095*1da177e4SLinus Torvalds int nr, ret = 0; 2096*1da177e4SLinus Torvalds 2097*1da177e4SLinus Torvalds if (!q) 2098*1da177e4SLinus Torvalds return -ENXIO; 2099*1da177e4SLinus Torvalds 2100*1da177e4SLinus Torvalds cdi->last_sense = 0; 2101*1da177e4SLinus Torvalds 2102*1da177e4SLinus Torvalds while (nframes) { 2103*1da177e4SLinus Torvalds nr = nframes; 2104*1da177e4SLinus Torvalds if (cdi->cdda_method == CDDA_BPC_SINGLE) 2105*1da177e4SLinus Torvalds nr = 1; 2106*1da177e4SLinus Torvalds if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9)) 2107*1da177e4SLinus Torvalds nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW; 2108*1da177e4SLinus Torvalds 2109*1da177e4SLinus Torvalds len = nr * CD_FRAMESIZE_RAW; 2110*1da177e4SLinus Torvalds 2111*1da177e4SLinus Torvalds rq = blk_rq_map_user(q, READ, ubuf, len); 2112*1da177e4SLinus Torvalds if (IS_ERR(rq)) 2113*1da177e4SLinus Torvalds return PTR_ERR(rq); 2114*1da177e4SLinus Torvalds 2115*1da177e4SLinus Torvalds memset(rq->cmd, 0, sizeof(rq->cmd)); 2116*1da177e4SLinus Torvalds rq->cmd[0] = GPCMD_READ_CD; 2117*1da177e4SLinus Torvalds rq->cmd[1] = 1 << 2; 2118*1da177e4SLinus Torvalds rq->cmd[2] = (lba >> 24) & 0xff; 2119*1da177e4SLinus Torvalds rq->cmd[3] = (lba >> 16) & 0xff; 2120*1da177e4SLinus Torvalds rq->cmd[4] = (lba >> 8) & 0xff; 2121*1da177e4SLinus Torvalds rq->cmd[5] = lba & 0xff; 2122*1da177e4SLinus Torvalds rq->cmd[6] = (nr >> 16) & 0xff; 2123*1da177e4SLinus Torvalds rq->cmd[7] = (nr >> 8) & 0xff; 2124*1da177e4SLinus Torvalds rq->cmd[8] = nr & 0xff; 2125*1da177e4SLinus Torvalds rq->cmd[9] = 0xf8; 2126*1da177e4SLinus Torvalds 2127*1da177e4SLinus Torvalds rq->cmd_len = 12; 2128*1da177e4SLinus Torvalds rq->flags |= REQ_BLOCK_PC; 2129*1da177e4SLinus Torvalds rq->timeout = 60 * HZ; 2130*1da177e4SLinus Torvalds bio = rq->bio; 2131*1da177e4SLinus Torvalds 2132*1da177e4SLinus Torvalds if (rq->bio) 2133*1da177e4SLinus Torvalds blk_queue_bounce(q, &rq->bio); 2134*1da177e4SLinus Torvalds 2135*1da177e4SLinus Torvalds if (blk_execute_rq(q, cdi->disk, rq)) { 2136*1da177e4SLinus Torvalds struct request_sense *s = rq->sense; 2137*1da177e4SLinus Torvalds ret = -EIO; 2138*1da177e4SLinus Torvalds cdi->last_sense = s->sense_key; 2139*1da177e4SLinus Torvalds } 2140*1da177e4SLinus Torvalds 2141*1da177e4SLinus Torvalds if (blk_rq_unmap_user(rq, bio, len)) 2142*1da177e4SLinus Torvalds ret = -EFAULT; 2143*1da177e4SLinus Torvalds 2144*1da177e4SLinus Torvalds if (ret) 2145*1da177e4SLinus Torvalds break; 2146*1da177e4SLinus Torvalds 2147*1da177e4SLinus Torvalds nframes -= nr; 2148*1da177e4SLinus Torvalds lba += nr; 2149*1da177e4SLinus Torvalds ubuf += len; 2150*1da177e4SLinus Torvalds } 2151*1da177e4SLinus Torvalds 2152*1da177e4SLinus Torvalds return ret; 2153*1da177e4SLinus Torvalds } 2154*1da177e4SLinus Torvalds 2155*1da177e4SLinus Torvalds static int cdrom_read_cdda(struct cdrom_device_info *cdi, __u8 __user *ubuf, 2156*1da177e4SLinus Torvalds int lba, int nframes) 2157*1da177e4SLinus Torvalds { 2158*1da177e4SLinus Torvalds int ret; 2159*1da177e4SLinus Torvalds 2160*1da177e4SLinus Torvalds if (cdi->cdda_method == CDDA_OLD) 2161*1da177e4SLinus Torvalds return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); 2162*1da177e4SLinus Torvalds 2163*1da177e4SLinus Torvalds retry: 2164*1da177e4SLinus Torvalds /* 2165*1da177e4SLinus Torvalds * for anything else than success and io error, we need to retry 2166*1da177e4SLinus Torvalds */ 2167*1da177e4SLinus Torvalds ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes); 2168*1da177e4SLinus Torvalds if (!ret || ret != -EIO) 2169*1da177e4SLinus Torvalds return ret; 2170*1da177e4SLinus Torvalds 2171*1da177e4SLinus Torvalds /* 2172*1da177e4SLinus Torvalds * I've seen drives get sense 4/8/3 udma crc errors on multi 2173*1da177e4SLinus Torvalds * frame dma, so drop to single frame dma if we need to 2174*1da177e4SLinus Torvalds */ 2175*1da177e4SLinus Torvalds if (cdi->cdda_method == CDDA_BPC_FULL && nframes > 1) { 2176*1da177e4SLinus Torvalds printk("cdrom: dropping to single frame dma\n"); 2177*1da177e4SLinus Torvalds cdi->cdda_method = CDDA_BPC_SINGLE; 2178*1da177e4SLinus Torvalds goto retry; 2179*1da177e4SLinus Torvalds } 2180*1da177e4SLinus Torvalds 2181*1da177e4SLinus Torvalds /* 2182*1da177e4SLinus Torvalds * so we have an io error of some sort with multi frame dma. if the 2183*1da177e4SLinus Torvalds * condition wasn't a hardware error 2184*1da177e4SLinus Torvalds * problems, not for any error 2185*1da177e4SLinus Torvalds */ 2186*1da177e4SLinus Torvalds if (cdi->last_sense != 0x04 && cdi->last_sense != 0x0b) 2187*1da177e4SLinus Torvalds return ret; 2188*1da177e4SLinus Torvalds 2189*1da177e4SLinus Torvalds printk("cdrom: dropping to old style cdda (sense=%x)\n", cdi->last_sense); 2190*1da177e4SLinus Torvalds cdi->cdda_method = CDDA_OLD; 2191*1da177e4SLinus Torvalds return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); 2192*1da177e4SLinus Torvalds } 2193*1da177e4SLinus Torvalds 2194*1da177e4SLinus Torvalds /* Just about every imaginable ioctl is supported in the Uniform layer 2195*1da177e4SLinus Torvalds * these days. ATAPI / SCSI specific code now mainly resides in 2196*1da177e4SLinus Torvalds * mmc_ioct(). 2197*1da177e4SLinus Torvalds */ 2198*1da177e4SLinus Torvalds int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi, 2199*1da177e4SLinus Torvalds struct inode *ip, unsigned int cmd, unsigned long arg) 2200*1da177e4SLinus Torvalds { 2201*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2202*1da177e4SLinus Torvalds int ret; 2203*1da177e4SLinus Torvalds 2204*1da177e4SLinus Torvalds /* Try the generic SCSI command ioctl's first.. */ 2205*1da177e4SLinus Torvalds ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg); 2206*1da177e4SLinus Torvalds if (ret != -ENOTTY) 2207*1da177e4SLinus Torvalds return ret; 2208*1da177e4SLinus Torvalds 2209*1da177e4SLinus Torvalds /* the first few commands do not deal with audio drive_info, but 2210*1da177e4SLinus Torvalds only with routines in cdrom device operations. */ 2211*1da177e4SLinus Torvalds switch (cmd) { 2212*1da177e4SLinus Torvalds case CDROMMULTISESSION: { 2213*1da177e4SLinus Torvalds struct cdrom_multisession ms_info; 2214*1da177e4SLinus Torvalds u_char requested_format; 2215*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); 2216*1da177e4SLinus Torvalds if (!(cdo->capability & CDC_MULTI_SESSION)) 2217*1da177e4SLinus Torvalds return -ENOSYS; 2218*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_multisession, ms_info); 2219*1da177e4SLinus Torvalds requested_format = ms_info.addr_format; 2220*1da177e4SLinus Torvalds if (!((requested_format == CDROM_MSF) || 2221*1da177e4SLinus Torvalds (requested_format == CDROM_LBA))) 2222*1da177e4SLinus Torvalds return -EINVAL; 2223*1da177e4SLinus Torvalds ms_info.addr_format = CDROM_LBA; 2224*1da177e4SLinus Torvalds if ((ret=cdo->get_last_session(cdi, &ms_info))) 2225*1da177e4SLinus Torvalds return ret; 2226*1da177e4SLinus Torvalds sanitize_format(&ms_info.addr, &ms_info.addr_format, 2227*1da177e4SLinus Torvalds requested_format); 2228*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_multisession, ms_info); 2229*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); 2230*1da177e4SLinus Torvalds return 0; 2231*1da177e4SLinus Torvalds } 2232*1da177e4SLinus Torvalds 2233*1da177e4SLinus Torvalds case CDROMEJECT: { 2234*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 2235*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_OPEN_TRAY)) 2236*1da177e4SLinus Torvalds return -ENOSYS; 2237*1da177e4SLinus Torvalds if (cdi->use_count != 1 || keeplocked) 2238*1da177e4SLinus Torvalds return -EBUSY; 2239*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_LOCK)) 2240*1da177e4SLinus Torvalds if ((ret=cdo->lock_door(cdi, 0))) 2241*1da177e4SLinus Torvalds return ret; 2242*1da177e4SLinus Torvalds 2243*1da177e4SLinus Torvalds return cdo->tray_move(cdi, 1); 2244*1da177e4SLinus Torvalds } 2245*1da177e4SLinus Torvalds 2246*1da177e4SLinus Torvalds case CDROMCLOSETRAY: { 2247*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 2248*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_CLOSE_TRAY)) 2249*1da177e4SLinus Torvalds return -ENOSYS; 2250*1da177e4SLinus Torvalds return cdo->tray_move(cdi, 0); 2251*1da177e4SLinus Torvalds } 2252*1da177e4SLinus Torvalds 2253*1da177e4SLinus Torvalds case CDROMEJECT_SW: { 2254*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 2255*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_OPEN_TRAY)) 2256*1da177e4SLinus Torvalds return -ENOSYS; 2257*1da177e4SLinus Torvalds if (keeplocked) 2258*1da177e4SLinus Torvalds return -EBUSY; 2259*1da177e4SLinus Torvalds cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); 2260*1da177e4SLinus Torvalds if (arg) 2261*1da177e4SLinus Torvalds cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT; 2262*1da177e4SLinus Torvalds return 0; 2263*1da177e4SLinus Torvalds } 2264*1da177e4SLinus Torvalds 2265*1da177e4SLinus Torvalds case CDROM_MEDIA_CHANGED: { 2266*1da177e4SLinus Torvalds struct cdrom_changer_info *info; 2267*1da177e4SLinus Torvalds int changed; 2268*1da177e4SLinus Torvalds 2269*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 2270*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_MEDIA_CHANGED)) 2271*1da177e4SLinus Torvalds return -ENOSYS; 2272*1da177e4SLinus Torvalds 2273*1da177e4SLinus Torvalds /* cannot select disc or select current disc */ 2274*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT) 2275*1da177e4SLinus Torvalds return media_changed(cdi, 1); 2276*1da177e4SLinus Torvalds 2277*1da177e4SLinus Torvalds if ((unsigned int)arg >= cdi->capacity) 2278*1da177e4SLinus Torvalds return -EINVAL; 2279*1da177e4SLinus Torvalds 2280*1da177e4SLinus Torvalds info = kmalloc(sizeof(*info), GFP_KERNEL); 2281*1da177e4SLinus Torvalds if (!info) 2282*1da177e4SLinus Torvalds return -ENOMEM; 2283*1da177e4SLinus Torvalds 2284*1da177e4SLinus Torvalds if ((ret = cdrom_read_mech_status(cdi, info))) { 2285*1da177e4SLinus Torvalds kfree(info); 2286*1da177e4SLinus Torvalds return ret; 2287*1da177e4SLinus Torvalds } 2288*1da177e4SLinus Torvalds 2289*1da177e4SLinus Torvalds changed = info->slots[arg].change; 2290*1da177e4SLinus Torvalds kfree(info); 2291*1da177e4SLinus Torvalds return changed; 2292*1da177e4SLinus Torvalds } 2293*1da177e4SLinus Torvalds 2294*1da177e4SLinus Torvalds case CDROM_SET_OPTIONS: { 2295*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 2296*1da177e4SLinus Torvalds /* options need to be in sync with capability. too late for 2297*1da177e4SLinus Torvalds that, so we have to check each one separately... */ 2298*1da177e4SLinus Torvalds switch (arg) { 2299*1da177e4SLinus Torvalds case CDO_USE_FFLAGS: 2300*1da177e4SLinus Torvalds case CDO_CHECK_TYPE: 2301*1da177e4SLinus Torvalds break; 2302*1da177e4SLinus Torvalds case CDO_LOCK: 2303*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_LOCK)) 2304*1da177e4SLinus Torvalds return -ENOSYS; 2305*1da177e4SLinus Torvalds break; 2306*1da177e4SLinus Torvalds case 0: 2307*1da177e4SLinus Torvalds return cdi->options; 2308*1da177e4SLinus Torvalds /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */ 2309*1da177e4SLinus Torvalds default: 2310*1da177e4SLinus Torvalds if (!CDROM_CAN(arg)) 2311*1da177e4SLinus Torvalds return -ENOSYS; 2312*1da177e4SLinus Torvalds } 2313*1da177e4SLinus Torvalds cdi->options |= (int) arg; 2314*1da177e4SLinus Torvalds return cdi->options; 2315*1da177e4SLinus Torvalds } 2316*1da177e4SLinus Torvalds 2317*1da177e4SLinus Torvalds case CDROM_CLEAR_OPTIONS: { 2318*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 2319*1da177e4SLinus Torvalds cdi->options &= ~(int) arg; 2320*1da177e4SLinus Torvalds return cdi->options; 2321*1da177e4SLinus Torvalds } 2322*1da177e4SLinus Torvalds 2323*1da177e4SLinus Torvalds case CDROM_SELECT_SPEED: { 2324*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 2325*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_SELECT_SPEED)) 2326*1da177e4SLinus Torvalds return -ENOSYS; 2327*1da177e4SLinus Torvalds return cdo->select_speed(cdi, arg); 2328*1da177e4SLinus Torvalds } 2329*1da177e4SLinus Torvalds 2330*1da177e4SLinus Torvalds case CDROM_SELECT_DISC: { 2331*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 2332*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_SELECT_DISC)) 2333*1da177e4SLinus Torvalds return -ENOSYS; 2334*1da177e4SLinus Torvalds 2335*1da177e4SLinus Torvalds if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE)) 2336*1da177e4SLinus Torvalds if ((int)arg >= cdi->capacity) 2337*1da177e4SLinus Torvalds return -EINVAL; 2338*1da177e4SLinus Torvalds 2339*1da177e4SLinus Torvalds /* cdo->select_disc is a hook to allow a driver-specific 2340*1da177e4SLinus Torvalds * way of seleting disc. However, since there is no 2341*1da177e4SLinus Torvalds * equiv hook for cdrom_slot_status this may not 2342*1da177e4SLinus Torvalds * actually be useful... 2343*1da177e4SLinus Torvalds */ 2344*1da177e4SLinus Torvalds if (cdo->select_disc != NULL) 2345*1da177e4SLinus Torvalds return cdo->select_disc(cdi, arg); 2346*1da177e4SLinus Torvalds 2347*1da177e4SLinus Torvalds /* no driver specific select_disc(), call our own */ 2348*1da177e4SLinus Torvalds cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); 2349*1da177e4SLinus Torvalds return cdrom_select_disc(cdi, arg); 2350*1da177e4SLinus Torvalds } 2351*1da177e4SLinus Torvalds 2352*1da177e4SLinus Torvalds case CDROMRESET: { 2353*1da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 2354*1da177e4SLinus Torvalds return -EACCES; 2355*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); 2356*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_RESET)) 2357*1da177e4SLinus Torvalds return -ENOSYS; 2358*1da177e4SLinus Torvalds invalidate_bdev(ip->i_bdev, 0); 2359*1da177e4SLinus Torvalds return cdo->reset(cdi); 2360*1da177e4SLinus Torvalds } 2361*1da177e4SLinus Torvalds 2362*1da177e4SLinus Torvalds case CDROM_LOCKDOOR: { 2363*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); 2364*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_LOCK)) 2365*1da177e4SLinus Torvalds return -EDRIVE_CANT_DO_THIS; 2366*1da177e4SLinus Torvalds keeplocked = arg ? 1 : 0; 2367*1da177e4SLinus Torvalds /* don't unlock the door on multiple opens,but allow root 2368*1da177e4SLinus Torvalds * to do so */ 2369*1da177e4SLinus Torvalds if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN)) 2370*1da177e4SLinus Torvalds return -EBUSY; 2371*1da177e4SLinus Torvalds return cdo->lock_door(cdi, arg); 2372*1da177e4SLinus Torvalds } 2373*1da177e4SLinus Torvalds 2374*1da177e4SLinus Torvalds case CDROM_DEBUG: { 2375*1da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 2376*1da177e4SLinus Torvalds return -EACCES; 2377*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); 2378*1da177e4SLinus Torvalds debug = arg ? 1 : 0; 2379*1da177e4SLinus Torvalds return debug; 2380*1da177e4SLinus Torvalds } 2381*1da177e4SLinus Torvalds 2382*1da177e4SLinus Torvalds case CDROM_GET_CAPABILITY: { 2383*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); 2384*1da177e4SLinus Torvalds return (cdo->capability & ~cdi->mask); 2385*1da177e4SLinus Torvalds } 2386*1da177e4SLinus Torvalds 2387*1da177e4SLinus Torvalds /* The following function is implemented, although very few audio 2388*1da177e4SLinus Torvalds * discs give Universal Product Code information, which should just be 2389*1da177e4SLinus Torvalds * the Medium Catalog Number on the box. Note, that the way the code 2390*1da177e4SLinus Torvalds * is written on the CD is /not/ uniform across all discs! 2391*1da177e4SLinus Torvalds */ 2392*1da177e4SLinus Torvalds case CDROM_GET_MCN: { 2393*1da177e4SLinus Torvalds struct cdrom_mcn mcn; 2394*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 2395*1da177e4SLinus Torvalds if (!(cdo->capability & CDC_MCN)) 2396*1da177e4SLinus Torvalds return -ENOSYS; 2397*1da177e4SLinus Torvalds if ((ret=cdo->get_mcn(cdi, &mcn))) 2398*1da177e4SLinus Torvalds return ret; 2399*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_mcn, mcn); 2400*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); 2401*1da177e4SLinus Torvalds return 0; 2402*1da177e4SLinus Torvalds } 2403*1da177e4SLinus Torvalds 2404*1da177e4SLinus Torvalds case CDROM_DRIVE_STATUS: { 2405*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); 2406*1da177e4SLinus Torvalds if (!(cdo->capability & CDC_DRIVE_STATUS)) 2407*1da177e4SLinus Torvalds return -ENOSYS; 2408*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_SELECT_DISC)) 2409*1da177e4SLinus Torvalds return cdo->drive_status(cdi, CDSL_CURRENT); 2410*1da177e4SLinus Torvalds if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) 2411*1da177e4SLinus Torvalds return cdo->drive_status(cdi, CDSL_CURRENT); 2412*1da177e4SLinus Torvalds if (((int)arg >= cdi->capacity)) 2413*1da177e4SLinus Torvalds return -EINVAL; 2414*1da177e4SLinus Torvalds return cdrom_slot_status(cdi, arg); 2415*1da177e4SLinus Torvalds } 2416*1da177e4SLinus Torvalds 2417*1da177e4SLinus Torvalds /* Ok, this is where problems start. The current interface for the 2418*1da177e4SLinus Torvalds CDROM_DISC_STATUS ioctl is flawed. It makes the false assumption 2419*1da177e4SLinus Torvalds that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc. Unfortunatly, 2420*1da177e4SLinus Torvalds while this is often the case, it is also very common for CDs to 2421*1da177e4SLinus Torvalds have some tracks with data, and some tracks with audio. Just 2422*1da177e4SLinus Torvalds because I feel like it, I declare the following to be the best 2423*1da177e4SLinus Torvalds way to cope. If the CD has ANY data tracks on it, it will be 2424*1da177e4SLinus Torvalds returned as a data CD. If it has any XA tracks, I will return 2425*1da177e4SLinus Torvalds it as that. Now I could simplify this interface by combining these 2426*1da177e4SLinus Torvalds returns with the above, but this more clearly demonstrates 2427*1da177e4SLinus Torvalds the problem with the current interface. Too bad this wasn't 2428*1da177e4SLinus Torvalds designed to use bitmasks... -Erik 2429*1da177e4SLinus Torvalds 2430*1da177e4SLinus Torvalds Well, now we have the option CDS_MIXED: a mixed-type CD. 2431*1da177e4SLinus Torvalds User level programmers might feel the ioctl is not very useful. 2432*1da177e4SLinus Torvalds ---david 2433*1da177e4SLinus Torvalds */ 2434*1da177e4SLinus Torvalds case CDROM_DISC_STATUS: { 2435*1da177e4SLinus Torvalds tracktype tracks; 2436*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); 2437*1da177e4SLinus Torvalds cdrom_count_tracks(cdi, &tracks); 2438*1da177e4SLinus Torvalds if (tracks.error) 2439*1da177e4SLinus Torvalds return(tracks.error); 2440*1da177e4SLinus Torvalds 2441*1da177e4SLinus Torvalds /* Policy mode on */ 2442*1da177e4SLinus Torvalds if (tracks.audio > 0) { 2443*1da177e4SLinus Torvalds if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 2444*1da177e4SLinus Torvalds return CDS_AUDIO; 2445*1da177e4SLinus Torvalds else 2446*1da177e4SLinus Torvalds return CDS_MIXED; 2447*1da177e4SLinus Torvalds } 2448*1da177e4SLinus Torvalds if (tracks.cdi > 0) return CDS_XA_2_2; 2449*1da177e4SLinus Torvalds if (tracks.xa > 0) return CDS_XA_2_1; 2450*1da177e4SLinus Torvalds if (tracks.data > 0) return CDS_DATA_1; 2451*1da177e4SLinus Torvalds /* Policy mode off */ 2452*1da177e4SLinus Torvalds 2453*1da177e4SLinus Torvalds cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); 2454*1da177e4SLinus Torvalds return CDS_NO_INFO; 2455*1da177e4SLinus Torvalds } 2456*1da177e4SLinus Torvalds 2457*1da177e4SLinus Torvalds case CDROM_CHANGER_NSLOTS: { 2458*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 2459*1da177e4SLinus Torvalds return cdi->capacity; 2460*1da177e4SLinus Torvalds } 2461*1da177e4SLinus Torvalds } 2462*1da177e4SLinus Torvalds 2463*1da177e4SLinus Torvalds /* use the ioctls that are implemented through the generic_packet() 2464*1da177e4SLinus Torvalds interface. this may look at bit funny, but if -ENOTTY is 2465*1da177e4SLinus Torvalds returned that particular ioctl is not implemented and we 2466*1da177e4SLinus Torvalds let it go through the device specific ones. */ 2467*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_GENERIC_PACKET)) { 2468*1da177e4SLinus Torvalds ret = mmc_ioctl(cdi, cmd, arg); 2469*1da177e4SLinus Torvalds if (ret != -ENOTTY) { 2470*1da177e4SLinus Torvalds return ret; 2471*1da177e4SLinus Torvalds } 2472*1da177e4SLinus Torvalds } 2473*1da177e4SLinus Torvalds 2474*1da177e4SLinus Torvalds /* note: most of the cdinfo() calls are commented out here, 2475*1da177e4SLinus Torvalds because they fill up the sys log when CD players poll 2476*1da177e4SLinus Torvalds the drive. */ 2477*1da177e4SLinus Torvalds switch (cmd) { 2478*1da177e4SLinus Torvalds case CDROMSUBCHNL: { 2479*1da177e4SLinus Torvalds struct cdrom_subchnl q; 2480*1da177e4SLinus Torvalds u_char requested, back; 2481*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2482*1da177e4SLinus Torvalds return -ENOSYS; 2483*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 2484*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_subchnl, q); 2485*1da177e4SLinus Torvalds requested = q.cdsc_format; 2486*1da177e4SLinus Torvalds if (!((requested == CDROM_MSF) || 2487*1da177e4SLinus Torvalds (requested == CDROM_LBA))) 2488*1da177e4SLinus Torvalds return -EINVAL; 2489*1da177e4SLinus Torvalds q.cdsc_format = CDROM_MSF; 2490*1da177e4SLinus Torvalds if ((ret=cdo->audio_ioctl(cdi, cmd, &q))) 2491*1da177e4SLinus Torvalds return ret; 2492*1da177e4SLinus Torvalds back = q.cdsc_format; /* local copy */ 2493*1da177e4SLinus Torvalds sanitize_format(&q.cdsc_absaddr, &back, requested); 2494*1da177e4SLinus Torvalds sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); 2495*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_subchnl, q); 2496*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 2497*1da177e4SLinus Torvalds return 0; 2498*1da177e4SLinus Torvalds } 2499*1da177e4SLinus Torvalds case CDROMREADTOCHDR: { 2500*1da177e4SLinus Torvalds struct cdrom_tochdr header; 2501*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2502*1da177e4SLinus Torvalds return -ENOSYS; 2503*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 2504*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_tochdr, header); 2505*1da177e4SLinus Torvalds if ((ret=cdo->audio_ioctl(cdi, cmd, &header))) 2506*1da177e4SLinus Torvalds return ret; 2507*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_tochdr, header); 2508*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 2509*1da177e4SLinus Torvalds return 0; 2510*1da177e4SLinus Torvalds } 2511*1da177e4SLinus Torvalds case CDROMREADTOCENTRY: { 2512*1da177e4SLinus Torvalds struct cdrom_tocentry entry; 2513*1da177e4SLinus Torvalds u_char requested_format; 2514*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2515*1da177e4SLinus Torvalds return -ENOSYS; 2516*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 2517*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_tocentry, entry); 2518*1da177e4SLinus Torvalds requested_format = entry.cdte_format; 2519*1da177e4SLinus Torvalds if (!((requested_format == CDROM_MSF) || 2520*1da177e4SLinus Torvalds (requested_format == CDROM_LBA))) 2521*1da177e4SLinus Torvalds return -EINVAL; 2522*1da177e4SLinus Torvalds /* make interface to low-level uniform */ 2523*1da177e4SLinus Torvalds entry.cdte_format = CDROM_MSF; 2524*1da177e4SLinus Torvalds if ((ret=cdo->audio_ioctl(cdi, cmd, &entry))) 2525*1da177e4SLinus Torvalds return ret; 2526*1da177e4SLinus Torvalds sanitize_format(&entry.cdte_addr, 2527*1da177e4SLinus Torvalds &entry.cdte_format, requested_format); 2528*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_tocentry, entry); 2529*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 2530*1da177e4SLinus Torvalds return 0; 2531*1da177e4SLinus Torvalds } 2532*1da177e4SLinus Torvalds case CDROMPLAYMSF: { 2533*1da177e4SLinus Torvalds struct cdrom_msf msf; 2534*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2535*1da177e4SLinus Torvalds return -ENOSYS; 2536*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 2537*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_msf, msf); 2538*1da177e4SLinus Torvalds return cdo->audio_ioctl(cdi, cmd, &msf); 2539*1da177e4SLinus Torvalds } 2540*1da177e4SLinus Torvalds case CDROMPLAYTRKIND: { 2541*1da177e4SLinus Torvalds struct cdrom_ti ti; 2542*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2543*1da177e4SLinus Torvalds return -ENOSYS; 2544*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 2545*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_ti, ti); 2546*1da177e4SLinus Torvalds CHECKAUDIO; 2547*1da177e4SLinus Torvalds return cdo->audio_ioctl(cdi, cmd, &ti); 2548*1da177e4SLinus Torvalds } 2549*1da177e4SLinus Torvalds case CDROMVOLCTRL: { 2550*1da177e4SLinus Torvalds struct cdrom_volctrl volume; 2551*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2552*1da177e4SLinus Torvalds return -ENOSYS; 2553*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 2554*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_volctrl, volume); 2555*1da177e4SLinus Torvalds return cdo->audio_ioctl(cdi, cmd, &volume); 2556*1da177e4SLinus Torvalds } 2557*1da177e4SLinus Torvalds case CDROMVOLREAD: { 2558*1da177e4SLinus Torvalds struct cdrom_volctrl volume; 2559*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2560*1da177e4SLinus Torvalds return -ENOSYS; 2561*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 2562*1da177e4SLinus Torvalds if ((ret=cdo->audio_ioctl(cdi, cmd, &volume))) 2563*1da177e4SLinus Torvalds return ret; 2564*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_volctrl, volume); 2565*1da177e4SLinus Torvalds return 0; 2566*1da177e4SLinus Torvalds } 2567*1da177e4SLinus Torvalds case CDROMSTART: 2568*1da177e4SLinus Torvalds case CDROMSTOP: 2569*1da177e4SLinus Torvalds case CDROMPAUSE: 2570*1da177e4SLinus Torvalds case CDROMRESUME: { 2571*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_PLAY_AUDIO)) 2572*1da177e4SLinus Torvalds return -ENOSYS; 2573*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 2574*1da177e4SLinus Torvalds CHECKAUDIO; 2575*1da177e4SLinus Torvalds return cdo->audio_ioctl(cdi, cmd, NULL); 2576*1da177e4SLinus Torvalds } 2577*1da177e4SLinus Torvalds } /* switch */ 2578*1da177e4SLinus Torvalds 2579*1da177e4SLinus Torvalds /* do the device specific ioctls */ 2580*1da177e4SLinus Torvalds if (CDROM_CAN(CDC_IOCTLS)) 2581*1da177e4SLinus Torvalds return cdo->dev_ioctl(cdi, cmd, arg); 2582*1da177e4SLinus Torvalds 2583*1da177e4SLinus Torvalds return -ENOSYS; 2584*1da177e4SLinus Torvalds } 2585*1da177e4SLinus Torvalds 2586*1da177e4SLinus Torvalds static inline 2587*1da177e4SLinus Torvalds int msf_to_lba(char m, char s, char f) 2588*1da177e4SLinus Torvalds { 2589*1da177e4SLinus Torvalds return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; 2590*1da177e4SLinus Torvalds } 2591*1da177e4SLinus Torvalds 2592*1da177e4SLinus Torvalds /* 2593*1da177e4SLinus Torvalds * Required when we need to use READ_10 to issue other than 2048 block 2594*1da177e4SLinus Torvalds * reads 2595*1da177e4SLinus Torvalds */ 2596*1da177e4SLinus Torvalds static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) 2597*1da177e4SLinus Torvalds { 2598*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2599*1da177e4SLinus Torvalds struct packet_command cgc; 2600*1da177e4SLinus Torvalds struct modesel_head mh; 2601*1da177e4SLinus Torvalds 2602*1da177e4SLinus Torvalds memset(&mh, 0, sizeof(mh)); 2603*1da177e4SLinus Torvalds mh.block_desc_length = 0x08; 2604*1da177e4SLinus Torvalds mh.block_length_med = (size >> 8) & 0xff; 2605*1da177e4SLinus Torvalds mh.block_length_lo = size & 0xff; 2606*1da177e4SLinus Torvalds 2607*1da177e4SLinus Torvalds memset(&cgc, 0, sizeof(cgc)); 2608*1da177e4SLinus Torvalds cgc.cmd[0] = 0x15; 2609*1da177e4SLinus Torvalds cgc.cmd[1] = 1 << 4; 2610*1da177e4SLinus Torvalds cgc.cmd[4] = 12; 2611*1da177e4SLinus Torvalds cgc.buflen = sizeof(mh); 2612*1da177e4SLinus Torvalds cgc.buffer = (char *) &mh; 2613*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_WRITE; 2614*1da177e4SLinus Torvalds mh.block_desc_length = 0x08; 2615*1da177e4SLinus Torvalds mh.block_length_med = (size >> 8) & 0xff; 2616*1da177e4SLinus Torvalds mh.block_length_lo = size & 0xff; 2617*1da177e4SLinus Torvalds 2618*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 2619*1da177e4SLinus Torvalds } 2620*1da177e4SLinus Torvalds 2621*1da177e4SLinus Torvalds static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, 2622*1da177e4SLinus Torvalds unsigned long arg) 2623*1da177e4SLinus Torvalds { 2624*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2625*1da177e4SLinus Torvalds struct packet_command cgc; 2626*1da177e4SLinus Torvalds struct request_sense sense; 2627*1da177e4SLinus Torvalds unsigned char buffer[32]; 2628*1da177e4SLinus Torvalds int ret = 0; 2629*1da177e4SLinus Torvalds 2630*1da177e4SLinus Torvalds memset(&cgc, 0, sizeof(cgc)); 2631*1da177e4SLinus Torvalds 2632*1da177e4SLinus Torvalds /* build a unified command and queue it through 2633*1da177e4SLinus Torvalds cdo->generic_packet() */ 2634*1da177e4SLinus Torvalds switch (cmd) { 2635*1da177e4SLinus Torvalds case CDROMREADRAW: 2636*1da177e4SLinus Torvalds case CDROMREADMODE1: 2637*1da177e4SLinus Torvalds case CDROMREADMODE2: { 2638*1da177e4SLinus Torvalds struct cdrom_msf msf; 2639*1da177e4SLinus Torvalds int blocksize = 0, format = 0, lba; 2640*1da177e4SLinus Torvalds 2641*1da177e4SLinus Torvalds switch (cmd) { 2642*1da177e4SLinus Torvalds case CDROMREADRAW: 2643*1da177e4SLinus Torvalds blocksize = CD_FRAMESIZE_RAW; 2644*1da177e4SLinus Torvalds break; 2645*1da177e4SLinus Torvalds case CDROMREADMODE1: 2646*1da177e4SLinus Torvalds blocksize = CD_FRAMESIZE; 2647*1da177e4SLinus Torvalds format = 2; 2648*1da177e4SLinus Torvalds break; 2649*1da177e4SLinus Torvalds case CDROMREADMODE2: 2650*1da177e4SLinus Torvalds blocksize = CD_FRAMESIZE_RAW0; 2651*1da177e4SLinus Torvalds break; 2652*1da177e4SLinus Torvalds } 2653*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_msf, msf); 2654*1da177e4SLinus Torvalds lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0); 2655*1da177e4SLinus Torvalds /* FIXME: we need upper bound checking, too!! */ 2656*1da177e4SLinus Torvalds if (lba < 0) 2657*1da177e4SLinus Torvalds return -EINVAL; 2658*1da177e4SLinus Torvalds cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL); 2659*1da177e4SLinus Torvalds if (cgc.buffer == NULL) 2660*1da177e4SLinus Torvalds return -ENOMEM; 2661*1da177e4SLinus Torvalds memset(&sense, 0, sizeof(sense)); 2662*1da177e4SLinus Torvalds cgc.sense = &sense; 2663*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_READ; 2664*1da177e4SLinus Torvalds ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize); 2665*1da177e4SLinus Torvalds if (ret && sense.sense_key==0x05 && sense.asc==0x20 && sense.ascq==0x00) { 2666*1da177e4SLinus Torvalds /* 2667*1da177e4SLinus Torvalds * SCSI-II devices are not required to support 2668*1da177e4SLinus Torvalds * READ_CD, so let's try switching block size 2669*1da177e4SLinus Torvalds */ 2670*1da177e4SLinus Torvalds /* FIXME: switch back again... */ 2671*1da177e4SLinus Torvalds if ((ret = cdrom_switch_blocksize(cdi, blocksize))) { 2672*1da177e4SLinus Torvalds kfree(cgc.buffer); 2673*1da177e4SLinus Torvalds return ret; 2674*1da177e4SLinus Torvalds } 2675*1da177e4SLinus Torvalds cgc.sense = NULL; 2676*1da177e4SLinus Torvalds ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1); 2677*1da177e4SLinus Torvalds ret |= cdrom_switch_blocksize(cdi, blocksize); 2678*1da177e4SLinus Torvalds } 2679*1da177e4SLinus Torvalds if (!ret && copy_to_user((char __user *)arg, cgc.buffer, blocksize)) 2680*1da177e4SLinus Torvalds ret = -EFAULT; 2681*1da177e4SLinus Torvalds kfree(cgc.buffer); 2682*1da177e4SLinus Torvalds return ret; 2683*1da177e4SLinus Torvalds } 2684*1da177e4SLinus Torvalds case CDROMREADAUDIO: { 2685*1da177e4SLinus Torvalds struct cdrom_read_audio ra; 2686*1da177e4SLinus Torvalds int lba; 2687*1da177e4SLinus Torvalds 2688*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_read_audio, ra); 2689*1da177e4SLinus Torvalds 2690*1da177e4SLinus Torvalds if (ra.addr_format == CDROM_MSF) 2691*1da177e4SLinus Torvalds lba = msf_to_lba(ra.addr.msf.minute, 2692*1da177e4SLinus Torvalds ra.addr.msf.second, 2693*1da177e4SLinus Torvalds ra.addr.msf.frame); 2694*1da177e4SLinus Torvalds else if (ra.addr_format == CDROM_LBA) 2695*1da177e4SLinus Torvalds lba = ra.addr.lba; 2696*1da177e4SLinus Torvalds else 2697*1da177e4SLinus Torvalds return -EINVAL; 2698*1da177e4SLinus Torvalds 2699*1da177e4SLinus Torvalds /* FIXME: we need upper bound checking, too!! */ 2700*1da177e4SLinus Torvalds if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) 2701*1da177e4SLinus Torvalds return -EINVAL; 2702*1da177e4SLinus Torvalds 2703*1da177e4SLinus Torvalds return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes); 2704*1da177e4SLinus Torvalds } 2705*1da177e4SLinus Torvalds case CDROMSUBCHNL: { 2706*1da177e4SLinus Torvalds struct cdrom_subchnl q; 2707*1da177e4SLinus Torvalds u_char requested, back; 2708*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_subchnl, q); 2709*1da177e4SLinus Torvalds requested = q.cdsc_format; 2710*1da177e4SLinus Torvalds if (!((requested == CDROM_MSF) || 2711*1da177e4SLinus Torvalds (requested == CDROM_LBA))) 2712*1da177e4SLinus Torvalds return -EINVAL; 2713*1da177e4SLinus Torvalds q.cdsc_format = CDROM_MSF; 2714*1da177e4SLinus Torvalds if ((ret = cdrom_read_subchannel(cdi, &q, 0))) 2715*1da177e4SLinus Torvalds return ret; 2716*1da177e4SLinus Torvalds back = q.cdsc_format; /* local copy */ 2717*1da177e4SLinus Torvalds sanitize_format(&q.cdsc_absaddr, &back, requested); 2718*1da177e4SLinus Torvalds sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested); 2719*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_subchnl, q); 2720*1da177e4SLinus Torvalds /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 2721*1da177e4SLinus Torvalds return 0; 2722*1da177e4SLinus Torvalds } 2723*1da177e4SLinus Torvalds case CDROMPLAYMSF: { 2724*1da177e4SLinus Torvalds struct cdrom_msf msf; 2725*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 2726*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_msf, msf); 2727*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; 2728*1da177e4SLinus Torvalds cgc.cmd[3] = msf.cdmsf_min0; 2729*1da177e4SLinus Torvalds cgc.cmd[4] = msf.cdmsf_sec0; 2730*1da177e4SLinus Torvalds cgc.cmd[5] = msf.cdmsf_frame0; 2731*1da177e4SLinus Torvalds cgc.cmd[6] = msf.cdmsf_min1; 2732*1da177e4SLinus Torvalds cgc.cmd[7] = msf.cdmsf_sec1; 2733*1da177e4SLinus Torvalds cgc.cmd[8] = msf.cdmsf_frame1; 2734*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_NONE; 2735*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 2736*1da177e4SLinus Torvalds } 2737*1da177e4SLinus Torvalds case CDROMPLAYBLK: { 2738*1da177e4SLinus Torvalds struct cdrom_blk blk; 2739*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); 2740*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_blk, blk); 2741*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_PLAY_AUDIO_10; 2742*1da177e4SLinus Torvalds cgc.cmd[2] = (blk.from >> 24) & 0xff; 2743*1da177e4SLinus Torvalds cgc.cmd[3] = (blk.from >> 16) & 0xff; 2744*1da177e4SLinus Torvalds cgc.cmd[4] = (blk.from >> 8) & 0xff; 2745*1da177e4SLinus Torvalds cgc.cmd[5] = blk.from & 0xff; 2746*1da177e4SLinus Torvalds cgc.cmd[7] = (blk.len >> 8) & 0xff; 2747*1da177e4SLinus Torvalds cgc.cmd[8] = blk.len & 0xff; 2748*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_NONE; 2749*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 2750*1da177e4SLinus Torvalds } 2751*1da177e4SLinus Torvalds case CDROMVOLCTRL: 2752*1da177e4SLinus Torvalds case CDROMVOLREAD: { 2753*1da177e4SLinus Torvalds struct cdrom_volctrl volctrl; 2754*1da177e4SLinus Torvalds char mask[sizeof(buffer)]; 2755*1da177e4SLinus Torvalds unsigned short offset; 2756*1da177e4SLinus Torvalds 2757*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); 2758*1da177e4SLinus Torvalds 2759*1da177e4SLinus Torvalds IOCTL_IN(arg, struct cdrom_volctrl, volctrl); 2760*1da177e4SLinus Torvalds 2761*1da177e4SLinus Torvalds cgc.buffer = buffer; 2762*1da177e4SLinus Torvalds cgc.buflen = 24; 2763*1da177e4SLinus Torvalds if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0))) 2764*1da177e4SLinus Torvalds return ret; 2765*1da177e4SLinus Torvalds 2766*1da177e4SLinus Torvalds /* originally the code depended on buffer[1] to determine 2767*1da177e4SLinus Torvalds how much data is available for transfer. buffer[1] is 2768*1da177e4SLinus Torvalds unfortunately ambigious and the only reliable way seem 2769*1da177e4SLinus Torvalds to be to simply skip over the block descriptor... */ 2770*1da177e4SLinus Torvalds offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6)); 2771*1da177e4SLinus Torvalds 2772*1da177e4SLinus Torvalds if (offset + 16 > sizeof(buffer)) 2773*1da177e4SLinus Torvalds return -E2BIG; 2774*1da177e4SLinus Torvalds 2775*1da177e4SLinus Torvalds if (offset + 16 > cgc.buflen) { 2776*1da177e4SLinus Torvalds cgc.buflen = offset+16; 2777*1da177e4SLinus Torvalds ret = cdrom_mode_sense(cdi, &cgc, 2778*1da177e4SLinus Torvalds GPMODE_AUDIO_CTL_PAGE, 0); 2779*1da177e4SLinus Torvalds if (ret) 2780*1da177e4SLinus Torvalds return ret; 2781*1da177e4SLinus Torvalds } 2782*1da177e4SLinus Torvalds 2783*1da177e4SLinus Torvalds /* sanity check */ 2784*1da177e4SLinus Torvalds if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || 2785*1da177e4SLinus Torvalds buffer[offset+1] < 14) 2786*1da177e4SLinus Torvalds return -EINVAL; 2787*1da177e4SLinus Torvalds 2788*1da177e4SLinus Torvalds /* now we have the current volume settings. if it was only 2789*1da177e4SLinus Torvalds a CDROMVOLREAD, return these values */ 2790*1da177e4SLinus Torvalds if (cmd == CDROMVOLREAD) { 2791*1da177e4SLinus Torvalds volctrl.channel0 = buffer[offset+9]; 2792*1da177e4SLinus Torvalds volctrl.channel1 = buffer[offset+11]; 2793*1da177e4SLinus Torvalds volctrl.channel2 = buffer[offset+13]; 2794*1da177e4SLinus Torvalds volctrl.channel3 = buffer[offset+15]; 2795*1da177e4SLinus Torvalds IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); 2796*1da177e4SLinus Torvalds return 0; 2797*1da177e4SLinus Torvalds } 2798*1da177e4SLinus Torvalds 2799*1da177e4SLinus Torvalds /* get the volume mask */ 2800*1da177e4SLinus Torvalds cgc.buffer = mask; 2801*1da177e4SLinus Torvalds if ((ret = cdrom_mode_sense(cdi, &cgc, 2802*1da177e4SLinus Torvalds GPMODE_AUDIO_CTL_PAGE, 1))) 2803*1da177e4SLinus Torvalds return ret; 2804*1da177e4SLinus Torvalds 2805*1da177e4SLinus Torvalds buffer[offset+9] = volctrl.channel0 & mask[offset+9]; 2806*1da177e4SLinus Torvalds buffer[offset+11] = volctrl.channel1 & mask[offset+11]; 2807*1da177e4SLinus Torvalds buffer[offset+13] = volctrl.channel2 & mask[offset+13]; 2808*1da177e4SLinus Torvalds buffer[offset+15] = volctrl.channel3 & mask[offset+15]; 2809*1da177e4SLinus Torvalds 2810*1da177e4SLinus Torvalds /* set volume */ 2811*1da177e4SLinus Torvalds cgc.buffer = buffer + offset - 8; 2812*1da177e4SLinus Torvalds memset(cgc.buffer, 0, 8); 2813*1da177e4SLinus Torvalds return cdrom_mode_select(cdi, &cgc); 2814*1da177e4SLinus Torvalds } 2815*1da177e4SLinus Torvalds 2816*1da177e4SLinus Torvalds case CDROMSTART: 2817*1da177e4SLinus Torvalds case CDROMSTOP: { 2818*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); 2819*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_START_STOP_UNIT; 2820*1da177e4SLinus Torvalds cgc.cmd[1] = 1; 2821*1da177e4SLinus Torvalds cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0; 2822*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_NONE; 2823*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 2824*1da177e4SLinus Torvalds } 2825*1da177e4SLinus Torvalds 2826*1da177e4SLinus Torvalds case CDROMPAUSE: 2827*1da177e4SLinus Torvalds case CDROMRESUME: { 2828*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 2829*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_PAUSE_RESUME; 2830*1da177e4SLinus Torvalds cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; 2831*1da177e4SLinus Torvalds cgc.data_direction = CGC_DATA_NONE; 2832*1da177e4SLinus Torvalds return cdo->generic_packet(cdi, &cgc); 2833*1da177e4SLinus Torvalds } 2834*1da177e4SLinus Torvalds 2835*1da177e4SLinus Torvalds case DVD_READ_STRUCT: { 2836*1da177e4SLinus Torvalds dvd_struct *s; 2837*1da177e4SLinus Torvalds int size = sizeof(dvd_struct); 2838*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_DVD)) 2839*1da177e4SLinus Torvalds return -ENOSYS; 2840*1da177e4SLinus Torvalds if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL) 2841*1da177e4SLinus Torvalds return -ENOMEM; 2842*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); 2843*1da177e4SLinus Torvalds if (copy_from_user(s, (dvd_struct __user *)arg, size)) { 2844*1da177e4SLinus Torvalds kfree(s); 2845*1da177e4SLinus Torvalds return -EFAULT; 2846*1da177e4SLinus Torvalds } 2847*1da177e4SLinus Torvalds if ((ret = dvd_read_struct(cdi, s))) { 2848*1da177e4SLinus Torvalds kfree(s); 2849*1da177e4SLinus Torvalds return ret; 2850*1da177e4SLinus Torvalds } 2851*1da177e4SLinus Torvalds if (copy_to_user((dvd_struct __user *)arg, s, size)) 2852*1da177e4SLinus Torvalds ret = -EFAULT; 2853*1da177e4SLinus Torvalds kfree(s); 2854*1da177e4SLinus Torvalds return ret; 2855*1da177e4SLinus Torvalds } 2856*1da177e4SLinus Torvalds 2857*1da177e4SLinus Torvalds case DVD_AUTH: { 2858*1da177e4SLinus Torvalds dvd_authinfo ai; 2859*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_DVD)) 2860*1da177e4SLinus Torvalds return -ENOSYS; 2861*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); 2862*1da177e4SLinus Torvalds IOCTL_IN(arg, dvd_authinfo, ai); 2863*1da177e4SLinus Torvalds if ((ret = dvd_do_auth (cdi, &ai))) 2864*1da177e4SLinus Torvalds return ret; 2865*1da177e4SLinus Torvalds IOCTL_OUT(arg, dvd_authinfo, ai); 2866*1da177e4SLinus Torvalds return 0; 2867*1da177e4SLinus Torvalds } 2868*1da177e4SLinus Torvalds 2869*1da177e4SLinus Torvalds case CDROM_NEXT_WRITABLE: { 2870*1da177e4SLinus Torvalds long next = 0; 2871*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); 2872*1da177e4SLinus Torvalds if ((ret = cdrom_get_next_writable(cdi, &next))) 2873*1da177e4SLinus Torvalds return ret; 2874*1da177e4SLinus Torvalds IOCTL_OUT(arg, long, next); 2875*1da177e4SLinus Torvalds return 0; 2876*1da177e4SLinus Torvalds } 2877*1da177e4SLinus Torvalds case CDROM_LAST_WRITTEN: { 2878*1da177e4SLinus Torvalds long last = 0; 2879*1da177e4SLinus Torvalds cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); 2880*1da177e4SLinus Torvalds if ((ret = cdrom_get_last_written(cdi, &last))) 2881*1da177e4SLinus Torvalds return ret; 2882*1da177e4SLinus Torvalds IOCTL_OUT(arg, long, last); 2883*1da177e4SLinus Torvalds return 0; 2884*1da177e4SLinus Torvalds } 2885*1da177e4SLinus Torvalds } /* switch */ 2886*1da177e4SLinus Torvalds 2887*1da177e4SLinus Torvalds return -ENOTTY; 2888*1da177e4SLinus Torvalds } 2889*1da177e4SLinus Torvalds 2890*1da177e4SLinus Torvalds static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, 2891*1da177e4SLinus Torvalds track_information *ti) 2892*1da177e4SLinus Torvalds { 2893*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2894*1da177e4SLinus Torvalds struct packet_command cgc; 2895*1da177e4SLinus Torvalds int ret, buflen; 2896*1da177e4SLinus Torvalds 2897*1da177e4SLinus Torvalds init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); 2898*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; 2899*1da177e4SLinus Torvalds cgc.cmd[1] = type & 3; 2900*1da177e4SLinus Torvalds cgc.cmd[4] = (track & 0xff00) >> 8; 2901*1da177e4SLinus Torvalds cgc.cmd[5] = track & 0xff; 2902*1da177e4SLinus Torvalds cgc.cmd[8] = 8; 2903*1da177e4SLinus Torvalds cgc.quiet = 1; 2904*1da177e4SLinus Torvalds 2905*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 2906*1da177e4SLinus Torvalds return ret; 2907*1da177e4SLinus Torvalds 2908*1da177e4SLinus Torvalds buflen = be16_to_cpu(ti->track_information_length) + 2909*1da177e4SLinus Torvalds sizeof(ti->track_information_length); 2910*1da177e4SLinus Torvalds 2911*1da177e4SLinus Torvalds if (buflen > sizeof(track_information)) 2912*1da177e4SLinus Torvalds buflen = sizeof(track_information); 2913*1da177e4SLinus Torvalds 2914*1da177e4SLinus Torvalds cgc.cmd[8] = cgc.buflen = buflen; 2915*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 2916*1da177e4SLinus Torvalds return ret; 2917*1da177e4SLinus Torvalds 2918*1da177e4SLinus Torvalds /* return actual fill size */ 2919*1da177e4SLinus Torvalds return buflen; 2920*1da177e4SLinus Torvalds } 2921*1da177e4SLinus Torvalds 2922*1da177e4SLinus Torvalds /* requires CD R/RW */ 2923*1da177e4SLinus Torvalds static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di) 2924*1da177e4SLinus Torvalds { 2925*1da177e4SLinus Torvalds struct cdrom_device_ops *cdo = cdi->ops; 2926*1da177e4SLinus Torvalds struct packet_command cgc; 2927*1da177e4SLinus Torvalds int ret, buflen; 2928*1da177e4SLinus Torvalds 2929*1da177e4SLinus Torvalds /* set up command and get the disc info */ 2930*1da177e4SLinus Torvalds init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); 2931*1da177e4SLinus Torvalds cgc.cmd[0] = GPCMD_READ_DISC_INFO; 2932*1da177e4SLinus Torvalds cgc.cmd[8] = cgc.buflen = 2; 2933*1da177e4SLinus Torvalds cgc.quiet = 1; 2934*1da177e4SLinus Torvalds 2935*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 2936*1da177e4SLinus Torvalds return ret; 2937*1da177e4SLinus Torvalds 2938*1da177e4SLinus Torvalds /* not all drives have the same disc_info length, so requeue 2939*1da177e4SLinus Torvalds * packet with the length the drive tells us it can supply 2940*1da177e4SLinus Torvalds */ 2941*1da177e4SLinus Torvalds buflen = be16_to_cpu(di->disc_information_length) + 2942*1da177e4SLinus Torvalds sizeof(di->disc_information_length); 2943*1da177e4SLinus Torvalds 2944*1da177e4SLinus Torvalds if (buflen > sizeof(disc_information)) 2945*1da177e4SLinus Torvalds buflen = sizeof(disc_information); 2946*1da177e4SLinus Torvalds 2947*1da177e4SLinus Torvalds cgc.cmd[8] = cgc.buflen = buflen; 2948*1da177e4SLinus Torvalds if ((ret = cdo->generic_packet(cdi, &cgc))) 2949*1da177e4SLinus Torvalds return ret; 2950*1da177e4SLinus Torvalds 2951*1da177e4SLinus Torvalds /* return actual fill size */ 2952*1da177e4SLinus Torvalds return buflen; 2953*1da177e4SLinus Torvalds } 2954*1da177e4SLinus Torvalds 2955*1da177e4SLinus Torvalds /* return the last written block on the CD-R media. this is for the udf 2956*1da177e4SLinus Torvalds file system. */ 2957*1da177e4SLinus Torvalds int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) 2958*1da177e4SLinus Torvalds { 2959*1da177e4SLinus Torvalds struct cdrom_tocentry toc; 2960*1da177e4SLinus Torvalds disc_information di; 2961*1da177e4SLinus Torvalds track_information ti; 2962*1da177e4SLinus Torvalds __u32 last_track; 2963*1da177e4SLinus Torvalds int ret = -1, ti_size; 2964*1da177e4SLinus Torvalds 2965*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_GENERIC_PACKET)) 2966*1da177e4SLinus Torvalds goto use_toc; 2967*1da177e4SLinus Torvalds 2968*1da177e4SLinus Torvalds ret = cdrom_get_disc_info(cdi, &di); 2969*1da177e4SLinus Torvalds if (ret < (int)(offsetof(typeof(di), last_track_lsb) 2970*1da177e4SLinus Torvalds + sizeof(di.last_track_lsb))) 2971*1da177e4SLinus Torvalds goto use_toc; 2972*1da177e4SLinus Torvalds 2973*1da177e4SLinus Torvalds /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ 2974*1da177e4SLinus Torvalds last_track = (di.last_track_msb << 8) | di.last_track_lsb; 2975*1da177e4SLinus Torvalds ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); 2976*1da177e4SLinus Torvalds if (ti_size < (int)offsetof(typeof(ti), track_start)) 2977*1da177e4SLinus Torvalds goto use_toc; 2978*1da177e4SLinus Torvalds 2979*1da177e4SLinus Torvalds /* if this track is blank, try the previous. */ 2980*1da177e4SLinus Torvalds if (ti.blank) { 2981*1da177e4SLinus Torvalds if (last_track==1) 2982*1da177e4SLinus Torvalds goto use_toc; 2983*1da177e4SLinus Torvalds last_track--; 2984*1da177e4SLinus Torvalds ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); 2985*1da177e4SLinus Torvalds } 2986*1da177e4SLinus Torvalds 2987*1da177e4SLinus Torvalds if (ti_size < (int)(offsetof(typeof(ti), track_size) 2988*1da177e4SLinus Torvalds + sizeof(ti.track_size))) 2989*1da177e4SLinus Torvalds goto use_toc; 2990*1da177e4SLinus Torvalds 2991*1da177e4SLinus Torvalds /* if last recorded field is valid, return it. */ 2992*1da177e4SLinus Torvalds if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) 2993*1da177e4SLinus Torvalds + sizeof(ti.last_rec_address))) { 2994*1da177e4SLinus Torvalds *last_written = be32_to_cpu(ti.last_rec_address); 2995*1da177e4SLinus Torvalds } else { 2996*1da177e4SLinus Torvalds /* make it up instead */ 2997*1da177e4SLinus Torvalds *last_written = be32_to_cpu(ti.track_start) + 2998*1da177e4SLinus Torvalds be32_to_cpu(ti.track_size); 2999*1da177e4SLinus Torvalds if (ti.free_blocks) 3000*1da177e4SLinus Torvalds *last_written -= (be32_to_cpu(ti.free_blocks) + 7); 3001*1da177e4SLinus Torvalds } 3002*1da177e4SLinus Torvalds return 0; 3003*1da177e4SLinus Torvalds 3004*1da177e4SLinus Torvalds /* this is where we end up if the drive either can't do a 3005*1da177e4SLinus Torvalds GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if 3006*1da177e4SLinus Torvalds it doesn't give enough information or fails. then we return 3007*1da177e4SLinus Torvalds the toc contents. */ 3008*1da177e4SLinus Torvalds use_toc: 3009*1da177e4SLinus Torvalds toc.cdte_format = CDROM_MSF; 3010*1da177e4SLinus Torvalds toc.cdte_track = CDROM_LEADOUT; 3011*1da177e4SLinus Torvalds if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) 3012*1da177e4SLinus Torvalds return ret; 3013*1da177e4SLinus Torvalds sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); 3014*1da177e4SLinus Torvalds *last_written = toc.cdte_addr.lba; 3015*1da177e4SLinus Torvalds return 0; 3016*1da177e4SLinus Torvalds } 3017*1da177e4SLinus Torvalds 3018*1da177e4SLinus Torvalds /* return the next writable block. also for udf file system. */ 3019*1da177e4SLinus Torvalds static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable) 3020*1da177e4SLinus Torvalds { 3021*1da177e4SLinus Torvalds disc_information di; 3022*1da177e4SLinus Torvalds track_information ti; 3023*1da177e4SLinus Torvalds __u16 last_track; 3024*1da177e4SLinus Torvalds int ret, ti_size; 3025*1da177e4SLinus Torvalds 3026*1da177e4SLinus Torvalds if (!CDROM_CAN(CDC_GENERIC_PACKET)) 3027*1da177e4SLinus Torvalds goto use_last_written; 3028*1da177e4SLinus Torvalds 3029*1da177e4SLinus Torvalds ret = cdrom_get_disc_info(cdi, &di); 3030*1da177e4SLinus Torvalds if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) 3031*1da177e4SLinus Torvalds + sizeof(di.last_track_lsb)) 3032*1da177e4SLinus Torvalds goto use_last_written; 3033*1da177e4SLinus Torvalds 3034*1da177e4SLinus Torvalds /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ 3035*1da177e4SLinus Torvalds last_track = (di.last_track_msb << 8) | di.last_track_lsb; 3036*1da177e4SLinus Torvalds ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); 3037*1da177e4SLinus Torvalds if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) 3038*1da177e4SLinus Torvalds goto use_last_written; 3039*1da177e4SLinus Torvalds 3040*1da177e4SLinus Torvalds /* if this track is blank, try the previous. */ 3041*1da177e4SLinus Torvalds if (ti.blank) { 3042*1da177e4SLinus Torvalds if (last_track == 1) 3043*1da177e4SLinus Torvalds goto use_last_written; 3044*1da177e4SLinus Torvalds last_track--; 3045*1da177e4SLinus Torvalds ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); 3046*1da177e4SLinus Torvalds if (ti_size < 0) 3047*1da177e4SLinus Torvalds goto use_last_written; 3048*1da177e4SLinus Torvalds } 3049*1da177e4SLinus Torvalds 3050*1da177e4SLinus Torvalds /* if next recordable address field is valid, use it. */ 3051*1da177e4SLinus Torvalds if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) 3052*1da177e4SLinus Torvalds + sizeof(ti.next_writable)) { 3053*1da177e4SLinus Torvalds *next_writable = be32_to_cpu(ti.next_writable); 3054*1da177e4SLinus Torvalds return 0; 3055*1da177e4SLinus Torvalds } 3056*1da177e4SLinus Torvalds 3057*1da177e4SLinus Torvalds use_last_written: 3058*1da177e4SLinus Torvalds if ((ret = cdrom_get_last_written(cdi, next_writable))) { 3059*1da177e4SLinus Torvalds *next_writable = 0; 3060*1da177e4SLinus Torvalds return ret; 3061*1da177e4SLinus Torvalds } else { 3062*1da177e4SLinus Torvalds *next_writable += 7; 3063*1da177e4SLinus Torvalds return 0; 3064*1da177e4SLinus Torvalds } 3065*1da177e4SLinus Torvalds } 3066*1da177e4SLinus Torvalds 3067*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_get_last_written); 3068*1da177e4SLinus Torvalds EXPORT_SYMBOL(register_cdrom); 3069*1da177e4SLinus Torvalds EXPORT_SYMBOL(unregister_cdrom); 3070*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_open); 3071*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_release); 3072*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_ioctl); 3073*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_media_changed); 3074*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_number_of_slots); 3075*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_mode_select); 3076*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_mode_sense); 3077*1da177e4SLinus Torvalds EXPORT_SYMBOL(init_cdrom_command); 3078*1da177e4SLinus Torvalds EXPORT_SYMBOL(cdrom_get_media_event); 3079*1da177e4SLinus Torvalds 3080*1da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 3081*1da177e4SLinus Torvalds 3082*1da177e4SLinus Torvalds #define CDROM_STR_SIZE 1000 3083*1da177e4SLinus Torvalds 3084*1da177e4SLinus Torvalds static struct cdrom_sysctl_settings { 3085*1da177e4SLinus Torvalds char info[CDROM_STR_SIZE]; /* general info */ 3086*1da177e4SLinus Torvalds int autoclose; /* close tray upon mount, etc */ 3087*1da177e4SLinus Torvalds int autoeject; /* eject on umount */ 3088*1da177e4SLinus Torvalds int debug; /* turn on debugging messages */ 3089*1da177e4SLinus Torvalds int lock; /* lock the door on device open */ 3090*1da177e4SLinus Torvalds int check; /* check media type */ 3091*1da177e4SLinus Torvalds } cdrom_sysctl_settings; 3092*1da177e4SLinus Torvalds 3093*1da177e4SLinus Torvalds static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, 3094*1da177e4SLinus Torvalds void __user *buffer, size_t *lenp, loff_t *ppos) 3095*1da177e4SLinus Torvalds { 3096*1da177e4SLinus Torvalds int pos; 3097*1da177e4SLinus Torvalds struct cdrom_device_info *cdi; 3098*1da177e4SLinus Torvalds char *info = cdrom_sysctl_settings.info; 3099*1da177e4SLinus Torvalds 3100*1da177e4SLinus Torvalds if (!*lenp || (*ppos && !write)) { 3101*1da177e4SLinus Torvalds *lenp = 0; 3102*1da177e4SLinus Torvalds return 0; 3103*1da177e4SLinus Torvalds } 3104*1da177e4SLinus Torvalds 3105*1da177e4SLinus Torvalds pos = sprintf(info, "CD-ROM information, " VERSION "\n"); 3106*1da177e4SLinus Torvalds 3107*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\ndrive name:\t"); 3108*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3109*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%s", cdi->name); 3110*1da177e4SLinus Torvalds 3111*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\ndrive speed:\t"); 3112*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3113*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", cdi->speed); 3114*1da177e4SLinus Torvalds 3115*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\ndrive # of slots:"); 3116*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3117*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", cdi->capacity); 3118*1da177e4SLinus Torvalds 3119*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan close tray:\t"); 3120*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3121*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); 3122*1da177e4SLinus Torvalds 3123*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan open tray:\t"); 3124*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3125*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); 3126*1da177e4SLinus Torvalds 3127*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan lock tray:\t"); 3128*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3129*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); 3130*1da177e4SLinus Torvalds 3131*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan change speed:"); 3132*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3133*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); 3134*1da177e4SLinus Torvalds 3135*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan select disk:"); 3136*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3137*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); 3138*1da177e4SLinus Torvalds 3139*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan read multisession:"); 3140*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3141*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); 3142*1da177e4SLinus Torvalds 3143*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan read MCN:\t"); 3144*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3145*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); 3146*1da177e4SLinus Torvalds 3147*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nReports media changed:"); 3148*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3149*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); 3150*1da177e4SLinus Torvalds 3151*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan play audio:\t"); 3152*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3153*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); 3154*1da177e4SLinus Torvalds 3155*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write CD-R:\t"); 3156*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3157*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); 3158*1da177e4SLinus Torvalds 3159*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write CD-RW:"); 3160*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3161*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); 3162*1da177e4SLinus Torvalds 3163*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan read DVD:\t"); 3164*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3165*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); 3166*1da177e4SLinus Torvalds 3167*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write DVD-R:"); 3168*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3169*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); 3170*1da177e4SLinus Torvalds 3171*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write DVD-RAM:"); 3172*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3173*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); 3174*1da177e4SLinus Torvalds 3175*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan read MRW:\t"); 3176*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3177*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0); 3178*1da177e4SLinus Torvalds 3179*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write MRW:\t"); 3180*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3181*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); 3182*1da177e4SLinus Torvalds 3183*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\nCan write RAM:\t"); 3184*1da177e4SLinus Torvalds for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) 3185*1da177e4SLinus Torvalds pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0); 3186*1da177e4SLinus Torvalds 3187*1da177e4SLinus Torvalds strcpy(info+pos,"\n\n"); 3188*1da177e4SLinus Torvalds 3189*1da177e4SLinus Torvalds return proc_dostring(ctl, write, filp, buffer, lenp, ppos); 3190*1da177e4SLinus Torvalds } 3191*1da177e4SLinus Torvalds 3192*1da177e4SLinus Torvalds /* Unfortunately, per device settings are not implemented through 3193*1da177e4SLinus Torvalds procfs/sysctl yet. When they are, this will naturally disappear. For now 3194*1da177e4SLinus Torvalds just update all drives. Later this will become the template on which 3195*1da177e4SLinus Torvalds new registered drives will be based. */ 3196*1da177e4SLinus Torvalds static void cdrom_update_settings(void) 3197*1da177e4SLinus Torvalds { 3198*1da177e4SLinus Torvalds struct cdrom_device_info *cdi; 3199*1da177e4SLinus Torvalds 3200*1da177e4SLinus Torvalds for (cdi = topCdromPtr; cdi != NULL; cdi = cdi->next) { 3201*1da177e4SLinus Torvalds if (autoclose && CDROM_CAN(CDC_CLOSE_TRAY)) 3202*1da177e4SLinus Torvalds cdi->options |= CDO_AUTO_CLOSE; 3203*1da177e4SLinus Torvalds else if (!autoclose) 3204*1da177e4SLinus Torvalds cdi->options &= ~CDO_AUTO_CLOSE; 3205*1da177e4SLinus Torvalds if (autoeject && CDROM_CAN(CDC_OPEN_TRAY)) 3206*1da177e4SLinus Torvalds cdi->options |= CDO_AUTO_EJECT; 3207*1da177e4SLinus Torvalds else if (!autoeject) 3208*1da177e4SLinus Torvalds cdi->options &= ~CDO_AUTO_EJECT; 3209*1da177e4SLinus Torvalds if (lockdoor && CDROM_CAN(CDC_LOCK)) 3210*1da177e4SLinus Torvalds cdi->options |= CDO_LOCK; 3211*1da177e4SLinus Torvalds else if (!lockdoor) 3212*1da177e4SLinus Torvalds cdi->options &= ~CDO_LOCK; 3213*1da177e4SLinus Torvalds if (check_media_type) 3214*1da177e4SLinus Torvalds cdi->options |= CDO_CHECK_TYPE; 3215*1da177e4SLinus Torvalds else 3216*1da177e4SLinus Torvalds cdi->options &= ~CDO_CHECK_TYPE; 3217*1da177e4SLinus Torvalds } 3218*1da177e4SLinus Torvalds } 3219*1da177e4SLinus Torvalds 3220*1da177e4SLinus Torvalds static int cdrom_sysctl_handler(ctl_table *ctl, int write, struct file * filp, 3221*1da177e4SLinus Torvalds void __user *buffer, size_t *lenp, loff_t *ppos) 3222*1da177e4SLinus Torvalds { 3223*1da177e4SLinus Torvalds int *valp = ctl->data; 3224*1da177e4SLinus Torvalds int val = *valp; 3225*1da177e4SLinus Torvalds int ret; 3226*1da177e4SLinus Torvalds 3227*1da177e4SLinus Torvalds ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); 3228*1da177e4SLinus Torvalds 3229*1da177e4SLinus Torvalds if (write && *valp != val) { 3230*1da177e4SLinus Torvalds 3231*1da177e4SLinus Torvalds /* we only care for 1 or 0. */ 3232*1da177e4SLinus Torvalds if (*valp) 3233*1da177e4SLinus Torvalds *valp = 1; 3234*1da177e4SLinus Torvalds else 3235*1da177e4SLinus Torvalds *valp = 0; 3236*1da177e4SLinus Torvalds 3237*1da177e4SLinus Torvalds switch (ctl->ctl_name) { 3238*1da177e4SLinus Torvalds case DEV_CDROM_AUTOCLOSE: { 3239*1da177e4SLinus Torvalds if (valp == &cdrom_sysctl_settings.autoclose) 3240*1da177e4SLinus Torvalds autoclose = cdrom_sysctl_settings.autoclose; 3241*1da177e4SLinus Torvalds break; 3242*1da177e4SLinus Torvalds } 3243*1da177e4SLinus Torvalds case DEV_CDROM_AUTOEJECT: { 3244*1da177e4SLinus Torvalds if (valp == &cdrom_sysctl_settings.autoeject) 3245*1da177e4SLinus Torvalds autoeject = cdrom_sysctl_settings.autoeject; 3246*1da177e4SLinus Torvalds break; 3247*1da177e4SLinus Torvalds } 3248*1da177e4SLinus Torvalds case DEV_CDROM_DEBUG: { 3249*1da177e4SLinus Torvalds if (valp == &cdrom_sysctl_settings.debug) 3250*1da177e4SLinus Torvalds debug = cdrom_sysctl_settings.debug; 3251*1da177e4SLinus Torvalds break; 3252*1da177e4SLinus Torvalds } 3253*1da177e4SLinus Torvalds case DEV_CDROM_LOCK: { 3254*1da177e4SLinus Torvalds if (valp == &cdrom_sysctl_settings.lock) 3255*1da177e4SLinus Torvalds lockdoor = cdrom_sysctl_settings.lock; 3256*1da177e4SLinus Torvalds break; 3257*1da177e4SLinus Torvalds } 3258*1da177e4SLinus Torvalds case DEV_CDROM_CHECK_MEDIA: { 3259*1da177e4SLinus Torvalds if (valp == &cdrom_sysctl_settings.check) 3260*1da177e4SLinus Torvalds check_media_type = cdrom_sysctl_settings.check; 3261*1da177e4SLinus Torvalds break; 3262*1da177e4SLinus Torvalds } 3263*1da177e4SLinus Torvalds } 3264*1da177e4SLinus Torvalds /* update the option flags according to the changes. we 3265*1da177e4SLinus Torvalds don't have per device options through sysctl yet, 3266*1da177e4SLinus Torvalds but we will have and then this will disappear. */ 3267*1da177e4SLinus Torvalds cdrom_update_settings(); 3268*1da177e4SLinus Torvalds } 3269*1da177e4SLinus Torvalds 3270*1da177e4SLinus Torvalds return ret; 3271*1da177e4SLinus Torvalds } 3272*1da177e4SLinus Torvalds 3273*1da177e4SLinus Torvalds /* Place files in /proc/sys/dev/cdrom */ 3274*1da177e4SLinus Torvalds static ctl_table cdrom_table[] = { 3275*1da177e4SLinus Torvalds { 3276*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_INFO, 3277*1da177e4SLinus Torvalds .procname = "info", 3278*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.info, 3279*1da177e4SLinus Torvalds .maxlen = CDROM_STR_SIZE, 3280*1da177e4SLinus Torvalds .mode = 0444, 3281*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_info, 3282*1da177e4SLinus Torvalds }, 3283*1da177e4SLinus Torvalds { 3284*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_AUTOCLOSE, 3285*1da177e4SLinus Torvalds .procname = "autoclose", 3286*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.autoclose, 3287*1da177e4SLinus Torvalds .maxlen = sizeof(int), 3288*1da177e4SLinus Torvalds .mode = 0644, 3289*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_handler, 3290*1da177e4SLinus Torvalds }, 3291*1da177e4SLinus Torvalds { 3292*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_AUTOEJECT, 3293*1da177e4SLinus Torvalds .procname = "autoeject", 3294*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.autoeject, 3295*1da177e4SLinus Torvalds .maxlen = sizeof(int), 3296*1da177e4SLinus Torvalds .mode = 0644, 3297*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_handler, 3298*1da177e4SLinus Torvalds }, 3299*1da177e4SLinus Torvalds { 3300*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_DEBUG, 3301*1da177e4SLinus Torvalds .procname = "debug", 3302*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.debug, 3303*1da177e4SLinus Torvalds .maxlen = sizeof(int), 3304*1da177e4SLinus Torvalds .mode = 0644, 3305*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_handler, 3306*1da177e4SLinus Torvalds }, 3307*1da177e4SLinus Torvalds { 3308*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_LOCK, 3309*1da177e4SLinus Torvalds .procname = "lock", 3310*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.lock, 3311*1da177e4SLinus Torvalds .maxlen = sizeof(int), 3312*1da177e4SLinus Torvalds .mode = 0644, 3313*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_handler, 3314*1da177e4SLinus Torvalds }, 3315*1da177e4SLinus Torvalds { 3316*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM_CHECK_MEDIA, 3317*1da177e4SLinus Torvalds .procname = "check_media", 3318*1da177e4SLinus Torvalds .data = &cdrom_sysctl_settings.check, 3319*1da177e4SLinus Torvalds .maxlen = sizeof(int), 3320*1da177e4SLinus Torvalds .mode = 0644, 3321*1da177e4SLinus Torvalds .proc_handler = &cdrom_sysctl_handler 3322*1da177e4SLinus Torvalds }, 3323*1da177e4SLinus Torvalds { .ctl_name = 0 } 3324*1da177e4SLinus Torvalds }; 3325*1da177e4SLinus Torvalds 3326*1da177e4SLinus Torvalds static ctl_table cdrom_cdrom_table[] = { 3327*1da177e4SLinus Torvalds { 3328*1da177e4SLinus Torvalds .ctl_name = DEV_CDROM, 3329*1da177e4SLinus Torvalds .procname = "cdrom", 3330*1da177e4SLinus Torvalds .maxlen = 0, 3331*1da177e4SLinus Torvalds .mode = 0555, 3332*1da177e4SLinus Torvalds .child = cdrom_table, 3333*1da177e4SLinus Torvalds }, 3334*1da177e4SLinus Torvalds { .ctl_name = 0 } 3335*1da177e4SLinus Torvalds }; 3336*1da177e4SLinus Torvalds 3337*1da177e4SLinus Torvalds /* Make sure that /proc/sys/dev is there */ 3338*1da177e4SLinus Torvalds static ctl_table cdrom_root_table[] = { 3339*1da177e4SLinus Torvalds { 3340*1da177e4SLinus Torvalds .ctl_name = CTL_DEV, 3341*1da177e4SLinus Torvalds .procname = "dev", 3342*1da177e4SLinus Torvalds .maxlen = 0, 3343*1da177e4SLinus Torvalds .mode = 0555, 3344*1da177e4SLinus Torvalds .child = cdrom_cdrom_table, 3345*1da177e4SLinus Torvalds }, 3346*1da177e4SLinus Torvalds { .ctl_name = 0 } 3347*1da177e4SLinus Torvalds }; 3348*1da177e4SLinus Torvalds static struct ctl_table_header *cdrom_sysctl_header; 3349*1da177e4SLinus Torvalds 3350*1da177e4SLinus Torvalds static void cdrom_sysctl_register(void) 3351*1da177e4SLinus Torvalds { 3352*1da177e4SLinus Torvalds static int initialized; 3353*1da177e4SLinus Torvalds 3354*1da177e4SLinus Torvalds if (initialized == 1) 3355*1da177e4SLinus Torvalds return; 3356*1da177e4SLinus Torvalds 3357*1da177e4SLinus Torvalds cdrom_sysctl_header = register_sysctl_table(cdrom_root_table, 1); 3358*1da177e4SLinus Torvalds if (cdrom_root_table->ctl_name && cdrom_root_table->child->de) 3359*1da177e4SLinus Torvalds cdrom_root_table->child->de->owner = THIS_MODULE; 3360*1da177e4SLinus Torvalds 3361*1da177e4SLinus Torvalds /* set the defaults */ 3362*1da177e4SLinus Torvalds cdrom_sysctl_settings.autoclose = autoclose; 3363*1da177e4SLinus Torvalds cdrom_sysctl_settings.autoeject = autoeject; 3364*1da177e4SLinus Torvalds cdrom_sysctl_settings.debug = debug; 3365*1da177e4SLinus Torvalds cdrom_sysctl_settings.lock = lockdoor; 3366*1da177e4SLinus Torvalds cdrom_sysctl_settings.check = check_media_type; 3367*1da177e4SLinus Torvalds 3368*1da177e4SLinus Torvalds initialized = 1; 3369*1da177e4SLinus Torvalds } 3370*1da177e4SLinus Torvalds 3371*1da177e4SLinus Torvalds static void cdrom_sysctl_unregister(void) 3372*1da177e4SLinus Torvalds { 3373*1da177e4SLinus Torvalds if (cdrom_sysctl_header) 3374*1da177e4SLinus Torvalds unregister_sysctl_table(cdrom_sysctl_header); 3375*1da177e4SLinus Torvalds } 3376*1da177e4SLinus Torvalds 3377*1da177e4SLinus Torvalds #endif /* CONFIG_SYSCTL */ 3378*1da177e4SLinus Torvalds 3379*1da177e4SLinus Torvalds static int __init cdrom_init(void) 3380*1da177e4SLinus Torvalds { 3381*1da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 3382*1da177e4SLinus Torvalds cdrom_sysctl_register(); 3383*1da177e4SLinus Torvalds #endif 3384*1da177e4SLinus Torvalds return 0; 3385*1da177e4SLinus Torvalds } 3386*1da177e4SLinus Torvalds 3387*1da177e4SLinus Torvalds static void __exit cdrom_exit(void) 3388*1da177e4SLinus Torvalds { 3389*1da177e4SLinus Torvalds printk(KERN_INFO "Uniform CD-ROM driver unloaded\n"); 3390*1da177e4SLinus Torvalds #ifdef CONFIG_SYSCTL 3391*1da177e4SLinus Torvalds cdrom_sysctl_unregister(); 3392*1da177e4SLinus Torvalds #endif 3393*1da177e4SLinus Torvalds } 3394*1da177e4SLinus Torvalds 3395*1da177e4SLinus Torvalds module_init(cdrom_init); 3396*1da177e4SLinus Torvalds module_exit(cdrom_exit); 3397*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 3398