[PATCH] sky2: optimize for 32 bit dma
[linux-2.6] / drivers / cdrom / mcdx.c
1 /*
2  * The Mitsumi CDROM interface
3  * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4  * VERSION: 2.14(hs)
5  *
6  * ... anyway, I'm back again, thanks to Marcin, he adopted
7  * large portions of my code (at least the parts containing
8  * my main thoughts ...)
9  *
10  ****************** H E L P *********************************
11  * If you ever plan to update your CD ROM drive and perhaps
12  * want to sell or simply give away your Mitsumi FX-001[DS]
13  * -- Please --
14  * mail me (heiko@lotte.sax.de).  When my last drive goes
15  * ballistic no more driver support will be available from me!
16  *************************************************************
17  *
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2, or (at your option)
21  * any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; see the file COPYING.  If not, write to
30  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31  *
32  * Thanks to
33  *  The Linux Community at all and ...
34  *  Martin Harriss (he wrote the first Mitsumi Driver)
35  *  Eberhard Moenkeberg (he gave me much support and the initial kick)
36  *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
37  *      improved the original driver)
38  *  Jon Tombs, Bjorn Ekwall (module support)
39  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
40  *  Gerd Knorr (he lent me his PhotoCD)
41  *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
42  *  Andreas Kies (testing the mysterious hang-ups)
43  *  Heiko Eissfeldt (VERIFY_READ/WRITE)
44  *  Marcin Dalecki (improved performance, shortened code)
45  *  ... somebody forgotten?
46  *
47  *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
48  *                     Removed init_module & cleanup_module in favor of 
49  *                     module_init & module_exit.
50  *                     Torben Mathiasen <tmm@image.dk>
51  */
52
53
54 #ifdef RCS
55 static const char *mcdx_c_version
56     = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57 #endif
58
59 #include <linux/module.h>
60
61 #include <linux/errno.h>
62 #include <linux/interrupt.h>
63 #include <linux/fs.h>
64 #include <linux/kernel.h>
65 #include <linux/cdrom.h>
66 #include <linux/ioport.h>
67 #include <linux/mm.h>
68 #include <linux/slab.h>
69 #include <linux/init.h>
70 #include <asm/io.h>
71 #include <asm/current.h>
72 #include <asm/uaccess.h>
73
74 #include <linux/major.h>
75 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76 #include <linux/blkdev.h>
77 #include <linux/devfs_fs_kernel.h>
78
79 #include "mcdx.h"
80
81 #ifndef HZ
82 #error HZ not defined
83 #endif
84
85 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
86
87 #if !MCDX_QUIET
88 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
89 #else
90 #define xinfo(fmt, args...) { ; }
91 #endif
92
93 #if MCDX_DEBUG
94 #define xtrace(lvl, fmt, args...) \
95                 { if (lvl > 0) \
96                         { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
97 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
98 #else
99 #define xtrace(lvl, fmt, args...) { ; }
100 #define xdebug(fmt, args...) { ; }
101 #endif
102
103 /* CONSTANTS *******************************************************/
104
105 /* Following are the number of sectors we _request_ from the drive
106    every time an access outside the already requested range is done.
107    The _direct_ size is the number of sectors we're allowed to skip
108    directly (performing a read instead of requesting the new sector
109    needed */
110 static const int REQUEST_SIZE = 800;    /* should be less then 255 * 4 */
111 static const int DIRECT_SIZE = 400;     /* should be less then REQUEST_SIZE */
112
113 enum drivemodes { TOC, DATA, RAW, COOKED };
114 enum datamodes { MODE0, MODE1, MODE2 };
115 enum resetmodes { SOFT, HARD };
116
117 static const int SINGLE = 0x01;         /* single speed drive (FX001S, LU) */
118 static const int DOUBLE = 0x02;         /* double speed drive (FX001D, ..? */
119 static const int DOOR = 0x04;           /* door locking capability */
120 static const int MULTI = 0x08;          /* multi session capability */
121
122 static const unsigned char READ1X = 0xc0;
123 static const unsigned char READ2X = 0xc1;
124
125
126 /* DECLARATIONS ****************************************************/
127 struct s_subqcode {
128         unsigned char control;
129         unsigned char tno;
130         unsigned char index;
131         struct cdrom_msf0 tt;
132         struct cdrom_msf0 dt;
133 };
134
135 struct s_diskinfo {
136         unsigned int n_first;
137         unsigned int n_last;
138         struct cdrom_msf0 msf_leadout;
139         struct cdrom_msf0 msf_first;
140 };
141
142 struct s_multi {
143         unsigned char multi;
144         struct cdrom_msf0 msf_last;
145 };
146
147 struct s_version {
148         unsigned char code;
149         unsigned char ver;
150 };
151
152 /* Per drive/controller stuff **************************************/
153
154 struct s_drive_stuff {
155         /* waitqueues */
156         wait_queue_head_t busyq;
157         wait_queue_head_t lockq;
158         wait_queue_head_t sleepq;
159
160         /* flags */
161         volatile int introk;    /* status of last irq operation */
162         volatile int busy;      /* drive performs an operation */
163         volatile int lock;      /* exclusive usage */
164
165         /* cd infos */
166         struct s_diskinfo di;
167         struct s_multi multi;
168         struct s_subqcode *toc; /* first entry of the toc array */
169         struct s_subqcode start;
170         struct s_subqcode stop;
171         int xa;                 /* 1 if xa disk */
172         int audio;              /* 1 if audio disk */
173         int audiostatus;
174
175         /* `buffer' control */
176         volatile int valid;     /* pending, ..., values are valid */
177         volatile int pending;   /* next sector to be read */
178         volatile int low_border;        /* first sector not to be skipped direct */
179         volatile int high_border;       /* first sector `out of area' */
180 #ifdef AK2
181         volatile int int_err;
182 #endif                          /* AK2 */
183
184         /* adds and odds */
185         unsigned wreg_data;     /* w data */
186         unsigned wreg_reset;    /* w hardware reset */
187         unsigned wreg_hcon;     /* w hardware conf */
188         unsigned wreg_chn;      /* w channel */
189         unsigned rreg_data;     /* r data */
190         unsigned rreg_status;   /* r status */
191
192         int irq;                /* irq used by this drive */
193         int present;            /* drive present and its capabilities */
194         unsigned char readcmd;  /* read cmd depends on single/double speed */
195         unsigned char playcmd;  /* play should always be single speed */
196         unsigned int xxx;       /* set if changed, reset while open */
197         unsigned int yyy;       /* set if changed, reset by media_changed */
198         int users;              /* keeps track of open/close */
199         int lastsector;         /* last block accessible */
200         int status;             /* last operation's error / status */
201         int readerrs;           /* # of blocks read w/o error */
202         struct cdrom_device_info info;
203         struct gendisk *disk;
204 };
205
206
207 /* Prototypes ******************************************************/
208
209 /*      The following prototypes are already declared elsewhere.  They are
210         repeated here to show what's going on.  And to sense, if they're
211         changed elsewhere. */
212
213 static int mcdx_init(void);
214
215 static int mcdx_block_open(struct inode *inode, struct file *file)
216 {
217         struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
218         return cdrom_open(&p->info, inode, file);
219 }
220
221 static int mcdx_block_release(struct inode *inode, struct file *file)
222 {
223         struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
224         return cdrom_release(&p->info, file);
225 }
226
227 static int mcdx_block_ioctl(struct inode *inode, struct file *file,
228                                 unsigned cmd, unsigned long arg)
229 {
230         struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
231         return cdrom_ioctl(file, &p->info, inode, cmd, arg);
232 }
233
234 static int mcdx_block_media_changed(struct gendisk *disk)
235 {
236         struct s_drive_stuff *p = disk->private_data;
237         return cdrom_media_changed(&p->info);
238 }
239
240 static struct block_device_operations mcdx_bdops =
241 {
242         .owner          = THIS_MODULE,
243         .open           = mcdx_block_open,
244         .release        = mcdx_block_release,
245         .ioctl          = mcdx_block_ioctl,
246         .media_changed  = mcdx_block_media_changed,
247 };
248
249
250 /*      Indirect exported functions. These functions are exported by their
251         addresses, such as mcdx_open and mcdx_close in the
252         structure mcdx_dops. */
253
254 /* exported by file_ops */
255 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
256 static void mcdx_close(struct cdrom_device_info *cdi);
257 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
258 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
259 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
260 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
261                             unsigned int cmd, void *arg);
262
263 /* misc internal support functions */
264 static void log2msf(unsigned int, struct cdrom_msf0 *);
265 static unsigned int msf2log(const struct cdrom_msf0 *);
266 static unsigned int uint2bcd(unsigned int);
267 static unsigned int bcd2uint(unsigned char);
268 static unsigned port(int *);
269 static int irq(int *);
270 static void mcdx_delay(struct s_drive_stuff *, long jifs);
271 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
272                          int nr_sectors);
273 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
274                      int nr_sectors);
275
276 static int mcdx_config(struct s_drive_stuff *, int);
277 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
278                                int);
279 static int mcdx_stop(struct s_drive_stuff *, int);
280 static int mcdx_hold(struct s_drive_stuff *, int);
281 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
282 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
283 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
284 static int mcdx_requestsubqcode(struct s_drive_stuff *,
285                                 struct s_subqcode *, int);
286 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
287                                      struct s_multi *, int);
288 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
289                                int);
290 static int mcdx_getstatus(struct s_drive_stuff *, int);
291 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
292 static int mcdx_talk(struct s_drive_stuff *,
293                      const unsigned char *cmd, size_t,
294                      void *buffer, size_t size, unsigned int timeout, int);
295 static int mcdx_readtoc(struct s_drive_stuff *);
296 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
297 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
298 static int mcdx_setattentuator(struct s_drive_stuff *,
299                                struct cdrom_volctrl *, int);
300
301 /* static variables ************************************************/
302
303 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
304 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
305 static DEFINE_SPINLOCK(mcdx_lock);
306 static struct request_queue *mcdx_queue;
307
308 /* You can only set the first two pairs, from old MODULE_PARM code.  */
309 static int mcdx_set(const char *val, struct kernel_param *kp)
310 {
311         get_options((char *)val, 4, (int *)mcdx_drive_map);
312         return 0;
313 }
314 module_param_call(mcdx, mcdx_set, NULL, NULL, 0);
315
316 static struct cdrom_device_ops mcdx_dops = {
317         .open           = mcdx_open,
318         .release        = mcdx_close,
319         .media_changed  = mcdx_media_changed,
320         .tray_move      = mcdx_tray_move,
321         .lock_door      = mcdx_lockdoor,
322         .audio_ioctl    = mcdx_audio_ioctl,
323         .capability     = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
324                           CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
325 };
326
327 /* KERNEL INTERFACE FUNCTIONS **************************************/
328
329
330 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
331                             unsigned int cmd, void *arg)
332 {
333         struct s_drive_stuff *stuffp = cdi->handle;
334
335         if (!stuffp->present)
336                 return -ENXIO;
337
338         if (stuffp->xxx) {
339                 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
340                         stuffp->lastsector = -1;
341                 } else {
342                         stuffp->lastsector = (CD_FRAMESIZE / 512)
343                             * msf2log(&stuffp->di.msf_leadout) - 1;
344                 }
345
346                 if (stuffp->toc) {
347                         kfree(stuffp->toc);
348                         stuffp->toc = NULL;
349                         if (-1 == mcdx_readtoc(stuffp))
350                                 return -1;
351                 }
352
353                 stuffp->xxx = 0;
354         }
355
356         switch (cmd) {
357         case CDROMSTART:{
358                         xtrace(IOCTL, "ioctl() START\n");
359                         /* Spin up the drive.  Don't think we can do this.
360                            * For now, ignore it.
361                          */
362                         return 0;
363                 }
364
365         case CDROMSTOP:{
366                         xtrace(IOCTL, "ioctl() STOP\n");
367                         stuffp->audiostatus = CDROM_AUDIO_INVALID;
368                         if (-1 == mcdx_stop(stuffp, 1))
369                                 return -EIO;
370                         return 0;
371                 }
372
373         case CDROMPLAYTRKIND:{
374                         struct cdrom_ti *ti = (struct cdrom_ti *) arg;
375
376                         xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
377                         if ((ti->cdti_trk0 < stuffp->di.n_first)
378                             || (ti->cdti_trk0 > stuffp->di.n_last)
379                             || (ti->cdti_trk1 < stuffp->di.n_first))
380                                 return -EINVAL;
381                         if (ti->cdti_trk1 > stuffp->di.n_last)
382                                 ti->cdti_trk1 = stuffp->di.n_last;
383                         xtrace(PLAYTRK, "ioctl() track %d to %d\n",
384                                ti->cdti_trk0, ti->cdti_trk1);
385                         return mcdx_playtrk(stuffp, ti);
386                 }
387
388         case CDROMPLAYMSF:{
389                         struct cdrom_msf *msf = (struct cdrom_msf *) arg;
390
391                         xtrace(IOCTL, "ioctl() PLAYMSF\n");
392
393                         if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
394                             && (-1 == mcdx_hold(stuffp, 1)))
395                                 return -EIO;
396
397                         msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
398                         msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
399                         msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
400
401                         msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
402                         msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
403                         msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
404
405                         stuffp->stop.dt.minute = msf->cdmsf_min1;
406                         stuffp->stop.dt.second = msf->cdmsf_sec1;
407                         stuffp->stop.dt.frame = msf->cdmsf_frame1;
408
409                         return mcdx_playmsf(stuffp, msf);
410                 }
411
412         case CDROMRESUME:{
413                         xtrace(IOCTL, "ioctl() RESUME\n");
414                         return mcdx_playtrk(stuffp, NULL);
415                 }
416
417         case CDROMREADTOCENTRY:{
418                         struct cdrom_tocentry *entry =
419                             (struct cdrom_tocentry *) arg;
420                         struct s_subqcode *tp = NULL;
421                         xtrace(IOCTL, "ioctl() READTOCENTRY\n");
422
423                         if (-1 == mcdx_readtoc(stuffp))
424                                 return -1;
425                         if (entry->cdte_track == CDROM_LEADOUT)
426                                 tp = &stuffp->toc[stuffp->di.n_last -
427                                                   stuffp->di.n_first + 1];
428                         else if (entry->cdte_track > stuffp->di.n_last
429                                  || entry->cdte_track < stuffp->di.n_first)
430                                 return -EINVAL;
431                         else
432                                 tp = &stuffp->toc[entry->cdte_track -
433                                                   stuffp->di.n_first];
434
435                         if (NULL == tp)
436                                 return -EIO;
437                         entry->cdte_adr = tp->control;
438                         entry->cdte_ctrl = tp->control >> 4;
439                         /* Always return stuff in MSF, and let the Uniform cdrom driver
440                            worry about what the user actually wants */
441                         entry->cdte_addr.msf.minute =
442                             bcd2uint(tp->dt.minute);
443                         entry->cdte_addr.msf.second =
444                             bcd2uint(tp->dt.second);
445                         entry->cdte_addr.msf.frame =
446                             bcd2uint(tp->dt.frame);
447                         return 0;
448                 }
449
450         case CDROMSUBCHNL:{
451                         struct cdrom_subchnl *sub =
452                             (struct cdrom_subchnl *) arg;
453                         struct s_subqcode q;
454
455                         xtrace(IOCTL, "ioctl() SUBCHNL\n");
456
457                         if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
458                                 return -EIO;
459
460                         xtrace(SUBCHNL, "audiostatus: %x\n",
461                                stuffp->audiostatus);
462                         sub->cdsc_audiostatus = stuffp->audiostatus;
463                         sub->cdsc_adr = q.control;
464                         sub->cdsc_ctrl = q.control >> 4;
465                         sub->cdsc_trk = bcd2uint(q.tno);
466                         sub->cdsc_ind = bcd2uint(q.index);
467
468                         xtrace(SUBCHNL, "trk %d, ind %d\n",
469                                sub->cdsc_trk, sub->cdsc_ind);
470                         /* Always return stuff in MSF, and let the Uniform cdrom driver
471                            worry about what the user actually wants */
472                         sub->cdsc_absaddr.msf.minute =
473                             bcd2uint(q.dt.minute);
474                         sub->cdsc_absaddr.msf.second =
475                             bcd2uint(q.dt.second);
476                         sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
477                         sub->cdsc_reladdr.msf.minute =
478                             bcd2uint(q.tt.minute);
479                         sub->cdsc_reladdr.msf.second =
480                             bcd2uint(q.tt.second);
481                         sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
482                         xtrace(SUBCHNL,
483                                "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
484                                sub->cdsc_absaddr.msf.minute,
485                                sub->cdsc_absaddr.msf.second,
486                                sub->cdsc_absaddr.msf.frame,
487                                sub->cdsc_reladdr.msf.minute,
488                                sub->cdsc_reladdr.msf.second,
489                                sub->cdsc_reladdr.msf.frame);
490
491                         return 0;
492                 }
493
494         case CDROMREADTOCHDR:{
495                         struct cdrom_tochdr *toc =
496                             (struct cdrom_tochdr *) arg;
497
498                         xtrace(IOCTL, "ioctl() READTOCHDR\n");
499                         toc->cdth_trk0 = stuffp->di.n_first;
500                         toc->cdth_trk1 = stuffp->di.n_last;
501                         xtrace(TOCHDR,
502                                "ioctl() track0 = %d, track1 = %d\n",
503                                stuffp->di.n_first, stuffp->di.n_last);
504                         return 0;
505                 }
506
507         case CDROMPAUSE:{
508                         xtrace(IOCTL, "ioctl() PAUSE\n");
509                         if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
510                                 return -EINVAL;
511                         if (-1 == mcdx_stop(stuffp, 1))
512                                 return -EIO;
513                         stuffp->audiostatus = CDROM_AUDIO_PAUSED;
514                         if (-1 ==
515                             mcdx_requestsubqcode(stuffp, &stuffp->start,
516                                                  1))
517                                 return -EIO;
518                         return 0;
519                 }
520
521         case CDROMMULTISESSION:{
522                         struct cdrom_multisession *ms =
523                             (struct cdrom_multisession *) arg;
524                         xtrace(IOCTL, "ioctl() MULTISESSION\n");
525                         /* Always return stuff in LBA, and let the Uniform cdrom driver
526                            worry about what the user actually wants */
527                         ms->addr.lba = msf2log(&stuffp->multi.msf_last);
528                         ms->xa_flag = !!stuffp->multi.multi;
529                         xtrace(MS,
530                                "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
531                                ms->xa_flag, ms->addr.lba,
532                                stuffp->multi.msf_last.minute,
533                                stuffp->multi.msf_last.second,
534                                stuffp->multi.msf_last.frame);
535
536                         return 0;
537                 }
538
539         case CDROMEJECT:{
540                         xtrace(IOCTL, "ioctl() EJECT\n");
541                         if (stuffp->users > 1)
542                                 return -EBUSY;
543                         return (mcdx_tray_move(cdi, 1));
544                 }
545
546         case CDROMCLOSETRAY:{
547                         xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
548                         return (mcdx_tray_move(cdi, 0));
549                 }
550
551         case CDROMVOLCTRL:{
552                         struct cdrom_volctrl *volctrl =
553                             (struct cdrom_volctrl *) arg;
554                         xtrace(IOCTL, "ioctl() VOLCTRL\n");
555
556 #if 0                           /* not tested! */
557                         /* adjust for the weirdness of workman (md) */
558                         /* can't test it (hs) */
559                         volctrl.channel2 = volctrl.channel1;
560                         volctrl.channel1 = volctrl.channel3 = 0x00;
561 #endif
562                         return mcdx_setattentuator(stuffp, volctrl, 2);
563                 }
564
565         default:
566                 return -EINVAL;
567         }
568 }
569
570 static void do_mcdx_request(request_queue_t * q)
571 {
572         struct s_drive_stuff *stuffp;
573         struct request *req;
574
575       again:
576
577         req = elv_next_request(q);
578         if (!req)
579                 return;
580
581         stuffp = req->rq_disk->private_data;
582
583         if (!stuffp->present) {
584                 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
585                 xtrace(REQUEST, "end_request(0): bad device\n");
586                 end_request(req, 0);
587                 return;
588         }
589
590         if (stuffp->audio) {
591                 xwarn("do_request() attempt to read from audio cd\n");
592                 xtrace(REQUEST, "end_request(0): read from audio\n");
593                 end_request(req, 0);
594                 return;
595         }
596
597         xtrace(REQUEST, "do_request() (%lu + %lu)\n",
598                req->sector, req->nr_sectors);
599
600         if (req->cmd != READ) {
601                 xwarn("do_request(): non-read command to cd!!\n");
602                 xtrace(REQUEST, "end_request(0): write\n");
603                 end_request(req, 0);
604                 return;
605         }
606         else {
607                 stuffp->status = 0;
608                 while (req->nr_sectors) {
609                         int i;
610
611                         i = mcdx_transfer(stuffp,
612                                           req->buffer,
613                                           req->sector,
614                                           req->nr_sectors);
615
616                         if (i == -1) {
617                                 end_request(req, 0);
618                                 goto again;
619                         }
620                         req->sector += i;
621                         req->nr_sectors -= i;
622                         req->buffer += (i * 512);
623                 }
624                 end_request(req, 1);
625                 goto again;
626
627                 xtrace(REQUEST, "end_request(1)\n");
628                 end_request(req, 1);
629         }
630
631         goto again;
632 }
633
634 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
635 {
636         struct s_drive_stuff *stuffp;
637         xtrace(OPENCLOSE, "open()\n");
638         stuffp = cdi->handle;
639         if (!stuffp->present)
640                 return -ENXIO;
641
642         /* Make the modules looking used ... (thanx bjorn).
643          * But we shouldn't forget to decrement the module counter
644          * on error return */
645
646         /* this is only done to test if the drive talks with us */
647         if (-1 == mcdx_getstatus(stuffp, 1))
648                 return -EIO;
649
650         if (stuffp->xxx) {
651
652                 xtrace(OPENCLOSE, "open() media changed\n");
653                 stuffp->audiostatus = CDROM_AUDIO_INVALID;
654                 stuffp->readcmd = 0;
655                 xtrace(OPENCLOSE, "open() Request multisession info\n");
656                 if (-1 ==
657                     mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
658                         xinfo("No multidiskinfo\n");
659         } else {
660                 /* multisession ? */
661                 if (!stuffp->multi.multi)
662                         stuffp->multi.msf_last.second = 2;
663
664                 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
665                        stuffp->multi.multi,
666                        stuffp->multi.msf_last.minute,
667                        stuffp->multi.msf_last.second,
668                        stuffp->multi.msf_last.frame);
669
670                 {;
671                 }               /* got multisession information */
672                 /* request the disks table of contents (aka diskinfo) */
673                 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
674
675                         stuffp->lastsector = -1;
676
677                 } else {
678
679                         stuffp->lastsector = (CD_FRAMESIZE / 512)
680                             * msf2log(&stuffp->di.msf_leadout) - 1;
681
682                         xtrace(OPENCLOSE,
683                                "open() start %d (%02x:%02x.%02x) %d\n",
684                                stuffp->di.n_first,
685                                stuffp->di.msf_first.minute,
686                                stuffp->di.msf_first.second,
687                                stuffp->di.msf_first.frame,
688                                msf2log(&stuffp->di.msf_first));
689                         xtrace(OPENCLOSE,
690                                "open() last %d (%02x:%02x.%02x) %d\n",
691                                stuffp->di.n_last,
692                                stuffp->di.msf_leadout.minute,
693                                stuffp->di.msf_leadout.second,
694                                stuffp->di.msf_leadout.frame,
695                                msf2log(&stuffp->di.msf_leadout));
696                 }
697
698                 if (stuffp->toc) {
699                         xtrace(MALLOC, "open() free old toc @ %p\n",
700                                stuffp->toc);
701                         kfree(stuffp->toc);
702
703                         stuffp->toc = NULL;
704                 }
705
706                 xtrace(OPENCLOSE, "open() init irq generation\n");
707                 if (-1 == mcdx_config(stuffp, 1))
708                         return -EIO;
709 #ifdef FALLBACK
710                 /* Set the read speed */
711                 xwarn("AAA %x AAA\n", stuffp->readcmd);
712                 if (stuffp->readerrs)
713                         stuffp->readcmd = READ1X;
714                 else
715                         stuffp->readcmd =
716                             stuffp->present | SINGLE ? READ1X : READ2X;
717                 xwarn("XXX %x XXX\n", stuffp->readcmd);
718 #else
719                 stuffp->readcmd =
720                     stuffp->present | SINGLE ? READ1X : READ2X;
721 #endif
722
723                 /* try to get the first sector, iff any ... */
724                 if (stuffp->lastsector >= 0) {
725                         char buf[512];
726                         int ans;
727                         int tries;
728
729                         stuffp->xa = 0;
730                         stuffp->audio = 0;
731
732                         for (tries = 6; tries; tries--) {
733
734                                 stuffp->introk = 1;
735
736                                 xtrace(OPENCLOSE, "open() try as %s\n",
737                                        stuffp->xa ? "XA" : "normal");
738                                 /* set data mode */
739                                 if (-1 == (ans = mcdx_setdatamode(stuffp,
740                                                                   stuffp->
741                                                                   xa ?
742                                                                   MODE2 :
743                                                                   MODE1,
744                                                                   1))) {
745                                         /* return -EIO; */
746                                         stuffp->xa = 0;
747                                         break;
748                                 }
749
750                                 if ((stuffp->audio = e_audio(ans)))
751                                         break;
752
753                                 while (0 ==
754                                        (ans =
755                                         mcdx_transfer(stuffp, buf, 0, 1)));
756
757                                 if (ans == 1)
758                                         break;
759                                 stuffp->xa = !stuffp->xa;
760                         }
761                 }
762                 /* xa disks will be read in raw mode, others not */
763                 if (-1 == mcdx_setdrivemode(stuffp,
764                                             stuffp->xa ? RAW : COOKED,
765                                             1))
766                         return -EIO;
767                 if (stuffp->audio) {
768                         xinfo("open() audio disk found\n");
769                 } else if (stuffp->lastsector >= 0) {
770                         xinfo("open() %s%s disk found\n",
771                               stuffp->xa ? "XA / " : "",
772                               stuffp->multi.
773                               multi ? "Multi Session" : "Single Session");
774                 }
775         }
776         stuffp->xxx = 0;
777         stuffp->users++;
778         return 0;
779 }
780
781 static void mcdx_close(struct cdrom_device_info *cdi)
782 {
783         struct s_drive_stuff *stuffp;
784
785         xtrace(OPENCLOSE, "close()\n");
786
787         stuffp = cdi->handle;
788
789         --stuffp->users;
790 }
791
792 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
793 /*      Return: 1 if media changed since last call to this function
794                         0 otherwise */
795 {
796         struct s_drive_stuff *stuffp;
797
798         xinfo("mcdx_media_changed called for device %s\n", cdi->name);
799
800         stuffp = cdi->handle;
801         mcdx_getstatus(stuffp, 1);
802
803         if (stuffp->yyy == 0)
804                 return 0;
805
806         stuffp->yyy = 0;
807         return 1;
808 }
809
810 #ifndef MODULE
811 static int __init mcdx_setup(char *str)
812 {
813         int pi[4];
814         (void) get_options(str, ARRAY_SIZE(pi), pi);
815
816         if (pi[0] > 0)
817                 mcdx_drive_map[0][0] = pi[1];
818         if (pi[0] > 1)
819                 mcdx_drive_map[0][1] = pi[2];
820         return 1;
821 }
822
823 __setup("mcdx=", mcdx_setup);
824
825 #endif
826
827 /* DIRTY PART ******************************************************/
828
829 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
830 /* This routine is used for sleeping.
831  * A jifs value <0 means NO sleeping,
832  *              =0 means minimal sleeping (let the kernel
833  *                 run for other processes)
834  *              >0 means at least sleep for that amount.
835  *      May be we could use a simple count loop w/ jumps to itself, but
836  *      I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
837 {
838         if (jifs < 0)
839                 return;
840
841         xtrace(SLEEP, "*** delay: sleepq\n");
842         interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
843         xtrace(SLEEP, "delay awoken\n");
844         if (signal_pending(current)) {
845                 xtrace(SLEEP, "got signal\n");
846         }
847 }
848
849 static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
850 {
851         struct s_drive_stuff *stuffp = dev_id;
852         unsigned char b;
853
854         if (stuffp == NULL) {
855                 xwarn("mcdx: no device for intr %d\n", irq);
856                 return IRQ_NONE;
857         }
858 #ifdef AK2
859         if (!stuffp->busy && stuffp->pending)
860                 stuffp->int_err = 1;
861
862 #endif                          /* AK2 */
863         /* get the interrupt status */
864         b = inb(stuffp->rreg_status);
865         stuffp->introk = ~b & MCDX_RBIT_DTEN;
866
867         /* NOTE: We only should get interrupts if the data we
868          * requested are ready to transfer.
869          * But the drive seems to generate ``asynchronous'' interrupts
870          * on several error conditions too.  (Despite the err int enable
871          * setting during initialisation) */
872
873         /* if not ok, read the next byte as the drives status */
874         if (!stuffp->introk) {
875                 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
876                 if (~b & MCDX_RBIT_STEN) {
877                         xinfo("intr() irq %d    status 0x%02x\n",
878                               irq, inb(stuffp->rreg_data));
879                 } else {
880                         xinfo("intr() irq %d ambiguous hw status\n", irq);
881                 }
882         } else {
883                 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
884         }
885
886         stuffp->busy = 0;
887         wake_up_interruptible(&stuffp->busyq);
888         return IRQ_HANDLED;
889 }
890
891
892 static int mcdx_talk(struct s_drive_stuff *stuffp,
893           const unsigned char *cmd, size_t cmdlen,
894           void *buffer, size_t size, unsigned int timeout, int tries)
895 /* Send a command to the drive, wait for the result.
896  * returns -1 on timeout, drive status otherwise
897  * If buffer is not zero, the result (length size) is stored there.
898  * If buffer is zero the size should be the number of bytes to read
899  * from the drive.  These bytes are discarded.
900  */
901 {
902         int st;
903         char c;
904         int discard;
905
906         /* Somebody wants the data read? */
907         if ((discard = (buffer == NULL)))
908                 buffer = &c;
909
910         while (stuffp->lock) {
911                 xtrace(SLEEP, "*** talk: lockq\n");
912                 interruptible_sleep_on(&stuffp->lockq);
913                 xtrace(SLEEP, "talk: awoken\n");
914         }
915
916         stuffp->lock = 1;
917
918         /* An operation other then reading data destroys the
919            * data already requested and remembered in stuffp->request, ... */
920         stuffp->valid = 0;
921
922 #if MCDX_DEBUG & TALK
923         {
924                 unsigned char i;
925                 xtrace(TALK,
926                        "talk() %d / %d tries, res.size %d, command 0x%02x",
927                        tries, timeout, size, (unsigned char) cmd[0]);
928                 for (i = 1; i < cmdlen; i++)
929                         xtrace(TALK, " 0x%02x", cmd[i]);
930                 xtrace(TALK, "\n");
931         }
932 #endif
933
934         /*  give up if all tries are done (bad) or if the status
935          *  st != -1 (good) */
936         for (st = -1; st == -1 && tries; tries--) {
937
938                 char *bp = (char *) buffer;
939                 size_t sz = size;
940
941                 outsb(stuffp->wreg_data, cmd, cmdlen);
942                 xtrace(TALK, "talk() command sent\n");
943
944                 /* get the status byte */
945                 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
946                         xinfo("talk() %02x timed out (status), %d tr%s left\n",
947                              cmd[0], tries - 1, tries == 2 ? "y" : "ies");
948                         continue;
949                 }
950                 st = *bp;
951                 sz--;
952                 if (!discard)
953                         bp++;
954
955                 xtrace(TALK, "talk() got status 0x%02x\n", st);
956
957                 /* command error? */
958                 if (e_cmderr(st)) {
959                         xwarn("command error cmd = %02x %s \n",
960                               cmd[0], cmdlen > 1 ? "..." : "");
961                         st = -1;
962                         continue;
963                 }
964
965                 /* audio status? */
966                 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
967                         stuffp->audiostatus =
968                             e_audiobusy(st) ? CDROM_AUDIO_PLAY :
969                             CDROM_AUDIO_NO_STATUS;
970                 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
971                          && e_audiobusy(st) == 0)
972                         stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
973
974                 /* media change? */
975                 if (e_changed(st)) {
976                         xinfo("talk() media changed\n");
977                         stuffp->xxx = stuffp->yyy = 1;
978                 }
979
980                 /* now actually get the data */
981                 while (sz--) {
982                         if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
983                                 xinfo("talk() %02x timed out (data), %d tr%s left\n",
984                                      cmd[0], tries - 1,
985                                      tries == 2 ? "y" : "ies");
986                                 st = -1;
987                                 break;
988                         }
989                         if (!discard)
990                                 bp++;
991                         xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
992                 }
993         }
994
995 #if !MCDX_QUIET
996         if (!tries && st == -1)
997                 xinfo("talk() giving up\n");
998 #endif
999
1000         stuffp->lock = 0;
1001         wake_up_interruptible(&stuffp->lockq);
1002
1003         xtrace(TALK, "talk() done with 0x%02x\n", st);
1004         return st;
1005 }
1006
1007 /* MODULE STUFF ***********************************************************/
1008
1009 int __mcdx_init(void)
1010 {
1011         int i;
1012         int drives = 0;
1013
1014         mcdx_init();
1015         for (i = 0; i < MCDX_NDRIVES; i++) {
1016                 if (mcdx_stuffp[i]) {
1017                         xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1018                                i, mcdx_stuffp[i]);
1019                         drives++;
1020                 }
1021         }
1022
1023         if (!drives)
1024                 return -EIO;
1025
1026         return 0;
1027 }
1028
1029 static void __exit mcdx_exit(void)
1030 {
1031         int i;
1032
1033         xinfo("cleanup_module called\n");
1034
1035         for (i = 0; i < MCDX_NDRIVES; i++) {
1036                 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1037                 if (!stuffp)
1038                         continue;
1039                 del_gendisk(stuffp->disk);
1040                 if (unregister_cdrom(&stuffp->info)) {
1041                         printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1042                         continue;
1043                 }
1044                 put_disk(stuffp->disk);
1045                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1046                 free_irq(stuffp->irq, NULL);
1047                 if (stuffp->toc) {
1048                         xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1049                                stuffp->toc);
1050                         kfree(stuffp->toc);
1051                 }
1052                 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1053                        stuffp);
1054                 mcdx_stuffp[i] = NULL;
1055                 kfree(stuffp);
1056         }
1057
1058         if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1059                 xwarn("cleanup() unregister_blkdev() failed\n");
1060         }
1061         blk_cleanup_queue(mcdx_queue);
1062 #if !MCDX_QUIET
1063         else
1064         xinfo("cleanup() succeeded\n");
1065 #endif
1066 }
1067
1068 #ifdef MODULE
1069 module_init(__mcdx_init);
1070 #endif
1071 module_exit(mcdx_exit);
1072
1073
1074 /* Support functions ************************************************/
1075
1076 static int __init mcdx_init_drive(int drive)
1077 {
1078         struct s_version version;
1079         struct gendisk *disk;
1080         struct s_drive_stuff *stuffp;
1081         int size = sizeof(*stuffp);
1082         char msg[80];
1083
1084         xtrace(INIT, "init() try drive %d\n", drive);
1085
1086         xtrace(INIT, "kmalloc space for stuffpt's\n");
1087         xtrace(MALLOC, "init() malloc %d bytes\n", size);
1088         if (!(stuffp = kzalloc(size, GFP_KERNEL))) {
1089                 xwarn("init() malloc failed\n");
1090                 return 1;
1091         }
1092
1093         disk = alloc_disk(1);
1094         if (!disk) {
1095                 xwarn("init() malloc failed\n");
1096                 kfree(stuffp);
1097                 return 1;
1098         }
1099
1100         xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1101                sizeof(*stuffp), stuffp);
1102
1103         /* set default values */
1104         stuffp->present = 0;    /* this should be 0 already */
1105         stuffp->toc = NULL;     /* this should be NULL already */
1106
1107         /* setup our irq and i/o addresses */
1108         stuffp->irq = irq(mcdx_drive_map[drive]);
1109         stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1110         stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1111         stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1112         stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1113
1114         init_waitqueue_head(&stuffp->busyq);
1115         init_waitqueue_head(&stuffp->lockq);
1116         init_waitqueue_head(&stuffp->sleepq);
1117
1118         /* check if i/o addresses are available */
1119         if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1120                 xwarn("0x%03x,%d: Init failed. "
1121                       "I/O ports (0x%03x..0x%03x) already in use.\n",
1122                       stuffp->wreg_data, stuffp->irq,
1123                       stuffp->wreg_data,
1124                       stuffp->wreg_data + MCDX_IO_SIZE - 1);
1125                 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1126                 kfree(stuffp);
1127                 put_disk(disk);
1128                 xtrace(INIT, "init() continue at next drive\n");
1129                 return 0;       /* next drive */
1130         }
1131
1132         xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1133                stuffp->wreg_data);
1134         xtrace(INIT, "init() hardware reset\n");
1135         mcdx_reset(stuffp, HARD, 1);
1136
1137         xtrace(INIT, "init() get version\n");
1138         if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1139                 /* failed, next drive */
1140                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1141                 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1142                       MCDX, stuffp->wreg_data, stuffp->irq);
1143                 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1144                 kfree(stuffp);
1145                 put_disk(disk);
1146                 xtrace(INIT, "init() continue at next drive\n");
1147                 return 0;
1148         }
1149
1150         switch (version.code) {
1151         case 'D':
1152                 stuffp->readcmd = READ2X;
1153                 stuffp->present = DOUBLE | DOOR | MULTI;
1154                 break;
1155         case 'F':
1156                 stuffp->readcmd = READ1X;
1157                 stuffp->present = SINGLE | DOOR | MULTI;
1158                 break;
1159         case 'M':
1160                 stuffp->readcmd = READ1X;
1161                 stuffp->present = SINGLE;
1162                 break;
1163         default:
1164                 stuffp->present = 0;
1165                 break;
1166         }
1167
1168         stuffp->playcmd = READ1X;
1169
1170         if (!stuffp->present) {
1171                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1172                 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1173                       MCDX, stuffp->wreg_data, stuffp->irq);
1174                 kfree(stuffp);
1175                 put_disk(disk);
1176                 return 0;       /* next drive */
1177         }
1178
1179         xtrace(INIT, "init() register blkdev\n");
1180         if (register_blkdev(MAJOR_NR, "mcdx")) {
1181                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1182                 kfree(stuffp);
1183                 put_disk(disk);
1184                 return 1;
1185         }
1186
1187         mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1188         if (!mcdx_queue) {
1189                 unregister_blkdev(MAJOR_NR, "mcdx");
1190                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1191                 kfree(stuffp);
1192                 put_disk(disk);
1193                 return 1;
1194         }
1195
1196         xtrace(INIT, "init() subscribe irq and i/o\n");
1197         if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) {
1198                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1199                 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1200                       MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1201                 stuffp->irq = 0;
1202                 blk_cleanup_queue(mcdx_queue);
1203                 kfree(stuffp);
1204                 put_disk(disk);
1205                 return 0;
1206         }
1207
1208         xtrace(INIT, "init() get garbage\n");
1209         {
1210                 int i;
1211                 mcdx_delay(stuffp, HZ / 2);
1212                 for (i = 100; i; i--)
1213                         (void) inb(stuffp->rreg_status);
1214         }
1215
1216
1217 #ifdef WE_KNOW_WHY
1218         /* irq 11 -> channel register */
1219         outb(0x50, stuffp->wreg_chn);
1220 #endif
1221
1222         xtrace(INIT, "init() set non dma but irq mode\n");
1223         mcdx_config(stuffp, 1);
1224
1225         stuffp->info.ops = &mcdx_dops;
1226         stuffp->info.speed = 2;
1227         stuffp->info.capacity = 1;
1228         stuffp->info.handle = stuffp;
1229         sprintf(stuffp->info.name, "mcdx%d", drive);
1230         disk->major = MAJOR_NR;
1231         disk->first_minor = drive;
1232         strcpy(disk->disk_name, stuffp->info.name);
1233         disk->fops = &mcdx_bdops;
1234         disk->flags = GENHD_FL_CD;
1235         stuffp->disk = disk;
1236
1237         sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1238                 " (Firmware version %c %x)\n",
1239                 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1240         mcdx_stuffp[drive] = stuffp;
1241         xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1242         if (register_cdrom(&stuffp->info) != 0) {
1243                 printk("Cannot register Mitsumi CD-ROM!\n");
1244                 free_irq(stuffp->irq, NULL);
1245                 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1246                 kfree(stuffp);
1247                 put_disk(disk);
1248                 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1249                         xwarn("cleanup() unregister_blkdev() failed\n");
1250                 blk_cleanup_queue(mcdx_queue);
1251                 return 2;
1252         }
1253         disk->private_data = stuffp;
1254         disk->queue = mcdx_queue;
1255         add_disk(disk);
1256         printk(msg);
1257         return 0;
1258 }
1259
1260 static int __init mcdx_init(void)
1261 {
1262         int drive;
1263         xwarn("Version 2.14(hs) \n");
1264
1265         xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1266
1267         /* zero the pointer array */
1268         for (drive = 0; drive < MCDX_NDRIVES; drive++)
1269                 mcdx_stuffp[drive] = NULL;
1270
1271         /* do the initialisation */
1272         for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1273                 switch (mcdx_init_drive(drive)) {
1274                 case 2:
1275                         return -EIO;
1276                 case 1:
1277                         break;
1278                 }
1279         }
1280         return 0;
1281 }
1282
1283 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1284               char *p, int sector, int nr_sectors)
1285 /*      This seems to do the actually transfer.  But it does more.  It
1286         keeps track of errors occurred and will (if possible) fall back
1287         to single speed on error.
1288         Return: -1 on timeout or other error
1289                         else status byte (as in stuff->st) */
1290 {
1291         int ans;
1292
1293         ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1294         return ans;
1295 #ifdef FALLBACK
1296         if (-1 == ans)
1297                 stuffp->readerrs++;
1298         else
1299                 return ans;
1300
1301         if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1302                 xwarn("XXX Already reading 1x -- no chance\n");
1303                 return -1;
1304         }
1305
1306         xwarn("XXX Fallback to 1x\n");
1307
1308         stuffp->readcmd = READ1X;
1309         return mcdx_transfer(stuffp, p, sector, nr_sectors);
1310 #endif
1311
1312 }
1313
1314
1315 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1316                      char *p, int sector, int nr_sectors)
1317 /*      This does actually the transfer from the drive.
1318         Return: -1 on timeout or other error
1319                         else status byte (as in stuff->st) */
1320 {
1321         int border;
1322         int done = 0;
1323         long timeout;
1324
1325         if (stuffp->audio) {
1326                 xwarn("Attempt to read from audio CD.\n");
1327                 return -1;
1328         }
1329
1330         if (!stuffp->readcmd) {
1331                 xinfo("Can't transfer from missing disk.\n");
1332                 return -1;
1333         }
1334
1335         while (stuffp->lock) {
1336                 interruptible_sleep_on(&stuffp->lockq);
1337         }
1338
1339         if (stuffp->valid && (sector >= stuffp->pending)
1340             && (sector < stuffp->low_border)) {
1341
1342                 /* All (or at least a part of the sectors requested) seems
1343                    * to be already requested, so we don't need to bother the
1344                    * drive with new requests ...
1345                    * Wait for the drive become idle, but first
1346                    * check for possible occurred errors --- the drive
1347                    * seems to report them asynchronously */
1348
1349
1350                 border = stuffp->high_border < (border =
1351                                                 sector + nr_sectors)
1352                     ? stuffp->high_border : border;
1353
1354                 stuffp->lock = current->pid;
1355
1356                 do {
1357
1358                         while (stuffp->busy) {
1359
1360                                 timeout =
1361                                     interruptible_sleep_on_timeout
1362                                     (&stuffp->busyq, 5 * HZ);
1363
1364                                 if (!stuffp->introk) {
1365                                         xtrace(XFER,
1366                                                "error via interrupt\n");
1367                                 } else if (!timeout) {
1368                                         xtrace(XFER, "timeout\n");
1369                                 } else if (signal_pending(current)) {
1370                                         xtrace(XFER, "signal\n");
1371                                 } else
1372                                         continue;
1373
1374                                 stuffp->lock = 0;
1375                                 stuffp->busy = 0;
1376                                 stuffp->valid = 0;
1377
1378                                 wake_up_interruptible(&stuffp->lockq);
1379                                 xtrace(XFER, "transfer() done (-1)\n");
1380                                 return -1;
1381                         }
1382
1383                         /* check if we need to set the busy flag (as we
1384                          * expect an interrupt */
1385                         stuffp->busy = (3 == (stuffp->pending & 3));
1386
1387                         /* Test if it's the first sector of a block,
1388                          * there we have to skip some bytes as we read raw data */
1389                         if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1390                                 const int HEAD =
1391                                     CD_FRAMESIZE_RAW - CD_XA_TAIL -
1392                                     CD_FRAMESIZE;
1393                                 insb(stuffp->rreg_data, p, HEAD);
1394                         }
1395
1396                         /* now actually read the data */
1397                         insb(stuffp->rreg_data, p, 512);
1398
1399                         /* test if it's the last sector of a block,
1400                          * if so, we have to handle XA special */
1401                         if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1402                                 char dummy[CD_XA_TAIL];
1403                                 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1404                         }
1405
1406                         if (stuffp->pending == sector) {
1407                                 p += 512;
1408                                 done++;
1409                                 sector++;
1410                         }
1411                 } while (++(stuffp->pending) < border);
1412
1413                 stuffp->lock = 0;
1414                 wake_up_interruptible(&stuffp->lockq);
1415
1416         } else {
1417
1418                 /* The requested sector(s) is/are out of the
1419                  * already requested range, so we have to bother the drive
1420                  * with a new request. */
1421
1422                 static unsigned char cmd[] = {
1423                         0,
1424                         0, 0, 0,
1425                         0, 0, 0
1426                 };
1427
1428                 cmd[0] = stuffp->readcmd;
1429
1430                 /* The numbers held in ->pending, ..., should be valid */
1431                 stuffp->valid = 1;
1432                 stuffp->pending = sector & ~3;
1433
1434                 /* do some sanity checks */
1435                 if (stuffp->pending > stuffp->lastsector) {
1436                         xwarn
1437                             ("transfer() sector %d from nirvana requested.\n",
1438                              stuffp->pending);
1439                         stuffp->status = MCDX_ST_EOM;
1440                         stuffp->valid = 0;
1441                         xtrace(XFER, "transfer() done (-1)\n");
1442                         return -1;
1443                 }
1444
1445                 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1446                     > stuffp->lastsector + 1) {
1447                         xtrace(XFER, "cut low_border\n");
1448                         stuffp->low_border = stuffp->lastsector + 1;
1449                 }
1450                 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1451                     > stuffp->lastsector + 1) {
1452                         xtrace(XFER, "cut high_border\n");
1453                         stuffp->high_border = stuffp->lastsector + 1;
1454                 }
1455
1456                 {               /* Convert the sector to be requested to MSF format */
1457                         struct cdrom_msf0 pending;
1458                         log2msf(stuffp->pending / 4, &pending);
1459                         cmd[1] = pending.minute;
1460                         cmd[2] = pending.second;
1461                         cmd[3] = pending.frame;
1462                 }
1463
1464                 cmd[6] =
1465                     (unsigned
1466                      char) ((stuffp->high_border - stuffp->pending) / 4);
1467                 xtrace(XFER, "[%2d]\n", cmd[6]);
1468
1469                 stuffp->busy = 1;
1470                 /* Now really issue the request command */
1471                 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1472
1473         }
1474 #ifdef AK2
1475         if (stuffp->int_err) {
1476                 stuffp->valid = 0;
1477                 stuffp->int_err = 0;
1478                 return -1;
1479         }
1480 #endif                          /* AK2 */
1481
1482         stuffp->low_border = (stuffp->low_border +=
1483                               done) <
1484             stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1485
1486         return done;
1487 }
1488
1489
1490 /*      Access to elements of the mcdx_drive_map members */
1491
1492 static unsigned port(int *ip)
1493 {
1494         return ip[0];
1495 }
1496 static int irq(int *ip)
1497 {
1498         return ip[1];
1499 }
1500
1501 /*      Misc number converters */
1502
1503 static unsigned int bcd2uint(unsigned char c)
1504 {
1505         return (c >> 4) * 10 + (c & 0x0f);
1506 }
1507
1508 static unsigned int uint2bcd(unsigned int ival)
1509 {
1510         return ((ival / 10) << 4) | (ival % 10);
1511 }
1512
1513 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1514 {
1515         l += CD_MSF_OFFSET;
1516         pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1517         pmsf->second = uint2bcd(l / 75);
1518         pmsf->frame = uint2bcd(l % 75);
1519 }
1520
1521 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1522 {
1523         return bcd2uint(pmsf->frame)
1524             + bcd2uint(pmsf->second) * 75
1525             + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1526 }
1527
1528 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1529 /*  Read the toc entries from the CD,
1530  *  Return: -1 on failure, else 0 */
1531 {
1532
1533         if (stuffp->toc) {
1534                 xtrace(READTOC, "ioctl() toc already read\n");
1535                 return 0;
1536         }
1537
1538         xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1539                stuffp->di.n_last - stuffp->di.n_first + 1);
1540
1541         if (-1 == mcdx_hold(stuffp, 1))
1542                 return -1;
1543
1544         xtrace(READTOC, "ioctl() tocmode\n");
1545         if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1546                 return -EIO;
1547
1548         /* all seems to be ok so far ... malloc */
1549         {
1550                 int size;
1551                 size =
1552                     sizeof(struct s_subqcode) * (stuffp->di.n_last -
1553                                                  stuffp->di.n_first + 2);
1554
1555                 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1556                 stuffp->toc = kmalloc(size, GFP_KERNEL);
1557                 if (!stuffp->toc) {
1558                         xwarn("Cannot malloc %d bytes for toc\n", size);
1559                         mcdx_setdrivemode(stuffp, DATA, 1);
1560                         return -EIO;
1561                 }
1562         }
1563
1564         /* now read actually the index */
1565         {
1566                 int trk;
1567                 int retries;
1568
1569                 for (trk = 0;
1570                      trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1571                      trk++)
1572                         stuffp->toc[trk].index = 0;
1573
1574                 for (retries = 300; retries; retries--) {       /* why 300? */
1575                         struct s_subqcode q;
1576                         unsigned int idx;
1577
1578                         if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1579                                 mcdx_setdrivemode(stuffp, DATA, 1);
1580                                 return -EIO;
1581                         }
1582
1583                         idx = bcd2uint(q.index);
1584
1585                         if ((idx > 0)
1586                             && (idx <= stuffp->di.n_last)
1587                             && (q.tno == 0)
1588                             && (stuffp->toc[idx - stuffp->di.n_first].
1589                                 index == 0)) {
1590                                 stuffp->toc[idx - stuffp->di.n_first] = q;
1591                                 xtrace(READTOC,
1592                                        "ioctl() toc idx %d (trk %d)\n",
1593                                        idx, trk);
1594                                 trk--;
1595                         }
1596                         if (trk == 0)
1597                                 break;
1598                 }
1599                 memset(&stuffp->
1600                        toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1601                        sizeof(stuffp->toc[0]));
1602                 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1603                             1].dt = stuffp->di.msf_leadout;
1604         }
1605
1606         /* unset toc mode */
1607         xtrace(READTOC, "ioctl() undo toc mode\n");
1608         if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1609                 return -EIO;
1610
1611 #if MCDX_DEBUG && READTOC
1612         {
1613                 int trk;
1614                 for (trk = 0;
1615                      trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1616                      trk++)
1617                         xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1618                                "  %02x:%02x.%02x  %02x:%02x.%02x\n",
1619                                trk + stuffp->di.n_first,
1620                                stuffp->toc[trk].control,
1621                                stuffp->toc[trk].tno,
1622                                stuffp->toc[trk].index,
1623                                stuffp->toc[trk].tt.minute,
1624                                stuffp->toc[trk].tt.second,
1625                                stuffp->toc[trk].tt.frame,
1626                                stuffp->toc[trk].dt.minute,
1627                                stuffp->toc[trk].dt.second,
1628                                stuffp->toc[trk].dt.frame);
1629         }
1630 #endif
1631
1632         return 0;
1633 }
1634
1635 static int
1636 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1637 {
1638         unsigned char cmd[7] = {
1639                 0, 0, 0, 0, 0, 0, 0
1640         };
1641
1642         if (!stuffp->readcmd) {
1643                 xinfo("Can't play from missing disk.\n");
1644                 return -1;
1645         }
1646
1647         cmd[0] = stuffp->playcmd;
1648
1649         cmd[1] = msf->cdmsf_min0;
1650         cmd[2] = msf->cdmsf_sec0;
1651         cmd[3] = msf->cdmsf_frame0;
1652         cmd[4] = msf->cdmsf_min1;
1653         cmd[5] = msf->cdmsf_sec1;
1654         cmd[6] = msf->cdmsf_frame1;
1655
1656         xtrace(PLAYMSF, "ioctl(): play %x "
1657                "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1658                cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1659
1660         outsb(stuffp->wreg_data, cmd, sizeof cmd);
1661
1662         if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1663                 xwarn("playmsf() timeout\n");
1664                 return -1;
1665         }
1666
1667         stuffp->audiostatus = CDROM_AUDIO_PLAY;
1668         return 0;
1669 }
1670
1671 static int
1672 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1673 {
1674         struct s_subqcode *p;
1675         struct cdrom_msf msf;
1676
1677         if (-1 == mcdx_readtoc(stuffp))
1678                 return -1;
1679
1680         if (ti)
1681                 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1682         else
1683                 p = &stuffp->start;
1684
1685         msf.cdmsf_min0 = p->dt.minute;
1686         msf.cdmsf_sec0 = p->dt.second;
1687         msf.cdmsf_frame0 = p->dt.frame;
1688
1689         if (ti) {
1690                 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1691                 stuffp->stop = *p;
1692         } else
1693                 p = &stuffp->stop;
1694
1695         msf.cdmsf_min1 = p->dt.minute;
1696         msf.cdmsf_sec1 = p->dt.second;
1697         msf.cdmsf_frame1 = p->dt.frame;
1698
1699         return mcdx_playmsf(stuffp, &msf);
1700 }
1701
1702
1703 /* Drive functions ************************************************/
1704
1705 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1706 {
1707         struct s_drive_stuff *stuffp = cdi->handle;
1708
1709         if (!stuffp->present)
1710                 return -ENXIO;
1711         if (!(stuffp->present & DOOR))
1712                 return -ENOSYS;
1713
1714         if (position)           /* 1: eject */
1715                 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1716         else                    /* 0: close */
1717                 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1718         return 1;
1719 }
1720
1721 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1722 {
1723         return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1724 }
1725
1726 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1727 {
1728         return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1729 }
1730
1731 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1732                      struct s_subqcode *sub, int tries)
1733 {
1734         char buf[11];
1735         int ans;
1736
1737         if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1738                                    2 * HZ, tries)))
1739                 return -1;
1740         sub->control = buf[1];
1741         sub->tno = buf[2];
1742         sub->index = buf[3];
1743         sub->tt.minute = buf[4];
1744         sub->tt.second = buf[5];
1745         sub->tt.frame = buf[6];
1746         sub->dt.minute = buf[8];
1747         sub->dt.second = buf[9];
1748         sub->dt.frame = buf[10];
1749
1750         return ans;
1751 }
1752
1753 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1754                           struct s_multi *multi, int tries)
1755 {
1756         char buf[5];
1757         int ans;
1758
1759         if (stuffp->present & MULTI) {
1760                 ans =
1761                     mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1762                               tries);
1763                 multi->multi = buf[1];
1764                 multi->msf_last.minute = buf[2];
1765                 multi->msf_last.second = buf[3];
1766                 multi->msf_last.frame = buf[4];
1767                 return ans;
1768         } else {
1769                 multi->multi = 0;
1770                 return 0;
1771         }
1772 }
1773
1774 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1775                     int tries)
1776 {
1777         char buf[9];
1778         int ans;
1779         ans =
1780             mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1781         if (ans == -1) {
1782                 info->n_first = 0;
1783                 info->n_last = 0;
1784         } else {
1785                 info->n_first = bcd2uint(buf[1]);
1786                 info->n_last = bcd2uint(buf[2]);
1787                 info->msf_leadout.minute = buf[3];
1788                 info->msf_leadout.second = buf[4];
1789                 info->msf_leadout.frame = buf[5];
1790                 info->msf_first.minute = buf[6];
1791                 info->msf_first.second = buf[7];
1792                 info->msf_first.frame = buf[8];
1793         }
1794         return ans;
1795 }
1796
1797 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1798                   int tries)
1799 {
1800         char cmd[2];
1801         int ans;
1802
1803         xtrace(HW, "setdrivemode() %d\n", mode);
1804
1805         if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1806                 return -1;
1807
1808         switch (mode) {
1809         case TOC:
1810                 cmd[1] |= 0x04;
1811                 break;
1812         case DATA:
1813                 cmd[1] &= ~0x04;
1814                 break;
1815         case RAW:
1816                 cmd[1] |= 0x40;
1817                 break;
1818         case COOKED:
1819                 cmd[1] &= ~0x40;
1820                 break;
1821         default:
1822                 break;
1823         }
1824         cmd[0] = 0x50;
1825         return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1826 }
1827
1828 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1829                  int tries)
1830 {
1831         unsigned char cmd[2] = { 0xa0 };
1832         xtrace(HW, "setdatamode() %d\n", mode);
1833         switch (mode) {
1834         case MODE0:
1835                 cmd[1] = 0x00;
1836                 break;
1837         case MODE1:
1838                 cmd[1] = 0x01;
1839                 break;
1840         case MODE2:
1841                 cmd[1] = 0x02;
1842                 break;
1843         default:
1844                 return -EINVAL;
1845         }
1846         return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1847 }
1848
1849 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1850 {
1851         char cmd[4];
1852
1853         xtrace(HW, "config()\n");
1854
1855         cmd[0] = 0x90;
1856
1857         cmd[1] = 0x10;          /* irq enable */
1858         cmd[2] = 0x05;          /* pre, err irq enable */
1859
1860         if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1861                 return -1;
1862
1863         cmd[1] = 0x02;          /* dma select */
1864         cmd[2] = 0x00;          /* no dma */
1865
1866         return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1867 }
1868
1869 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1870                     int tries)
1871 {
1872         char buf[3];
1873         int ans;
1874
1875         if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1876                                    1, buf, sizeof(buf), 2 * HZ, tries)))
1877                 return ans;
1878
1879         ver->code = buf[1];
1880         ver->ver = buf[2];
1881
1882         return ans;
1883 }
1884
1885 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1886 {
1887         if (mode == HARD) {
1888                 outb(0, stuffp->wreg_chn);      /* no dma, no irq -> hardware */
1889                 outb(0, stuffp->wreg_reset);    /* hw reset */
1890                 return 0;
1891         } else
1892                 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1893 }
1894
1895 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1896 {
1897         struct s_drive_stuff *stuffp = cdi->handle;
1898         char cmd[2] = { 0xfe };
1899
1900         if (!(stuffp->present & DOOR))
1901                 return -ENOSYS;
1902         if (stuffp->present & DOOR) {
1903                 cmd[1] = lock ? 0x01 : 0x00;
1904                 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1905         } else
1906                 return 0;
1907 }
1908
1909 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1910 {
1911         return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1912 }
1913
1914 static int
1915 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1916 {
1917         unsigned long timeout = to + jiffies;
1918         char c;
1919
1920         if (!buf)
1921                 buf = &c;
1922
1923         while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1924                 if (time_after(jiffies, timeout))
1925                         return -1;
1926                 mcdx_delay(stuffp, delay);
1927         }
1928
1929         *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1930
1931         return 0;
1932 }
1933
1934 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1935                     struct cdrom_volctrl *vol, int tries)
1936 {
1937         char cmd[5];
1938         cmd[0] = 0xae;
1939         cmd[1] = vol->channel0;
1940         cmd[2] = 0;
1941         cmd[3] = vol->channel1;
1942         cmd[4] = 0;
1943
1944         return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1945 }
1946
1947 MODULE_LICENSE("GPL");
1948 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);