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(file, &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 spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED;
311 static struct request_queue *mcdx_queue;
312 MODULE_PARM(mcdx, "1-4i");
314 static struct cdrom_device_ops mcdx_dops = {
316 .release = mcdx_close,
317 .media_changed = mcdx_media_changed,
318 .tray_move = mcdx_tray_move,
319 .lock_door = mcdx_lockdoor,
320 .audio_ioctl = mcdx_audio_ioctl,
321 .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
322 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
325 /* KERNEL INTERFACE FUNCTIONS **************************************/
328 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
329 unsigned int cmd, void *arg)
331 struct s_drive_stuff *stuffp = cdi->handle;
333 if (!stuffp->present)
337 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
338 stuffp->lastsector = -1;
340 stuffp->lastsector = (CD_FRAMESIZE / 512)
341 * msf2log(&stuffp->di.msf_leadout) - 1;
347 if (-1 == mcdx_readtoc(stuffp))
356 xtrace(IOCTL, "ioctl() START\n");
357 /* Spin up the drive. Don't think we can do this.
358 * For now, ignore it.
364 xtrace(IOCTL, "ioctl() STOP\n");
365 stuffp->audiostatus = CDROM_AUDIO_INVALID;
366 if (-1 == mcdx_stop(stuffp, 1))
371 case CDROMPLAYTRKIND:{
372 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
374 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
375 if ((ti->cdti_trk0 < stuffp->di.n_first)
376 || (ti->cdti_trk0 > stuffp->di.n_last)
377 || (ti->cdti_trk1 < stuffp->di.n_first))
379 if (ti->cdti_trk1 > stuffp->di.n_last)
380 ti->cdti_trk1 = stuffp->di.n_last;
381 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
382 ti->cdti_trk0, ti->cdti_trk1);
383 return mcdx_playtrk(stuffp, ti);
387 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
389 xtrace(IOCTL, "ioctl() PLAYMSF\n");
391 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
392 && (-1 == mcdx_hold(stuffp, 1)))
395 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
396 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
397 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
399 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
400 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
401 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
403 stuffp->stop.dt.minute = msf->cdmsf_min1;
404 stuffp->stop.dt.second = msf->cdmsf_sec1;
405 stuffp->stop.dt.frame = msf->cdmsf_frame1;
407 return mcdx_playmsf(stuffp, msf);
411 xtrace(IOCTL, "ioctl() RESUME\n");
412 return mcdx_playtrk(stuffp, NULL);
415 case CDROMREADTOCENTRY:{
416 struct cdrom_tocentry *entry =
417 (struct cdrom_tocentry *) arg;
418 struct s_subqcode *tp = NULL;
419 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
421 if (-1 == mcdx_readtoc(stuffp))
423 if (entry->cdte_track == CDROM_LEADOUT)
424 tp = &stuffp->toc[stuffp->di.n_last -
425 stuffp->di.n_first + 1];
426 else if (entry->cdte_track > stuffp->di.n_last
427 || entry->cdte_track < stuffp->di.n_first)
430 tp = &stuffp->toc[entry->cdte_track -
435 entry->cdte_adr = tp->control;
436 entry->cdte_ctrl = tp->control >> 4;
437 /* Always return stuff in MSF, and let the Uniform cdrom driver
438 worry about what the user actually wants */
439 entry->cdte_addr.msf.minute =
440 bcd2uint(tp->dt.minute);
441 entry->cdte_addr.msf.second =
442 bcd2uint(tp->dt.second);
443 entry->cdte_addr.msf.frame =
444 bcd2uint(tp->dt.frame);
449 struct cdrom_subchnl *sub =
450 (struct cdrom_subchnl *) arg;
453 xtrace(IOCTL, "ioctl() SUBCHNL\n");
455 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
458 xtrace(SUBCHNL, "audiostatus: %x\n",
459 stuffp->audiostatus);
460 sub->cdsc_audiostatus = stuffp->audiostatus;
461 sub->cdsc_adr = q.control;
462 sub->cdsc_ctrl = q.control >> 4;
463 sub->cdsc_trk = bcd2uint(q.tno);
464 sub->cdsc_ind = bcd2uint(q.index);
466 xtrace(SUBCHNL, "trk %d, ind %d\n",
467 sub->cdsc_trk, sub->cdsc_ind);
468 /* Always return stuff in MSF, and let the Uniform cdrom driver
469 worry about what the user actually wants */
470 sub->cdsc_absaddr.msf.minute =
471 bcd2uint(q.dt.minute);
472 sub->cdsc_absaddr.msf.second =
473 bcd2uint(q.dt.second);
474 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
475 sub->cdsc_reladdr.msf.minute =
476 bcd2uint(q.tt.minute);
477 sub->cdsc_reladdr.msf.second =
478 bcd2uint(q.tt.second);
479 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
481 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
482 sub->cdsc_absaddr.msf.minute,
483 sub->cdsc_absaddr.msf.second,
484 sub->cdsc_absaddr.msf.frame,
485 sub->cdsc_reladdr.msf.minute,
486 sub->cdsc_reladdr.msf.second,
487 sub->cdsc_reladdr.msf.frame);
492 case CDROMREADTOCHDR:{
493 struct cdrom_tochdr *toc =
494 (struct cdrom_tochdr *) arg;
496 xtrace(IOCTL, "ioctl() READTOCHDR\n");
497 toc->cdth_trk0 = stuffp->di.n_first;
498 toc->cdth_trk1 = stuffp->di.n_last;
500 "ioctl() track0 = %d, track1 = %d\n",
501 stuffp->di.n_first, stuffp->di.n_last);
506 xtrace(IOCTL, "ioctl() PAUSE\n");
507 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
509 if (-1 == mcdx_stop(stuffp, 1))
511 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
513 mcdx_requestsubqcode(stuffp, &stuffp->start,
519 case CDROMMULTISESSION:{
520 struct cdrom_multisession *ms =
521 (struct cdrom_multisession *) arg;
522 xtrace(IOCTL, "ioctl() MULTISESSION\n");
523 /* Always return stuff in LBA, and let the Uniform cdrom driver
524 worry about what the user actually wants */
525 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
526 ms->xa_flag = !!stuffp->multi.multi;
528 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
529 ms->xa_flag, ms->addr.lba,
530 stuffp->multi.msf_last.minute,
531 stuffp->multi.msf_last.second,
532 stuffp->multi.msf_last.frame);
538 xtrace(IOCTL, "ioctl() EJECT\n");
539 if (stuffp->users > 1)
541 return (mcdx_tray_move(cdi, 1));
544 case CDROMCLOSETRAY:{
545 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
546 return (mcdx_tray_move(cdi, 0));
550 struct cdrom_volctrl *volctrl =
551 (struct cdrom_volctrl *) arg;
552 xtrace(IOCTL, "ioctl() VOLCTRL\n");
554 #if 0 /* not tested! */
555 /* adjust for the weirdness of workman (md) */
556 /* can't test it (hs) */
557 volctrl.channel2 = volctrl.channel1;
558 volctrl.channel1 = volctrl.channel3 = 0x00;
560 return mcdx_setattentuator(stuffp, volctrl, 2);
568 void do_mcdx_request(request_queue_t * q)
570 struct s_drive_stuff *stuffp;
575 req = elv_next_request(q);
579 stuffp = req->rq_disk->private_data;
581 if (!stuffp->present) {
582 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
583 xtrace(REQUEST, "end_request(0): bad device\n");
589 xwarn("do_request() attempt to read from audio cd\n");
590 xtrace(REQUEST, "end_request(0): read from audio\n");
595 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
596 req->sector, req->nr_sectors);
598 if (req->cmd != READ) {
599 xwarn("do_request(): non-read command to cd!!\n");
600 xtrace(REQUEST, "end_request(0): write\n");
606 while (req->nr_sectors) {
609 i = mcdx_transfer(stuffp,
619 req->nr_sectors -= i;
620 req->buffer += (i * 512);
625 xtrace(REQUEST, "end_request(1)\n");
632 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
634 struct s_drive_stuff *stuffp;
635 xtrace(OPENCLOSE, "open()\n");
636 stuffp = cdi->handle;
637 if (!stuffp->present)
640 /* Make the modules looking used ... (thanx bjorn).
641 * But we shouldn't forget to decrement the module counter
644 /* this is only done to test if the drive talks with us */
645 if (-1 == mcdx_getstatus(stuffp, 1))
650 xtrace(OPENCLOSE, "open() media changed\n");
651 stuffp->audiostatus = CDROM_AUDIO_INVALID;
653 xtrace(OPENCLOSE, "open() Request multisession info\n");
655 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
656 xinfo("No multidiskinfo\n");
659 if (!stuffp->multi.multi)
660 stuffp->multi.msf_last.second = 2;
662 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
664 stuffp->multi.msf_last.minute,
665 stuffp->multi.msf_last.second,
666 stuffp->multi.msf_last.frame);
669 } /* got multisession information */
670 /* request the disks table of contents (aka diskinfo) */
671 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
673 stuffp->lastsector = -1;
677 stuffp->lastsector = (CD_FRAMESIZE / 512)
678 * msf2log(&stuffp->di.msf_leadout) - 1;
681 "open() start %d (%02x:%02x.%02x) %d\n",
683 stuffp->di.msf_first.minute,
684 stuffp->di.msf_first.second,
685 stuffp->di.msf_first.frame,
686 msf2log(&stuffp->di.msf_first));
688 "open() last %d (%02x:%02x.%02x) %d\n",
690 stuffp->di.msf_leadout.minute,
691 stuffp->di.msf_leadout.second,
692 stuffp->di.msf_leadout.frame,
693 msf2log(&stuffp->di.msf_leadout));
697 xtrace(MALLOC, "open() free old toc @ %p\n",
704 xtrace(OPENCLOSE, "open() init irq generation\n");
705 if (-1 == mcdx_config(stuffp, 1))
708 /* Set the read speed */
709 xwarn("AAA %x AAA\n", stuffp->readcmd);
710 if (stuffp->readerrs)
711 stuffp->readcmd = READ1X;
714 stuffp->present | SINGLE ? READ1X : READ2X;
715 xwarn("XXX %x XXX\n", stuffp->readcmd);
718 stuffp->present | SINGLE ? READ1X : READ2X;
721 /* try to get the first sector, iff any ... */
722 if (stuffp->lastsector >= 0) {
730 for (tries = 6; tries; tries--) {
734 xtrace(OPENCLOSE, "open() try as %s\n",
735 stuffp->xa ? "XA" : "normal");
737 if (-1 == (ans = mcdx_setdatamode(stuffp,
748 if ((stuffp->audio = e_audio(ans)))
753 mcdx_transfer(stuffp, buf, 0, 1)));
757 stuffp->xa = !stuffp->xa;
760 /* xa disks will be read in raw mode, others not */
761 if (-1 == mcdx_setdrivemode(stuffp,
762 stuffp->xa ? RAW : COOKED,
766 xinfo("open() audio disk found\n");
767 } else if (stuffp->lastsector >= 0) {
768 xinfo("open() %s%s disk found\n",
769 stuffp->xa ? "XA / " : "",
771 multi ? "Multi Session" : "Single Session");
779 static void mcdx_close(struct cdrom_device_info *cdi)
781 struct s_drive_stuff *stuffp;
783 xtrace(OPENCLOSE, "close()\n");
785 stuffp = cdi->handle;
790 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
791 /* Return: 1 if media changed since last call to this function
794 struct s_drive_stuff *stuffp;
796 xinfo("mcdx_media_changed called for device %s\n", cdi->name);
798 stuffp = cdi->handle;
799 mcdx_getstatus(stuffp, 1);
801 if (stuffp->yyy == 0)
809 static int __init mcdx_setup(char *str)
812 (void) get_options(str, ARRAY_SIZE(pi), pi);
815 mcdx_drive_map[0][0] = pi[1];
817 mcdx_drive_map[0][1] = pi[2];
821 __setup("mcdx=", mcdx_setup);
825 /* DIRTY PART ******************************************************/
827 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
828 /* This routine is used for sleeping.
829 * A jifs value <0 means NO sleeping,
830 * =0 means minimal sleeping (let the kernel
831 * run for other processes)
832 * >0 means at least sleep for that amount.
833 * May be we could use a simple count loop w/ jumps to itself, but
834 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
839 xtrace(SLEEP, "*** delay: sleepq\n");
840 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
841 xtrace(SLEEP, "delay awoken\n");
842 if (signal_pending(current)) {
843 xtrace(SLEEP, "got signal\n");
847 static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
849 struct s_drive_stuff *stuffp = dev_id;
852 if (stuffp == NULL) {
853 xwarn("mcdx: no device for intr %d\n", irq);
857 if (!stuffp->busy && stuffp->pending)
861 /* get the interrupt status */
862 b = inb(stuffp->rreg_status);
863 stuffp->introk = ~b & MCDX_RBIT_DTEN;
865 /* NOTE: We only should get interrupts if the data we
866 * requested are ready to transfer.
867 * But the drive seems to generate ``asynchronous'' interrupts
868 * on several error conditions too. (Despite the err int enable
869 * setting during initialisation) */
871 /* if not ok, read the next byte as the drives status */
872 if (!stuffp->introk) {
873 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
874 if (~b & MCDX_RBIT_STEN) {
875 xinfo("intr() irq %d status 0x%02x\n",
876 irq, inb(stuffp->rreg_data));
878 xinfo("intr() irq %d ambiguous hw status\n", irq);
881 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
885 wake_up_interruptible(&stuffp->busyq);
890 static int mcdx_talk(struct s_drive_stuff *stuffp,
891 const unsigned char *cmd, size_t cmdlen,
892 void *buffer, size_t size, unsigned int timeout, int tries)
893 /* Send a command to the drive, wait for the result.
894 * returns -1 on timeout, drive status otherwise
895 * If buffer is not zero, the result (length size) is stored there.
896 * If buffer is zero the size should be the number of bytes to read
897 * from the drive. These bytes are discarded.
904 /* Somebody wants the data read? */
905 if ((discard = (buffer == NULL)))
908 while (stuffp->lock) {
909 xtrace(SLEEP, "*** talk: lockq\n");
910 interruptible_sleep_on(&stuffp->lockq);
911 xtrace(SLEEP, "talk: awoken\n");
916 /* An operation other then reading data destroys the
917 * data already requested and remembered in stuffp->request, ... */
920 #if MCDX_DEBUG & TALK
924 "talk() %d / %d tries, res.size %d, command 0x%02x",
925 tries, timeout, size, (unsigned char) cmd[0]);
926 for (i = 1; i < cmdlen; i++)
927 xtrace(TALK, " 0x%02x", cmd[i]);
932 /* give up if all tries are done (bad) or if the status
934 for (st = -1; st == -1 && tries; tries--) {
936 char *bp = (char *) buffer;
939 outsb(stuffp->wreg_data, cmd, cmdlen);
940 xtrace(TALK, "talk() command sent\n");
942 /* get the status byte */
943 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
944 xinfo("talk() %02x timed out (status), %d tr%s left\n",
945 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
953 xtrace(TALK, "talk() got status 0x%02x\n", st);
957 xwarn("command error cmd = %02x %s \n",
958 cmd[0], cmdlen > 1 ? "..." : "");
964 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
965 stuffp->audiostatus =
966 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
967 CDROM_AUDIO_NO_STATUS;
968 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
969 && e_audiobusy(st) == 0)
970 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
974 xinfo("talk() media changed\n");
975 stuffp->xxx = stuffp->yyy = 1;
978 /* now actually get the data */
980 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
981 xinfo("talk() %02x timed out (data), %d tr%s left\n",
983 tries == 2 ? "y" : "ies");
989 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
994 if (!tries && st == -1)
995 xinfo("talk() giving up\n");
999 wake_up_interruptible(&stuffp->lockq);
1001 xtrace(TALK, "talk() done with 0x%02x\n", st);
1005 /* MODULE STUFF ***********************************************************/
1007 int __mcdx_init(void)
1013 for (i = 0; i < MCDX_NDRIVES; i++) {
1014 if (mcdx_stuffp[i]) {
1015 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1027 void __exit mcdx_exit(void)
1031 xinfo("cleanup_module called\n");
1033 for (i = 0; i < MCDX_NDRIVES; i++) {
1034 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1037 del_gendisk(stuffp->disk);
1038 if (unregister_cdrom(&stuffp->info)) {
1039 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1042 put_disk(stuffp->disk);
1043 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1044 free_irq(stuffp->irq, NULL);
1046 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1050 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1052 mcdx_stuffp[i] = NULL;
1056 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1057 xwarn("cleanup() unregister_blkdev() failed\n");
1059 blk_cleanup_queue(mcdx_queue);
1062 xinfo("cleanup() succeeded\n");
1067 module_init(__mcdx_init);
1069 module_exit(mcdx_exit);
1072 /* Support functions ************************************************/
1074 int __init mcdx_init_drive(int drive)
1076 struct s_version version;
1077 struct gendisk *disk;
1078 struct s_drive_stuff *stuffp;
1079 int size = sizeof(*stuffp);
1082 xtrace(INIT, "init() try drive %d\n", drive);
1084 xtrace(INIT, "kmalloc space for stuffpt's\n");
1085 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1086 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1087 xwarn("init() malloc failed\n");
1091 disk = alloc_disk(1);
1093 xwarn("init() malloc failed\n");
1098 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1099 sizeof(*stuffp), stuffp);
1101 /* set default values */
1102 memset(stuffp, 0, sizeof(*stuffp));
1104 stuffp->present = 0; /* this should be 0 already */
1105 stuffp->toc = NULL; /* this should be NULL already */
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;
1114 init_waitqueue_head(&stuffp->busyq);
1115 init_waitqueue_head(&stuffp->lockq);
1116 init_waitqueue_head(&stuffp->sleepq);
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,
1124 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1125 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1128 xtrace(INIT, "init() continue at next drive\n");
1129 return 0; /* next drive */
1132 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1134 xtrace(INIT, "init() hardware reset\n");
1135 mcdx_reset(stuffp, HARD, 1);
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);
1146 xtrace(INIT, "init() continue at next drive\n");
1150 switch (version.code) {
1152 stuffp->readcmd = READ2X;
1153 stuffp->present = DOUBLE | DOOR | MULTI;
1156 stuffp->readcmd = READ1X;
1157 stuffp->present = SINGLE | DOOR | MULTI;
1160 stuffp->readcmd = READ1X;
1161 stuffp->present = SINGLE;
1164 stuffp->present = 0;
1168 stuffp->playcmd = READ1X;
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);
1176 return 0; /* next drive */
1179 xtrace(INIT, "init() register blkdev\n");
1180 if (register_blkdev(MAJOR_NR, "mcdx")) {
1181 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1187 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1189 unregister_blkdev(MAJOR_NR, "mcdx");
1190 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
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);
1202 blk_cleanup_queue(mcdx_queue);
1208 xtrace(INIT, "init() get garbage\n");
1211 mcdx_delay(stuffp, HZ / 2);
1212 for (i = 100; i; i--)
1213 (void) inb(stuffp->rreg_status);
1218 /* irq 11 -> channel register */
1219 outb(0x50, stuffp->wreg_chn);
1222 xtrace(INIT, "init() set non dma but irq mode\n");
1223 mcdx_config(stuffp, 1);
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;
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);
1248 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1249 xwarn("cleanup() unregister_blkdev() failed\n");
1250 blk_cleanup_queue(mcdx_queue);
1253 disk->private_data = stuffp;
1254 disk->queue = mcdx_queue;
1260 int __init mcdx_init(void)
1264 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1266 xwarn("Version 2.14(hs) \n");
1269 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1271 /* zero the pointer array */
1272 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1273 mcdx_stuffp[drive] = NULL;
1275 /* do the initialisation */
1276 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1277 switch (mcdx_init_drive(drive)) {
1287 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1288 char *p, int sector, int nr_sectors)
1289 /* This seems to do the actually transfer. But it does more. It
1290 keeps track of errors occurred and will (if possible) fall back
1291 to single speed on error.
1292 Return: -1 on timeout or other error
1293 else status byte (as in stuff->st) */
1297 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1305 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1306 xwarn("XXX Already reading 1x -- no chance\n");
1310 xwarn("XXX Fallback to 1x\n");
1312 stuffp->readcmd = READ1X;
1313 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1319 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1320 char *p, int sector, int nr_sectors)
1321 /* This does actually the transfer from the drive.
1322 Return: -1 on timeout or other error
1323 else status byte (as in stuff->st) */
1329 if (stuffp->audio) {
1330 xwarn("Attempt to read from audio CD.\n");
1334 if (!stuffp->readcmd) {
1335 xinfo("Can't transfer from missing disk.\n");
1339 while (stuffp->lock) {
1340 interruptible_sleep_on(&stuffp->lockq);
1343 if (stuffp->valid && (sector >= stuffp->pending)
1344 && (sector < stuffp->low_border)) {
1346 /* All (or at least a part of the sectors requested) seems
1347 * to be already requested, so we don't need to bother the
1348 * drive with new requests ...
1349 * Wait for the drive become idle, but first
1350 * check for possible occurred errors --- the drive
1351 * seems to report them asynchronously */
1354 border = stuffp->high_border < (border =
1355 sector + nr_sectors)
1356 ? stuffp->high_border : border;
1358 stuffp->lock = current->pid;
1362 while (stuffp->busy) {
1365 interruptible_sleep_on_timeout
1366 (&stuffp->busyq, 5 * HZ);
1368 if (!stuffp->introk) {
1370 "error via interrupt\n");
1371 } else if (!timeout) {
1372 xtrace(XFER, "timeout\n");
1373 } else if (signal_pending(current)) {
1374 xtrace(XFER, "signal\n");
1382 wake_up_interruptible(&stuffp->lockq);
1383 xtrace(XFER, "transfer() done (-1)\n");
1387 /* check if we need to set the busy flag (as we
1388 * expect an interrupt */
1389 stuffp->busy = (3 == (stuffp->pending & 3));
1391 /* Test if it's the first sector of a block,
1392 * there we have to skip some bytes as we read raw data */
1393 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1395 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1397 insb(stuffp->rreg_data, p, HEAD);
1400 /* now actually read the data */
1401 insb(stuffp->rreg_data, p, 512);
1403 /* test if it's the last sector of a block,
1404 * if so, we have to handle XA special */
1405 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1406 char dummy[CD_XA_TAIL];
1407 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1410 if (stuffp->pending == sector) {
1415 } while (++(stuffp->pending) < border);
1418 wake_up_interruptible(&stuffp->lockq);
1422 /* The requested sector(s) is/are out of the
1423 * already requested range, so we have to bother the drive
1424 * with a new request. */
1426 static unsigned char cmd[] = {
1432 cmd[0] = stuffp->readcmd;
1434 /* The numbers held in ->pending, ..., should be valid */
1436 stuffp->pending = sector & ~3;
1438 /* do some sanity checks */
1439 if (stuffp->pending > stuffp->lastsector) {
1441 ("transfer() sector %d from nirvana requested.\n",
1443 stuffp->status = MCDX_ST_EOM;
1445 xtrace(XFER, "transfer() done (-1)\n");
1449 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1450 > stuffp->lastsector + 1) {
1451 xtrace(XFER, "cut low_border\n");
1452 stuffp->low_border = stuffp->lastsector + 1;
1454 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1455 > stuffp->lastsector + 1) {
1456 xtrace(XFER, "cut high_border\n");
1457 stuffp->high_border = stuffp->lastsector + 1;
1460 { /* Convert the sector to be requested to MSF format */
1461 struct cdrom_msf0 pending;
1462 log2msf(stuffp->pending / 4, &pending);
1463 cmd[1] = pending.minute;
1464 cmd[2] = pending.second;
1465 cmd[3] = pending.frame;
1470 char) ((stuffp->high_border - stuffp->pending) / 4);
1471 xtrace(XFER, "[%2d]\n", cmd[6]);
1474 /* Now really issue the request command */
1475 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1479 if (stuffp->int_err) {
1481 stuffp->int_err = 0;
1486 stuffp->low_border = (stuffp->low_border +=
1488 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1494 /* Access to elements of the mcdx_drive_map members */
1496 static unsigned port(int *ip)
1500 static int irq(int *ip)
1505 /* Misc number converters */
1507 static unsigned int bcd2uint(unsigned char c)
1509 return (c >> 4) * 10 + (c & 0x0f);
1512 static unsigned int uint2bcd(unsigned int ival)
1514 return ((ival / 10) << 4) | (ival % 10);
1517 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1520 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1521 pmsf->second = uint2bcd(l / 75);
1522 pmsf->frame = uint2bcd(l % 75);
1525 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1527 return bcd2uint(pmsf->frame)
1528 + bcd2uint(pmsf->second) * 75
1529 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1532 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1533 /* Read the toc entries from the CD,
1534 * Return: -1 on failure, else 0 */
1538 xtrace(READTOC, "ioctl() toc already read\n");
1542 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1543 stuffp->di.n_last - stuffp->di.n_first + 1);
1545 if (-1 == mcdx_hold(stuffp, 1))
1548 xtrace(READTOC, "ioctl() tocmode\n");
1549 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1552 /* all seems to be ok so far ... malloc */
1556 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1557 stuffp->di.n_first + 2);
1559 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1560 stuffp->toc = kmalloc(size, GFP_KERNEL);
1562 xwarn("Cannot malloc %d bytes for toc\n", size);
1563 mcdx_setdrivemode(stuffp, DATA, 1);
1568 /* now read actually the index */
1574 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1576 stuffp->toc[trk].index = 0;
1578 for (retries = 300; retries; retries--) { /* why 300? */
1579 struct s_subqcode q;
1582 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1583 mcdx_setdrivemode(stuffp, DATA, 1);
1587 idx = bcd2uint(q.index);
1590 && (idx <= stuffp->di.n_last)
1592 && (stuffp->toc[idx - stuffp->di.n_first].
1594 stuffp->toc[idx - stuffp->di.n_first] = q;
1596 "ioctl() toc idx %d (trk %d)\n",
1604 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1605 sizeof(stuffp->toc[0]));
1606 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1607 1].dt = stuffp->di.msf_leadout;
1610 /* unset toc mode */
1611 xtrace(READTOC, "ioctl() undo toc mode\n");
1612 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1615 #if MCDX_DEBUG && READTOC
1619 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1621 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1622 " %02x:%02x.%02x %02x:%02x.%02x\n",
1623 trk + stuffp->di.n_first,
1624 stuffp->toc[trk].control,
1625 stuffp->toc[trk].tno,
1626 stuffp->toc[trk].index,
1627 stuffp->toc[trk].tt.minute,
1628 stuffp->toc[trk].tt.second,
1629 stuffp->toc[trk].tt.frame,
1630 stuffp->toc[trk].dt.minute,
1631 stuffp->toc[trk].dt.second,
1632 stuffp->toc[trk].dt.frame);
1640 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1642 unsigned char cmd[7] = {
1646 if (!stuffp->readcmd) {
1647 xinfo("Can't play from missing disk.\n");
1651 cmd[0] = stuffp->playcmd;
1653 cmd[1] = msf->cdmsf_min0;
1654 cmd[2] = msf->cdmsf_sec0;
1655 cmd[3] = msf->cdmsf_frame0;
1656 cmd[4] = msf->cdmsf_min1;
1657 cmd[5] = msf->cdmsf_sec1;
1658 cmd[6] = msf->cdmsf_frame1;
1660 xtrace(PLAYMSF, "ioctl(): play %x "
1661 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1662 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1664 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1666 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1667 xwarn("playmsf() timeout\n");
1671 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1676 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1678 struct s_subqcode *p;
1679 struct cdrom_msf msf;
1681 if (-1 == mcdx_readtoc(stuffp))
1685 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1689 msf.cdmsf_min0 = p->dt.minute;
1690 msf.cdmsf_sec0 = p->dt.second;
1691 msf.cdmsf_frame0 = p->dt.frame;
1694 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1699 msf.cdmsf_min1 = p->dt.minute;
1700 msf.cdmsf_sec1 = p->dt.second;
1701 msf.cdmsf_frame1 = p->dt.frame;
1703 return mcdx_playmsf(stuffp, &msf);
1707 /* Drive functions ************************************************/
1709 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1711 struct s_drive_stuff *stuffp = cdi->handle;
1713 if (!stuffp->present)
1715 if (!(stuffp->present & DOOR))
1718 if (position) /* 1: eject */
1719 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1721 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1725 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1727 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1730 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1732 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1735 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1736 struct s_subqcode *sub, int tries)
1741 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1744 sub->control = buf[1];
1746 sub->index = buf[3];
1747 sub->tt.minute = buf[4];
1748 sub->tt.second = buf[5];
1749 sub->tt.frame = buf[6];
1750 sub->dt.minute = buf[8];
1751 sub->dt.second = buf[9];
1752 sub->dt.frame = buf[10];
1757 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1758 struct s_multi *multi, int tries)
1763 if (stuffp->present & MULTI) {
1765 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1767 multi->multi = buf[1];
1768 multi->msf_last.minute = buf[2];
1769 multi->msf_last.second = buf[3];
1770 multi->msf_last.frame = buf[4];
1778 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1784 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1789 info->n_first = bcd2uint(buf[1]);
1790 info->n_last = bcd2uint(buf[2]);
1791 info->msf_leadout.minute = buf[3];
1792 info->msf_leadout.second = buf[4];
1793 info->msf_leadout.frame = buf[5];
1794 info->msf_first.minute = buf[6];
1795 info->msf_first.second = buf[7];
1796 info->msf_first.frame = buf[8];
1801 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1807 xtrace(HW, "setdrivemode() %d\n", mode);
1809 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1829 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1832 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1835 unsigned char cmd[2] = { 0xa0 };
1836 xtrace(HW, "setdatamode() %d\n", mode);
1850 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1853 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1857 xtrace(HW, "config()\n");
1861 cmd[1] = 0x10; /* irq enable */
1862 cmd[2] = 0x05; /* pre, err irq enable */
1864 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1867 cmd[1] = 0x02; /* dma select */
1868 cmd[2] = 0x00; /* no dma */
1870 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1873 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1879 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1880 1, buf, sizeof(buf), 2 * HZ, tries)))
1889 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1892 outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */
1893 outb(0, stuffp->wreg_reset); /* hw reset */
1896 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1899 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1901 struct s_drive_stuff *stuffp = cdi->handle;
1902 char cmd[2] = { 0xfe };
1904 if (!(stuffp->present & DOOR))
1906 if (stuffp->present & DOOR) {
1907 cmd[1] = lock ? 0x01 : 0x00;
1908 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1913 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1915 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1919 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1921 unsigned long timeout = to + jiffies;
1927 while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1928 if (time_after(jiffies, timeout))
1930 mcdx_delay(stuffp, delay);
1933 *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1938 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1939 struct cdrom_volctrl *vol, int tries)
1943 cmd[1] = vol->channel0;
1945 cmd[3] = vol->channel1;
1948 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1951 MODULE_LICENSE("GPL");
1952 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);