2 * The Mitsumi CDROM interface
3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
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 ...)
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]
14 * mail me (heiko@lotte.sax.de). When my last drive goes
15 * ballistic no more driver support will be available from me!
16 *************************************************************
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)
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.
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.
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?
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>
55 static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
59 #include <linux/version.h>
60 #include <linux/module.h>
62 #include <linux/errno.h>
63 #include <linux/interrupt.h>
65 #include <linux/kernel.h>
66 #include <linux/cdrom.h>
67 #include <linux/ioport.h>
69 #include <linux/slab.h>
70 #include <linux/init.h>
72 #include <asm/current.h>
73 #include <asm/uaccess.h>
75 #include <linux/major.h>
76 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
77 #include <linux/blkdev.h>
78 #include <linux/devfs_fs_kernel.h>
80 /* for compatible parameter passing with "insmod" */
81 #define mcdx_drive_map mcdx
88 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
91 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
93 #define xinfo(fmt, args...) { ; }
97 #define xtrace(lvl, fmt, args...) \
99 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
100 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
102 #define xtrace(lvl, fmt, args...) { ; }
103 #define xdebug(fmt, args...) { ; }
106 /* CONSTANTS *******************************************************/
108 /* Following are the number of sectors we _request_ from the drive
109 every time an access outside the already requested range is done.
110 The _direct_ size is the number of sectors we're allowed to skip
111 directly (performing a read instead of requesting the new sector
113 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
114 const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
116 enum drivemodes { TOC, DATA, RAW, COOKED };
117 enum datamodes { MODE0, MODE1, MODE2 };
118 enum resetmodes { SOFT, HARD };
120 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
121 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
122 const int DOOR = 0x04; /* door locking capability */
123 const int MULTI = 0x08; /* multi session capability */
125 const unsigned char READ1X = 0xc0;
126 const unsigned char READ2X = 0xc1;
129 /* DECLARATIONS ****************************************************/
131 unsigned char control;
134 struct cdrom_msf0 tt;
135 struct cdrom_msf0 dt;
139 unsigned int n_first;
141 struct cdrom_msf0 msf_leadout;
142 struct cdrom_msf0 msf_first;
147 struct cdrom_msf0 msf_last;
155 /* Per drive/controller stuff **************************************/
157 struct s_drive_stuff {
159 wait_queue_head_t busyq;
160 wait_queue_head_t lockq;
161 wait_queue_head_t sleepq;
164 volatile int introk; /* status of last irq operation */
165 volatile int busy; /* drive performs an operation */
166 volatile int lock; /* exclusive usage */
169 struct s_diskinfo di;
170 struct s_multi multi;
171 struct s_subqcode *toc; /* first entry of the toc array */
172 struct s_subqcode start;
173 struct s_subqcode stop;
174 int xa; /* 1 if xa disk */
175 int audio; /* 1 if audio disk */
178 /* `buffer' control */
179 volatile int valid; /* pending, ..., values are valid */
180 volatile int pending; /* next sector to be read */
181 volatile int low_border; /* first sector not to be skipped direct */
182 volatile int high_border; /* first sector `out of area' */
184 volatile int int_err;
188 unsigned wreg_data; /* w data */
189 unsigned wreg_reset; /* w hardware reset */
190 unsigned wreg_hcon; /* w hardware conf */
191 unsigned wreg_chn; /* w channel */
192 unsigned rreg_data; /* r data */
193 unsigned rreg_status; /* r status */
195 int irq; /* irq used by this drive */
196 int present; /* drive present and its capabilities */
197 unsigned char readcmd; /* read cmd depends on single/double speed */
198 unsigned char playcmd; /* play should always be single speed */
199 unsigned int xxx; /* set if changed, reset while open */
200 unsigned int yyy; /* set if changed, reset by media_changed */
201 int users; /* keeps track of open/close */
202 int lastsector; /* last block accessible */
203 int status; /* last operation's error / status */
204 int readerrs; /* # of blocks read w/o error */
205 struct cdrom_device_info info;
206 struct gendisk *disk;
210 /* Prototypes ******************************************************/
212 /* The following prototypes are already declared elsewhere. They are
213 repeated here to show what's going on. And to sense, if they're
214 changed elsewhere. */
216 /* declared in blk.h */
218 void do_mcdx_request(request_queue_t * q);
220 static int mcdx_block_open(struct inode *inode, struct file *file)
222 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
223 return cdrom_open(&p->info, inode, file);
226 static int mcdx_block_release(struct inode *inode, struct file *file)
228 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
229 return cdrom_release(&p->info, file);
232 static int mcdx_block_ioctl(struct inode *inode, struct file *file,
233 unsigned cmd, unsigned long arg)
235 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
236 return cdrom_ioctl(&p->info, inode, cmd, arg);
239 static int mcdx_block_media_changed(struct gendisk *disk)
241 struct s_drive_stuff *p = disk->private_data;
242 return cdrom_media_changed(&p->info);
245 static struct block_device_operations mcdx_bdops =
247 .owner = THIS_MODULE,
248 .open = mcdx_block_open,
249 .release = mcdx_block_release,
250 .ioctl = mcdx_block_ioctl,
251 .media_changed = mcdx_block_media_changed,
255 /* Indirect exported functions. These functions are exported by their
256 addresses, such as mcdx_open and mcdx_close in the
257 structure mcdx_dops. */
259 /* exported by file_ops */
260 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
261 static void mcdx_close(struct cdrom_device_info *cdi);
262 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
263 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
264 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
265 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
266 unsigned int cmd, void *arg);
268 /* misc internal support functions */
269 static void log2msf(unsigned int, struct cdrom_msf0 *);
270 static unsigned int msf2log(const struct cdrom_msf0 *);
271 static unsigned int uint2bcd(unsigned int);
272 static unsigned int bcd2uint(unsigned char);
273 static unsigned port(int *);
274 static int irq(int *);
275 static void mcdx_delay(struct s_drive_stuff *, long jifs);
276 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
278 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
281 static int mcdx_config(struct s_drive_stuff *, int);
282 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
284 static int mcdx_stop(struct s_drive_stuff *, int);
285 static int mcdx_hold(struct s_drive_stuff *, int);
286 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
287 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
288 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
289 static int mcdx_requestsubqcode(struct s_drive_stuff *,
290 struct s_subqcode *, int);
291 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
292 struct s_multi *, int);
293 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
295 static int mcdx_getstatus(struct s_drive_stuff *, int);
296 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
297 static int mcdx_talk(struct s_drive_stuff *,
298 const unsigned char *cmd, size_t,
299 void *buffer, size_t size, unsigned int timeout, int);
300 static int mcdx_readtoc(struct s_drive_stuff *);
301 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
302 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
303 static int mcdx_setattentuator(struct s_drive_stuff *,
304 struct cdrom_volctrl *, int);
306 /* static variables ************************************************/
308 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
309 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
310 static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
311 0, 0, 0, 0, 0, 0, 0, 0
313 static spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED;
314 static struct request_queue *mcdx_queue;
315 MODULE_PARM(mcdx, "1-4i");
317 static struct cdrom_device_ops mcdx_dops = {
319 .release = mcdx_close,
320 .media_changed = mcdx_media_changed,
321 .tray_move = mcdx_tray_move,
322 .lock_door = mcdx_lockdoor,
323 .audio_ioctl = mcdx_audio_ioctl,
324 .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
325 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
328 /* KERNEL INTERFACE FUNCTIONS **************************************/
331 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
332 unsigned int cmd, void *arg)
334 struct s_drive_stuff *stuffp = cdi->handle;
336 if (!stuffp->present)
340 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
341 stuffp->lastsector = -1;
343 stuffp->lastsector = (CD_FRAMESIZE / 512)
344 * msf2log(&stuffp->di.msf_leadout) - 1;
350 if (-1 == mcdx_readtoc(stuffp))
359 xtrace(IOCTL, "ioctl() START\n");
360 /* Spin up the drive. Don't think we can do this.
361 * For now, ignore it.
367 xtrace(IOCTL, "ioctl() STOP\n");
368 stuffp->audiostatus = CDROM_AUDIO_INVALID;
369 if (-1 == mcdx_stop(stuffp, 1))
374 case CDROMPLAYTRKIND:{
375 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
377 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
378 if ((ti->cdti_trk0 < stuffp->di.n_first)
379 || (ti->cdti_trk0 > stuffp->di.n_last)
380 || (ti->cdti_trk1 < stuffp->di.n_first))
382 if (ti->cdti_trk1 > stuffp->di.n_last)
383 ti->cdti_trk1 = stuffp->di.n_last;
384 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
385 ti->cdti_trk0, ti->cdti_trk1);
386 return mcdx_playtrk(stuffp, ti);
390 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
392 xtrace(IOCTL, "ioctl() PLAYMSF\n");
394 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
395 && (-1 == mcdx_hold(stuffp, 1)))
398 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
399 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
400 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
402 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
403 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
404 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
406 stuffp->stop.dt.minute = msf->cdmsf_min1;
407 stuffp->stop.dt.second = msf->cdmsf_sec1;
408 stuffp->stop.dt.frame = msf->cdmsf_frame1;
410 return mcdx_playmsf(stuffp, msf);
414 xtrace(IOCTL, "ioctl() RESUME\n");
415 return mcdx_playtrk(stuffp, NULL);
418 case CDROMREADTOCENTRY:{
419 struct cdrom_tocentry *entry =
420 (struct cdrom_tocentry *) arg;
421 struct s_subqcode *tp = NULL;
422 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
424 if (-1 == mcdx_readtoc(stuffp))
426 if (entry->cdte_track == CDROM_LEADOUT)
427 tp = &stuffp->toc[stuffp->di.n_last -
428 stuffp->di.n_first + 1];
429 else if (entry->cdte_track > stuffp->di.n_last
430 || entry->cdte_track < stuffp->di.n_first)
433 tp = &stuffp->toc[entry->cdte_track -
438 entry->cdte_adr = tp->control;
439 entry->cdte_ctrl = tp->control >> 4;
440 /* Always return stuff in MSF, and let the Uniform cdrom driver
441 worry about what the user actually wants */
442 entry->cdte_addr.msf.minute =
443 bcd2uint(tp->dt.minute);
444 entry->cdte_addr.msf.second =
445 bcd2uint(tp->dt.second);
446 entry->cdte_addr.msf.frame =
447 bcd2uint(tp->dt.frame);
452 struct cdrom_subchnl *sub =
453 (struct cdrom_subchnl *) arg;
456 xtrace(IOCTL, "ioctl() SUBCHNL\n");
458 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
461 xtrace(SUBCHNL, "audiostatus: %x\n",
462 stuffp->audiostatus);
463 sub->cdsc_audiostatus = stuffp->audiostatus;
464 sub->cdsc_adr = q.control;
465 sub->cdsc_ctrl = q.control >> 4;
466 sub->cdsc_trk = bcd2uint(q.tno);
467 sub->cdsc_ind = bcd2uint(q.index);
469 xtrace(SUBCHNL, "trk %d, ind %d\n",
470 sub->cdsc_trk, sub->cdsc_ind);
471 /* Always return stuff in MSF, and let the Uniform cdrom driver
472 worry about what the user actually wants */
473 sub->cdsc_absaddr.msf.minute =
474 bcd2uint(q.dt.minute);
475 sub->cdsc_absaddr.msf.second =
476 bcd2uint(q.dt.second);
477 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
478 sub->cdsc_reladdr.msf.minute =
479 bcd2uint(q.tt.minute);
480 sub->cdsc_reladdr.msf.second =
481 bcd2uint(q.tt.second);
482 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
484 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
485 sub->cdsc_absaddr.msf.minute,
486 sub->cdsc_absaddr.msf.second,
487 sub->cdsc_absaddr.msf.frame,
488 sub->cdsc_reladdr.msf.minute,
489 sub->cdsc_reladdr.msf.second,
490 sub->cdsc_reladdr.msf.frame);
495 case CDROMREADTOCHDR:{
496 struct cdrom_tochdr *toc =
497 (struct cdrom_tochdr *) arg;
499 xtrace(IOCTL, "ioctl() READTOCHDR\n");
500 toc->cdth_trk0 = stuffp->di.n_first;
501 toc->cdth_trk1 = stuffp->di.n_last;
503 "ioctl() track0 = %d, track1 = %d\n",
504 stuffp->di.n_first, stuffp->di.n_last);
509 xtrace(IOCTL, "ioctl() PAUSE\n");
510 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
512 if (-1 == mcdx_stop(stuffp, 1))
514 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
516 mcdx_requestsubqcode(stuffp, &stuffp->start,
522 case CDROMMULTISESSION:{
523 struct cdrom_multisession *ms =
524 (struct cdrom_multisession *) arg;
525 xtrace(IOCTL, "ioctl() MULTISESSION\n");
526 /* Always return stuff in LBA, and let the Uniform cdrom driver
527 worry about what the user actually wants */
528 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
529 ms->xa_flag = !!stuffp->multi.multi;
531 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
532 ms->xa_flag, ms->addr.lba,
533 stuffp->multi.msf_last.minute,
534 stuffp->multi.msf_last.second,
535 stuffp->multi.msf_last.frame);
541 xtrace(IOCTL, "ioctl() EJECT\n");
542 if (stuffp->users > 1)
544 return (mcdx_tray_move(cdi, 1));
547 case CDROMCLOSETRAY:{
548 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
549 return (mcdx_tray_move(cdi, 0));
553 struct cdrom_volctrl *volctrl =
554 (struct cdrom_volctrl *) arg;
555 xtrace(IOCTL, "ioctl() VOLCTRL\n");
557 #if 0 /* not tested! */
558 /* adjust for the weirdness of workman (md) */
559 /* can't test it (hs) */
560 volctrl.channel2 = volctrl.channel1;
561 volctrl.channel1 = volctrl.channel3 = 0x00;
563 return mcdx_setattentuator(stuffp, volctrl, 2);
571 void do_mcdx_request(request_queue_t * q)
573 struct s_drive_stuff *stuffp;
578 req = elv_next_request(q);
582 stuffp = req->rq_disk->private_data;
584 if (!stuffp->present) {
585 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
586 xtrace(REQUEST, "end_request(0): bad device\n");
592 xwarn("do_request() attempt to read from audio cd\n");
593 xtrace(REQUEST, "end_request(0): read from audio\n");
598 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
599 req->sector, req->nr_sectors);
601 if (req->cmd != READ) {
602 xwarn("do_request(): non-read command to cd!!\n");
603 xtrace(REQUEST, "end_request(0): write\n");
609 while (req->nr_sectors) {
612 i = mcdx_transfer(stuffp,
622 req->nr_sectors -= i;
623 req->buffer += (i * 512);
628 xtrace(REQUEST, "end_request(1)\n");
635 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
637 struct s_drive_stuff *stuffp;
638 xtrace(OPENCLOSE, "open()\n");
639 stuffp = cdi->handle;
640 if (!stuffp->present)
643 /* Make the modules looking used ... (thanx bjorn).
644 * But we shouldn't forget to decrement the module counter
647 /* this is only done to test if the drive talks with us */
648 if (-1 == mcdx_getstatus(stuffp, 1))
653 xtrace(OPENCLOSE, "open() media changed\n");
654 stuffp->audiostatus = CDROM_AUDIO_INVALID;
656 xtrace(OPENCLOSE, "open() Request multisession info\n");
658 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
659 xinfo("No multidiskinfo\n");
662 if (!stuffp->multi.multi)
663 stuffp->multi.msf_last.second = 2;
665 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
667 stuffp->multi.msf_last.minute,
668 stuffp->multi.msf_last.second,
669 stuffp->multi.msf_last.frame);
672 } /* got multisession information */
673 /* request the disks table of contents (aka diskinfo) */
674 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
676 stuffp->lastsector = -1;
680 stuffp->lastsector = (CD_FRAMESIZE / 512)
681 * msf2log(&stuffp->di.msf_leadout) - 1;
684 "open() start %d (%02x:%02x.%02x) %d\n",
686 stuffp->di.msf_first.minute,
687 stuffp->di.msf_first.second,
688 stuffp->di.msf_first.frame,
689 msf2log(&stuffp->di.msf_first));
691 "open() last %d (%02x:%02x.%02x) %d\n",
693 stuffp->di.msf_leadout.minute,
694 stuffp->di.msf_leadout.second,
695 stuffp->di.msf_leadout.frame,
696 msf2log(&stuffp->di.msf_leadout));
700 xtrace(MALLOC, "open() free old toc @ %p\n",
707 xtrace(OPENCLOSE, "open() init irq generation\n");
708 if (-1 == mcdx_config(stuffp, 1))
711 /* Set the read speed */
712 xwarn("AAA %x AAA\n", stuffp->readcmd);
713 if (stuffp->readerrs)
714 stuffp->readcmd = READ1X;
717 stuffp->present | SINGLE ? READ1X : READ2X;
718 xwarn("XXX %x XXX\n", stuffp->readcmd);
721 stuffp->present | SINGLE ? READ1X : READ2X;
724 /* try to get the first sector, iff any ... */
725 if (stuffp->lastsector >= 0) {
733 for (tries = 6; tries; tries--) {
737 xtrace(OPENCLOSE, "open() try as %s\n",
738 stuffp->xa ? "XA" : "normal");
740 if (-1 == (ans = mcdx_setdatamode(stuffp,
751 if ((stuffp->audio = e_audio(ans)))
756 mcdx_transfer(stuffp, buf, 0, 1)));
760 stuffp->xa = !stuffp->xa;
763 /* xa disks will be read in raw mode, others not */
764 if (-1 == mcdx_setdrivemode(stuffp,
765 stuffp->xa ? RAW : COOKED,
769 xinfo("open() audio disk found\n");
770 } else if (stuffp->lastsector >= 0) {
771 xinfo("open() %s%s disk found\n",
772 stuffp->xa ? "XA / " : "",
774 multi ? "Multi Session" : "Single Session");
782 static void mcdx_close(struct cdrom_device_info *cdi)
784 struct s_drive_stuff *stuffp;
786 xtrace(OPENCLOSE, "close()\n");
788 stuffp = cdi->handle;
793 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
794 /* Return: 1 if media changed since last call to this function
797 struct s_drive_stuff *stuffp;
799 xinfo("mcdx_media_changed called for device %s\n", cdi->name);
801 stuffp = cdi->handle;
802 mcdx_getstatus(stuffp, 1);
804 if (stuffp->yyy == 0)
812 static int __init mcdx_setup(char *str)
815 (void) get_options(str, ARRAY_SIZE(pi), pi);
818 mcdx_drive_map[0][0] = pi[1];
820 mcdx_drive_map[0][1] = pi[2];
824 __setup("mcdx=", mcdx_setup);
828 /* DIRTY PART ******************************************************/
830 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
831 /* This routine is used for sleeping.
832 * A jifs value <0 means NO sleeping,
833 * =0 means minimal sleeping (let the kernel
834 * run for other processes)
835 * >0 means at least sleep for that amount.
836 * May be we could use a simple count loop w/ jumps to itself, but
837 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
842 xtrace(SLEEP, "*** delay: sleepq\n");
843 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
844 xtrace(SLEEP, "delay awoken\n");
845 if (signal_pending(current)) {
846 xtrace(SLEEP, "got signal\n");
850 static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
852 struct s_drive_stuff *stuffp;
855 stuffp = mcdx_irq_map[irq];
857 if (stuffp == NULL) {
858 xwarn("mcdx: no device for intr %d\n", irq);
862 if (!stuffp->busy && stuffp->pending)
866 /* get the interrupt status */
867 b = inb(stuffp->rreg_status);
868 stuffp->introk = ~b & MCDX_RBIT_DTEN;
870 /* NOTE: We only should get interrupts if the data we
871 * requested are ready to transfer.
872 * But the drive seems to generate ``asynchronous'' interrupts
873 * on several error conditions too. (Despite the err int enable
874 * setting during initialisation) */
876 /* if not ok, read the next byte as the drives status */
877 if (!stuffp->introk) {
878 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
879 if (~b & MCDX_RBIT_STEN) {
880 xinfo("intr() irq %d status 0x%02x\n",
881 irq, inb(stuffp->rreg_data));
883 xinfo("intr() irq %d ambiguous hw status\n", irq);
886 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
890 wake_up_interruptible(&stuffp->busyq);
895 static int mcdx_talk(struct s_drive_stuff *stuffp,
896 const unsigned char *cmd, size_t cmdlen,
897 void *buffer, size_t size, unsigned int timeout, int tries)
898 /* Send a command to the drive, wait for the result.
899 * returns -1 on timeout, drive status otherwise
900 * If buffer is not zero, the result (length size) is stored there.
901 * If buffer is zero the size should be the number of bytes to read
902 * from the drive. These bytes are discarded.
909 /* Somebody wants the data read? */
910 if ((discard = (buffer == NULL)))
913 while (stuffp->lock) {
914 xtrace(SLEEP, "*** talk: lockq\n");
915 interruptible_sleep_on(&stuffp->lockq);
916 xtrace(SLEEP, "talk: awoken\n");
921 /* An operation other then reading data destroys the
922 * data already requested and remembered in stuffp->request, ... */
925 #if MCDX_DEBUG & TALK
929 "talk() %d / %d tries, res.size %d, command 0x%02x",
930 tries, timeout, size, (unsigned char) cmd[0]);
931 for (i = 1; i < cmdlen; i++)
932 xtrace(TALK, " 0x%02x", cmd[i]);
937 /* give up if all tries are done (bad) or if the status
939 for (st = -1; st == -1 && tries; tries--) {
941 char *bp = (char *) buffer;
944 outsb(stuffp->wreg_data, cmd, cmdlen);
945 xtrace(TALK, "talk() command sent\n");
947 /* get the status byte */
948 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
949 xinfo("talk() %02x timed out (status), %d tr%s left\n",
950 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
958 xtrace(TALK, "talk() got status 0x%02x\n", st);
962 xwarn("command error cmd = %02x %s \n",
963 cmd[0], cmdlen > 1 ? "..." : "");
969 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
970 stuffp->audiostatus =
971 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
972 CDROM_AUDIO_NO_STATUS;
973 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
974 && e_audiobusy(st) == 0)
975 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
979 xinfo("talk() media changed\n");
980 stuffp->xxx = stuffp->yyy = 1;
983 /* now actually get the data */
985 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
986 xinfo("talk() %02x timed out (data), %d tr%s left\n",
988 tries == 2 ? "y" : "ies");
994 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
999 if (!tries && st == -1)
1000 xinfo("talk() giving up\n");
1004 wake_up_interruptible(&stuffp->lockq);
1006 xtrace(TALK, "talk() done with 0x%02x\n", st);
1010 /* MODULE STUFF ***********************************************************/
1012 int __mcdx_init(void)
1018 for (i = 0; i < MCDX_NDRIVES; i++) {
1019 if (mcdx_stuffp[i]) {
1020 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1032 void __exit mcdx_exit(void)
1036 xinfo("cleanup_module called\n");
1038 for (i = 0; i < MCDX_NDRIVES; i++) {
1039 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1042 del_gendisk(stuffp->disk);
1043 if (unregister_cdrom(&stuffp->info)) {
1044 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1047 put_disk(stuffp->disk);
1048 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1049 free_irq(stuffp->irq, NULL);
1051 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1055 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1057 mcdx_stuffp[i] = NULL;
1061 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1062 xwarn("cleanup() unregister_blkdev() failed\n");
1064 blk_cleanup_queue(mcdx_queue);
1067 xinfo("cleanup() succeeded\n");
1072 module_init(__mcdx_init);
1074 module_exit(mcdx_exit);
1077 /* Support functions ************************************************/
1079 int __init mcdx_init_drive(int drive)
1081 struct s_version version;
1082 struct gendisk *disk;
1083 struct s_drive_stuff *stuffp;
1084 int size = sizeof(*stuffp);
1087 xtrace(INIT, "init() try drive %d\n", drive);
1089 xtrace(INIT, "kmalloc space for stuffpt's\n");
1090 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1091 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1092 xwarn("init() malloc failed\n");
1096 disk = alloc_disk(1);
1098 xwarn("init() malloc failed\n");
1103 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1104 sizeof(*stuffp), stuffp);
1106 /* set default values */
1107 memset(stuffp, 0, sizeof(*stuffp));
1109 stuffp->present = 0; /* this should be 0 already */
1110 stuffp->toc = NULL; /* this should be NULL already */
1112 /* setup our irq and i/o addresses */
1113 stuffp->irq = irq(mcdx_drive_map[drive]);
1114 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1115 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1116 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1117 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1119 init_waitqueue_head(&stuffp->busyq);
1120 init_waitqueue_head(&stuffp->lockq);
1121 init_waitqueue_head(&stuffp->sleepq);
1123 /* check if i/o addresses are available */
1124 if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1125 xwarn("0x%03x,%d: Init failed. "
1126 "I/O ports (0x%03x..0x%03x) already in use.\n",
1127 stuffp->wreg_data, stuffp->irq,
1129 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1130 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1133 xtrace(INIT, "init() continue at next drive\n");
1134 return 0; /* next drive */
1137 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1139 xtrace(INIT, "init() hardware reset\n");
1140 mcdx_reset(stuffp, HARD, 1);
1142 xtrace(INIT, "init() get version\n");
1143 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1144 /* failed, next drive */
1145 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1146 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1147 MCDX, stuffp->wreg_data, stuffp->irq);
1148 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1151 xtrace(INIT, "init() continue at next drive\n");
1155 switch (version.code) {
1157 stuffp->readcmd = READ2X;
1158 stuffp->present = DOUBLE | DOOR | MULTI;
1161 stuffp->readcmd = READ1X;
1162 stuffp->present = SINGLE | DOOR | MULTI;
1165 stuffp->readcmd = READ1X;
1166 stuffp->present = SINGLE;
1169 stuffp->present = 0;
1173 stuffp->playcmd = READ1X;
1175 if (!stuffp->present) {
1176 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1177 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1178 MCDX, stuffp->wreg_data, stuffp->irq);
1181 return 0; /* next drive */
1184 xtrace(INIT, "init() register blkdev\n");
1185 if (register_blkdev(MAJOR_NR, "mcdx")) {
1186 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1192 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1194 unregister_blkdev(MAJOR_NR, "mcdx");
1195 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1201 xtrace(INIT, "init() subscribe irq and i/o\n");
1202 mcdx_irq_map[stuffp->irq] = stuffp;
1203 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1204 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1205 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1206 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1208 blk_cleanup_queue(mcdx_queue);
1214 xtrace(INIT, "init() get garbage\n");
1217 mcdx_delay(stuffp, HZ / 2);
1218 for (i = 100; i; i--)
1219 (void) inb(stuffp->rreg_status);
1224 /* irq 11 -> channel register */
1225 outb(0x50, stuffp->wreg_chn);
1228 xtrace(INIT, "init() set non dma but irq mode\n");
1229 mcdx_config(stuffp, 1);
1231 stuffp->info.ops = &mcdx_dops;
1232 stuffp->info.speed = 2;
1233 stuffp->info.capacity = 1;
1234 stuffp->info.handle = stuffp;
1235 sprintf(stuffp->info.name, "mcdx%d", drive);
1236 disk->major = MAJOR_NR;
1237 disk->first_minor = drive;
1238 strcpy(disk->disk_name, stuffp->info.name);
1239 disk->fops = &mcdx_bdops;
1240 disk->flags = GENHD_FL_CD;
1241 stuffp->disk = disk;
1243 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1244 " (Firmware version %c %x)\n",
1245 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1246 mcdx_stuffp[drive] = stuffp;
1247 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1248 if (register_cdrom(&stuffp->info) != 0) {
1249 printk("Cannot register Mitsumi CD-ROM!\n");
1250 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1251 free_irq(stuffp->irq, NULL);
1254 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1255 xwarn("cleanup() unregister_blkdev() failed\n");
1256 blk_cleanup_queue(mcdx_queue);
1259 disk->private_data = stuffp;
1260 disk->queue = mcdx_queue;
1266 int __init mcdx_init(void)
1270 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1272 xwarn("Version 2.14(hs) \n");
1275 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1277 /* zero the pointer array */
1278 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1279 mcdx_stuffp[drive] = NULL;
1281 /* do the initialisation */
1282 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1283 switch (mcdx_init_drive(drive)) {
1293 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1294 char *p, int sector, int nr_sectors)
1295 /* This seems to do the actually transfer. But it does more. It
1296 keeps track of errors occurred and will (if possible) fall back
1297 to single speed on error.
1298 Return: -1 on timeout or other error
1299 else status byte (as in stuff->st) */
1303 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1311 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1312 xwarn("XXX Already reading 1x -- no chance\n");
1316 xwarn("XXX Fallback to 1x\n");
1318 stuffp->readcmd = READ1X;
1319 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1325 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1326 char *p, int sector, int nr_sectors)
1327 /* This does actually the transfer from the drive.
1328 Return: -1 on timeout or other error
1329 else status byte (as in stuff->st) */
1335 if (stuffp->audio) {
1336 xwarn("Attempt to read from audio CD.\n");
1340 if (!stuffp->readcmd) {
1341 xinfo("Can't transfer from missing disk.\n");
1345 while (stuffp->lock) {
1346 interruptible_sleep_on(&stuffp->lockq);
1349 if (stuffp->valid && (sector >= stuffp->pending)
1350 && (sector < stuffp->low_border)) {
1352 /* All (or at least a part of the sectors requested) seems
1353 * to be already requested, so we don't need to bother the
1354 * drive with new requests ...
1355 * Wait for the drive become idle, but first
1356 * check for possible occurred errors --- the drive
1357 * seems to report them asynchronously */
1360 border = stuffp->high_border < (border =
1361 sector + nr_sectors)
1362 ? stuffp->high_border : border;
1364 stuffp->lock = current->pid;
1368 while (stuffp->busy) {
1371 interruptible_sleep_on_timeout
1372 (&stuffp->busyq, 5 * HZ);
1374 if (!stuffp->introk) {
1376 "error via interrupt\n");
1377 } else if (!timeout) {
1378 xtrace(XFER, "timeout\n");
1379 } else if (signal_pending(current)) {
1380 xtrace(XFER, "signal\n");
1388 wake_up_interruptible(&stuffp->lockq);
1389 xtrace(XFER, "transfer() done (-1)\n");
1393 /* check if we need to set the busy flag (as we
1394 * expect an interrupt */
1395 stuffp->busy = (3 == (stuffp->pending & 3));
1397 /* Test if it's the first sector of a block,
1398 * there we have to skip some bytes as we read raw data */
1399 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1401 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1403 insb(stuffp->rreg_data, p, HEAD);
1406 /* now actually read the data */
1407 insb(stuffp->rreg_data, p, 512);
1409 /* test if it's the last sector of a block,
1410 * if so, we have to handle XA special */
1411 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1412 char dummy[CD_XA_TAIL];
1413 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1416 if (stuffp->pending == sector) {
1421 } while (++(stuffp->pending) < border);
1424 wake_up_interruptible(&stuffp->lockq);
1428 /* The requested sector(s) is/are out of the
1429 * already requested range, so we have to bother the drive
1430 * with a new request. */
1432 static unsigned char cmd[] = {
1438 cmd[0] = stuffp->readcmd;
1440 /* The numbers held in ->pending, ..., should be valid */
1442 stuffp->pending = sector & ~3;
1444 /* do some sanity checks */
1445 if (stuffp->pending > stuffp->lastsector) {
1447 ("transfer() sector %d from nirvana requested.\n",
1449 stuffp->status = MCDX_ST_EOM;
1451 xtrace(XFER, "transfer() done (-1)\n");
1455 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1456 > stuffp->lastsector + 1) {
1457 xtrace(XFER, "cut low_border\n");
1458 stuffp->low_border = stuffp->lastsector + 1;
1460 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1461 > stuffp->lastsector + 1) {
1462 xtrace(XFER, "cut high_border\n");
1463 stuffp->high_border = stuffp->lastsector + 1;
1466 { /* Convert the sector to be requested to MSF format */
1467 struct cdrom_msf0 pending;
1468 log2msf(stuffp->pending / 4, &pending);
1469 cmd[1] = pending.minute;
1470 cmd[2] = pending.second;
1471 cmd[3] = pending.frame;
1476 char) ((stuffp->high_border - stuffp->pending) / 4);
1477 xtrace(XFER, "[%2d]\n", cmd[6]);
1480 /* Now really issue the request command */
1481 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1485 if (stuffp->int_err) {
1487 stuffp->int_err = 0;
1492 stuffp->low_border = (stuffp->low_border +=
1494 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1500 /* Access to elements of the mcdx_drive_map members */
1502 static unsigned port(int *ip)
1506 static int irq(int *ip)
1511 /* Misc number converters */
1513 static unsigned int bcd2uint(unsigned char c)
1515 return (c >> 4) * 10 + (c & 0x0f);
1518 static unsigned int uint2bcd(unsigned int ival)
1520 return ((ival / 10) << 4) | (ival % 10);
1523 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1526 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1527 pmsf->second = uint2bcd(l / 75);
1528 pmsf->frame = uint2bcd(l % 75);
1531 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1533 return bcd2uint(pmsf->frame)
1534 + bcd2uint(pmsf->second) * 75
1535 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1538 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1539 /* Read the toc entries from the CD,
1540 * Return: -1 on failure, else 0 */
1544 xtrace(READTOC, "ioctl() toc already read\n");
1548 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1549 stuffp->di.n_last - stuffp->di.n_first + 1);
1551 if (-1 == mcdx_hold(stuffp, 1))
1554 xtrace(READTOC, "ioctl() tocmode\n");
1555 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1558 /* all seems to be ok so far ... malloc */
1562 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1563 stuffp->di.n_first + 2);
1565 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1566 stuffp->toc = kmalloc(size, GFP_KERNEL);
1568 xwarn("Cannot malloc %d bytes for toc\n", size);
1569 mcdx_setdrivemode(stuffp, DATA, 1);
1574 /* now read actually the index */
1580 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1582 stuffp->toc[trk].index = 0;
1584 for (retries = 300; retries; retries--) { /* why 300? */
1585 struct s_subqcode q;
1588 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1589 mcdx_setdrivemode(stuffp, DATA, 1);
1593 idx = bcd2uint(q.index);
1596 && (idx <= stuffp->di.n_last)
1598 && (stuffp->toc[idx - stuffp->di.n_first].
1600 stuffp->toc[idx - stuffp->di.n_first] = q;
1602 "ioctl() toc idx %d (trk %d)\n",
1610 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1611 sizeof(stuffp->toc[0]));
1612 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1613 1].dt = stuffp->di.msf_leadout;
1616 /* unset toc mode */
1617 xtrace(READTOC, "ioctl() undo toc mode\n");
1618 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1621 #if MCDX_DEBUG && READTOC
1625 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1627 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1628 " %02x:%02x.%02x %02x:%02x.%02x\n",
1629 trk + stuffp->di.n_first,
1630 stuffp->toc[trk].control,
1631 stuffp->toc[trk].tno,
1632 stuffp->toc[trk].index,
1633 stuffp->toc[trk].tt.minute,
1634 stuffp->toc[trk].tt.second,
1635 stuffp->toc[trk].tt.frame,
1636 stuffp->toc[trk].dt.minute,
1637 stuffp->toc[trk].dt.second,
1638 stuffp->toc[trk].dt.frame);
1646 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1648 unsigned char cmd[7] = {
1652 if (!stuffp->readcmd) {
1653 xinfo("Can't play from missing disk.\n");
1657 cmd[0] = stuffp->playcmd;
1659 cmd[1] = msf->cdmsf_min0;
1660 cmd[2] = msf->cdmsf_sec0;
1661 cmd[3] = msf->cdmsf_frame0;
1662 cmd[4] = msf->cdmsf_min1;
1663 cmd[5] = msf->cdmsf_sec1;
1664 cmd[6] = msf->cdmsf_frame1;
1666 xtrace(PLAYMSF, "ioctl(): play %x "
1667 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1668 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1670 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1672 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1673 xwarn("playmsf() timeout\n");
1677 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1682 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1684 struct s_subqcode *p;
1685 struct cdrom_msf msf;
1687 if (-1 == mcdx_readtoc(stuffp))
1691 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1695 msf.cdmsf_min0 = p->dt.minute;
1696 msf.cdmsf_sec0 = p->dt.second;
1697 msf.cdmsf_frame0 = p->dt.frame;
1700 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1705 msf.cdmsf_min1 = p->dt.minute;
1706 msf.cdmsf_sec1 = p->dt.second;
1707 msf.cdmsf_frame1 = p->dt.frame;
1709 return mcdx_playmsf(stuffp, &msf);
1713 /* Drive functions ************************************************/
1715 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1717 struct s_drive_stuff *stuffp = cdi->handle;
1719 if (!stuffp->present)
1721 if (!(stuffp->present & DOOR))
1724 if (position) /* 1: eject */
1725 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1727 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1731 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1733 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1736 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1738 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1741 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1742 struct s_subqcode *sub, int tries)
1747 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1750 sub->control = buf[1];
1752 sub->index = buf[3];
1753 sub->tt.minute = buf[4];
1754 sub->tt.second = buf[5];
1755 sub->tt.frame = buf[6];
1756 sub->dt.minute = buf[8];
1757 sub->dt.second = buf[9];
1758 sub->dt.frame = buf[10];
1763 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1764 struct s_multi *multi, int tries)
1769 if (stuffp->present & MULTI) {
1771 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1773 multi->multi = buf[1];
1774 multi->msf_last.minute = buf[2];
1775 multi->msf_last.second = buf[3];
1776 multi->msf_last.frame = buf[4];
1784 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1790 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1795 info->n_first = bcd2uint(buf[1]);
1796 info->n_last = bcd2uint(buf[2]);
1797 info->msf_leadout.minute = buf[3];
1798 info->msf_leadout.second = buf[4];
1799 info->msf_leadout.frame = buf[5];
1800 info->msf_first.minute = buf[6];
1801 info->msf_first.second = buf[7];
1802 info->msf_first.frame = buf[8];
1807 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1813 xtrace(HW, "setdrivemode() %d\n", mode);
1815 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1835 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1838 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1841 unsigned char cmd[2] = { 0xa0 };
1842 xtrace(HW, "setdatamode() %d\n", mode);
1856 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1859 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1863 xtrace(HW, "config()\n");
1867 cmd[1] = 0x10; /* irq enable */
1868 cmd[2] = 0x05; /* pre, err irq enable */
1870 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1873 cmd[1] = 0x02; /* dma select */
1874 cmd[2] = 0x00; /* no dma */
1876 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1879 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1885 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1886 1, buf, sizeof(buf), 2 * HZ, tries)))
1895 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1898 outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */
1899 outb(0, stuffp->wreg_reset); /* hw reset */
1902 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1905 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1907 struct s_drive_stuff *stuffp = cdi->handle;
1908 char cmd[2] = { 0xfe };
1910 if (!(stuffp->present & DOOR))
1912 if (stuffp->present & DOOR) {
1913 cmd[1] = lock ? 0x01 : 0x00;
1914 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1919 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1921 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1925 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1927 unsigned long timeout = to + jiffies;
1933 while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1934 if (time_after(jiffies, timeout))
1936 mcdx_delay(stuffp, delay);
1939 *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1944 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1945 struct cdrom_volctrl *vol, int tries)
1949 cmd[1] = vol->channel0;
1951 cmd[3] = vol->channel1;
1954 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1957 MODULE_LICENSE("GPL");
1958 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);