xref: /openbmc/linux/drivers/cdrom/cdrom.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
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