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.1.1.1 2005/04/11 02:50:17 jack Exp $";
59 #include <linux/version.h>
60 #include <linux/module.h>
62 #include <linux/errno.h>
63 #include <linux/sched.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/uaccess.h>
74 #include <linux/major.h>
75 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76 #include <linux/blk.h>
77 #include <linux/devfs_fs_kernel.h>
79 /* for compatible parameter passing with "insmod" */
80 #define mcdx_drive_map mcdx
83 #if BITS_PER_LONG != 32
84 # error FIXME: this driver only works on 32-bit platforms
91 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
94 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
96 #define xinfo(fmt, args...) { ; }
100 #define xtrace(lvl, fmt, args...) \
102 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
103 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
105 #define xtrace(lvl, fmt, args...) { ; }
106 #define xdebug(fmt, args...) { ; }
109 /* CONSTANTS *******************************************************/
111 /* Following are the number of sectors we _request_ from the drive
112 every time an access outside the already requested range is done.
113 The _direct_ size is the number of sectors we're allowed to skip
114 directly (performing a read instead of requesting the new sector
116 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
117 const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
119 enum drivemodes { TOC, DATA, RAW, COOKED };
120 enum datamodes { MODE0, MODE1, MODE2 };
121 enum resetmodes { SOFT, HARD };
123 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
124 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
125 const int DOOR = 0x04; /* door locking capability */
126 const int MULTI = 0x08; /* multi session capability */
128 const unsigned char READ1X = 0xc0;
129 const unsigned char READ2X = 0xc1;
132 /* DECLARATIONS ****************************************************/
134 unsigned char control;
137 struct cdrom_msf0 tt;
138 struct cdrom_msf0 dt;
142 unsigned int n_first;
144 struct cdrom_msf0 msf_leadout;
145 struct cdrom_msf0 msf_first;
150 struct cdrom_msf0 msf_last;
158 /* Per drive/controller stuff **************************************/
160 struct s_drive_stuff {
162 wait_queue_head_t busyq;
163 wait_queue_head_t lockq;
164 wait_queue_head_t sleepq;
167 volatile int introk; /* status of last irq operation */
168 volatile int busy; /* drive performs an operation */
169 volatile int lock; /* exclusive usage */
172 struct s_diskinfo di;
173 struct s_multi multi;
174 struct s_subqcode *toc; /* first entry of the toc array */
175 struct s_subqcode start;
176 struct s_subqcode stop;
177 int xa; /* 1 if xa disk */
178 int audio; /* 1 if audio disk */
181 /* `buffer' control */
182 volatile int valid; /* pending, ..., values are valid */
183 volatile int pending; /* next sector to be read */
184 volatile int low_border; /* first sector not to be skipped direct */
185 volatile int high_border; /* first sector `out of area' */
187 volatile int int_err;
191 void *wreg_data; /* w data */
192 void *wreg_reset; /* w hardware reset */
193 void *wreg_hcon; /* w hardware conf */
194 void *wreg_chn; /* w channel */
195 void *rreg_data; /* r data */
196 void *rreg_status; /* r status */
198 int irq; /* irq used by this drive */
199 int minor; /* minor number of this drive */
200 int present; /* drive present and its capabilities */
201 unsigned char readcmd; /* read cmd depends on single/double speed */
202 unsigned char playcmd; /* play should always be single speed */
203 unsigned int xxx; /* set if changed, reset while open */
204 unsigned int yyy; /* set if changed, reset by media_changed */
205 int users; /* keeps track of open/close */
206 int lastsector; /* last block accessible */
207 int status; /* last operation's error / status */
208 int readerrs; /* # of blocks read w/o error */
212 /* Prototypes ******************************************************/
214 /* The following prototypes are already declared elsewhere. They are
215 repeated here to show what's going on. And to sense, if they're
216 changed elsewhere. */
218 /* declared in blk.h */
220 void do_mcdx_request(request_queue_t * q);
222 struct block_device_operations mcdx_bdops =
226 release: cdrom_release,
228 check_media_change: cdrom_media_changed,
232 /* Indirect exported functions. These functions are exported by their
233 addresses, such as mcdx_open and mcdx_close in the
234 structure mcdx_dops. */
236 /* ??? exported by the mcdx_sigaction struct */
237 static void mcdx_intr(int, void *, struct pt_regs *);
239 /* exported by file_ops */
240 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
241 static void mcdx_close(struct cdrom_device_info *cdi);
242 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
243 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
244 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
245 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
246 unsigned int cmd, void *arg);
248 /* misc internal support functions */
249 static void log2msf(unsigned int, struct cdrom_msf0 *);
250 static unsigned int msf2log(const struct cdrom_msf0 *);
251 static unsigned int uint2bcd(unsigned int);
252 static unsigned int bcd2uint(unsigned char);
253 static char *port(int *);
254 static int irq(int *);
255 static void mcdx_delay(struct s_drive_stuff *, long jifs);
256 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
258 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
261 static int mcdx_config(struct s_drive_stuff *, int);
262 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
264 static int mcdx_stop(struct s_drive_stuff *, int);
265 static int mcdx_hold(struct s_drive_stuff *, int);
266 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
267 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
268 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
269 static int mcdx_requestsubqcode(struct s_drive_stuff *,
270 struct s_subqcode *, int);
271 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
272 struct s_multi *, int);
273 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
275 static int mcdx_getstatus(struct s_drive_stuff *, int);
276 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
277 static int mcdx_talk(struct s_drive_stuff *,
278 const unsigned char *cmd, size_t,
279 void *buffer, size_t size, unsigned int timeout, int);
280 static int mcdx_readtoc(struct s_drive_stuff *);
281 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
282 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
283 static int mcdx_setattentuator(struct s_drive_stuff *,
284 struct cdrom_volctrl *, int);
286 /* static variables ************************************************/
288 static int mcdx_blocksizes[MCDX_NDRIVES];
289 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
290 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
291 static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
292 0, 0, 0, 0, 0, 0, 0, 0
294 MODULE_PARM(mcdx, "1-4i");
296 static struct cdrom_device_ops mcdx_dops = {
299 media_changed:mcdx_media_changed,
300 tray_move:mcdx_tray_move,
301 lock_door:mcdx_lockdoor,
302 audio_ioctl:mcdx_audio_ioctl,
303 capability:CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
304 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
307 static struct cdrom_device_info mcdx_info = {
315 /* KERNEL INTERFACE FUNCTIONS **************************************/
318 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
319 unsigned int cmd, void *arg)
321 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
323 if (!stuffp->present)
327 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
328 stuffp->lastsector = -1;
330 stuffp->lastsector = (CD_FRAMESIZE / 512)
331 * msf2log(&stuffp->di.msf_leadout) - 1;
337 if (-1 == mcdx_readtoc(stuffp))
346 xtrace(IOCTL, "ioctl() START\n");
347 /* Spin up the drive. Don't think we can do this.
348 * For now, ignore it.
354 xtrace(IOCTL, "ioctl() STOP\n");
355 stuffp->audiostatus = CDROM_AUDIO_INVALID;
356 if (-1 == mcdx_stop(stuffp, 1))
361 case CDROMPLAYTRKIND:{
362 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
364 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
365 if ((ti->cdti_trk0 < stuffp->di.n_first)
366 || (ti->cdti_trk0 > stuffp->di.n_last)
367 || (ti->cdti_trk1 < stuffp->di.n_first))
369 if (ti->cdti_trk1 > stuffp->di.n_last)
370 ti->cdti_trk1 = stuffp->di.n_last;
371 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
372 ti->cdti_trk0, ti->cdti_trk1);
373 return mcdx_playtrk(stuffp, ti);
377 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
379 xtrace(IOCTL, "ioctl() PLAYMSF\n");
381 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
382 && (-1 == mcdx_hold(stuffp, 1)))
385 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
386 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
387 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
389 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
390 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
391 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
393 stuffp->stop.dt.minute = msf->cdmsf_min1;
394 stuffp->stop.dt.second = msf->cdmsf_sec1;
395 stuffp->stop.dt.frame = msf->cdmsf_frame1;
397 return mcdx_playmsf(stuffp, msf);
401 xtrace(IOCTL, "ioctl() RESUME\n");
402 return mcdx_playtrk(stuffp, NULL);
405 case CDROMREADTOCENTRY:{
406 struct cdrom_tocentry *entry =
407 (struct cdrom_tocentry *) arg;
408 struct s_subqcode *tp = NULL;
409 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
411 if (-1 == mcdx_readtoc(stuffp))
413 if (entry->cdte_track == CDROM_LEADOUT)
414 tp = &stuffp->toc[stuffp->di.n_last -
415 stuffp->di.n_first + 1];
416 else if (entry->cdte_track > stuffp->di.n_last
417 || entry->cdte_track < stuffp->di.n_first)
420 tp = &stuffp->toc[entry->cdte_track -
425 entry->cdte_adr = tp->control;
426 entry->cdte_ctrl = tp->control >> 4;
427 /* Always return stuff in MSF, and let the Uniform cdrom driver
428 worry about what the user actually wants */
429 entry->cdte_addr.msf.minute =
430 bcd2uint(tp->dt.minute);
431 entry->cdte_addr.msf.second =
432 bcd2uint(tp->dt.second);
433 entry->cdte_addr.msf.frame =
434 bcd2uint(tp->dt.frame);
439 struct cdrom_subchnl *sub =
440 (struct cdrom_subchnl *) arg;
443 xtrace(IOCTL, "ioctl() SUBCHNL\n");
445 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
448 xtrace(SUBCHNL, "audiostatus: %x\n",
449 stuffp->audiostatus);
450 sub->cdsc_audiostatus = stuffp->audiostatus;
451 sub->cdsc_adr = q.control;
452 sub->cdsc_ctrl = q.control >> 4;
453 sub->cdsc_trk = bcd2uint(q.tno);
454 sub->cdsc_ind = bcd2uint(q.index);
456 xtrace(SUBCHNL, "trk %d, ind %d\n",
457 sub->cdsc_trk, sub->cdsc_ind);
458 /* Always return stuff in MSF, and let the Uniform cdrom driver
459 worry about what the user actually wants */
460 sub->cdsc_absaddr.msf.minute =
461 bcd2uint(q.dt.minute);
462 sub->cdsc_absaddr.msf.second =
463 bcd2uint(q.dt.second);
464 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
465 sub->cdsc_reladdr.msf.minute =
466 bcd2uint(q.tt.minute);
467 sub->cdsc_reladdr.msf.second =
468 bcd2uint(q.tt.second);
469 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
471 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
472 sub->cdsc_absaddr.msf.minute,
473 sub->cdsc_absaddr.msf.second,
474 sub->cdsc_absaddr.msf.frame,
475 sub->cdsc_reladdr.msf.minute,
476 sub->cdsc_reladdr.msf.second,
477 sub->cdsc_reladdr.msf.frame);
482 case CDROMREADTOCHDR:{
483 struct cdrom_tochdr *toc =
484 (struct cdrom_tochdr *) arg;
486 xtrace(IOCTL, "ioctl() READTOCHDR\n");
487 toc->cdth_trk0 = stuffp->di.n_first;
488 toc->cdth_trk1 = stuffp->di.n_last;
490 "ioctl() track0 = %d, track1 = %d\n",
491 stuffp->di.n_first, stuffp->di.n_last);
496 xtrace(IOCTL, "ioctl() PAUSE\n");
497 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
499 if (-1 == mcdx_stop(stuffp, 1))
501 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
503 mcdx_requestsubqcode(stuffp, &stuffp->start,
509 case CDROMMULTISESSION:{
510 struct cdrom_multisession *ms =
511 (struct cdrom_multisession *) arg;
512 xtrace(IOCTL, "ioctl() MULTISESSION\n");
513 /* Always return stuff in LBA, and let the Uniform cdrom driver
514 worry about what the user actually wants */
515 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
516 ms->xa_flag = !!stuffp->multi.multi;
518 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
519 ms->xa_flag, ms->addr.lba,
520 stuffp->multi.msf_last.minute,
521 stuffp->multi.msf_last.second,
522 stuffp->multi.msf_last.frame);
528 xtrace(IOCTL, "ioctl() EJECT\n");
529 if (stuffp->users > 1)
531 return (mcdx_tray_move(cdi, 1));
534 case CDROMCLOSETRAY:{
535 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
536 return (mcdx_tray_move(cdi, 0));
540 struct cdrom_volctrl *volctrl =
541 (struct cdrom_volctrl *) arg;
542 xtrace(IOCTL, "ioctl() VOLCTRL\n");
544 #if 0 /* not tested! */
545 /* adjust for the weirdness of workman (md) */
546 /* can't test it (hs) */
547 volctrl.channel2 = volctrl.channel1;
548 volctrl.channel1 = volctrl.channel3 = 0x00;
550 return mcdx_setattentuator(stuffp, volctrl, 2);
558 void do_mcdx_request(request_queue_t * q)
561 struct s_drive_stuff *stuffp;
566 xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
570 if (CURRENT->rq_status == RQ_INACTIVE) {
572 "end_request(0): rq_status == RQ_INACTIVE\n");
578 dev = MINOR(CURRENT->rq_dev);
579 stuffp = mcdx_stuffp[dev];
582 || (dev >= MCDX_NDRIVES)
583 || !stuffp || (!stuffp->present)) {
584 xwarn("do_request(): bad device: %s\n",
585 kdevname(CURRENT->rq_dev));
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 CURRENT->sector, CURRENT->nr_sectors);
601 switch (CURRENT->cmd) {
603 xwarn("do_request(): attempt to write to cd!!\n");
604 xtrace(REQUEST, "end_request(0): write\n");
610 while (CURRENT->nr_sectors) {
613 i = mcdx_transfer(stuffp,
616 CURRENT->nr_sectors);
622 CURRENT->sector += i;
623 CURRENT->nr_sectors -= i;
624 CURRENT->buffer += (i * 512);
629 xtrace(REQUEST, "end_request(1)\n");
634 panic(MCDX "do_request: unknown command.\n");
641 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
643 struct s_drive_stuff *stuffp;
644 xtrace(OPENCLOSE, "open()\n");
645 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
646 if (!stuffp->present)
649 /* Make the modules looking used ... (thanx bjorn).
650 * But we shouldn't forget to decrement the module counter
653 /* this is only done to test if the drive talks with us */
654 if (-1 == mcdx_getstatus(stuffp, 1))
659 xtrace(OPENCLOSE, "open() media changed\n");
660 stuffp->audiostatus = CDROM_AUDIO_INVALID;
662 xtrace(OPENCLOSE, "open() Request multisession info\n");
664 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
665 xinfo("No multidiskinfo\n");
668 if (!stuffp->multi.multi)
669 stuffp->multi.msf_last.second = 2;
671 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
673 stuffp->multi.msf_last.minute,
674 stuffp->multi.msf_last.second,
675 stuffp->multi.msf_last.frame);
678 } /* got multisession information */
679 /* request the disks table of contents (aka diskinfo) */
680 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
682 stuffp->lastsector = -1;
686 stuffp->lastsector = (CD_FRAMESIZE / 512)
687 * msf2log(&stuffp->di.msf_leadout) - 1;
690 "open() start %d (%02x:%02x.%02x) %d\n",
692 stuffp->di.msf_first.minute,
693 stuffp->di.msf_first.second,
694 stuffp->di.msf_first.frame,
695 msf2log(&stuffp->di.msf_first));
697 "open() last %d (%02x:%02x.%02x) %d\n",
699 stuffp->di.msf_leadout.minute,
700 stuffp->di.msf_leadout.second,
701 stuffp->di.msf_leadout.frame,
702 msf2log(&stuffp->di.msf_leadout));
706 xtrace(MALLOC, "open() free old toc @ %p\n",
713 xtrace(OPENCLOSE, "open() init irq generation\n");
714 if (-1 == mcdx_config(stuffp, 1))
717 /* Set the read speed */
718 xwarn("AAA %x AAA\n", stuffp->readcmd);
719 if (stuffp->readerrs)
720 stuffp->readcmd = READ1X;
723 stuffp->present | SINGLE ? READ1X : READ2X;
724 xwarn("XXX %x XXX\n", stuffp->readcmd);
727 stuffp->present | SINGLE ? READ1X : READ2X;
730 /* try to get the first sector, iff any ... */
731 if (stuffp->lastsector >= 0) {
739 for (tries = 6; tries; tries--) {
743 xtrace(OPENCLOSE, "open() try as %s\n",
744 stuffp->xa ? "XA" : "normal");
746 if (-1 == (ans = mcdx_setdatamode(stuffp,
757 if ((stuffp->audio = e_audio(ans)))
762 mcdx_transfer(stuffp, buf, 0, 1)));
766 stuffp->xa = !stuffp->xa;
769 /* xa disks will be read in raw mode, others not */
770 if (-1 == mcdx_setdrivemode(stuffp,
771 stuffp->xa ? RAW : COOKED,
775 xinfo("open() audio disk found\n");
776 } else if (stuffp->lastsector >= 0) {
777 xinfo("open() %s%s disk found\n",
778 stuffp->xa ? "XA / " : "",
780 multi ? "Multi Session" : "Single Session");
788 static void mcdx_close(struct cdrom_device_info *cdi)
790 struct s_drive_stuff *stuffp;
792 xtrace(OPENCLOSE, "close()\n");
794 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
799 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
800 /* Return: 1 if media changed since last call to this function
803 struct s_drive_stuff *stuffp;
805 xinfo("mcdx_media_changed called for device %s\n",
808 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
809 mcdx_getstatus(stuffp, 1);
811 if (stuffp->yyy == 0)
819 static int __init mcdx_setup(char *str)
822 (void) get_options(str, ARRAY_SIZE(pi), pi);
825 mcdx_drive_map[0][0] = pi[1];
827 mcdx_drive_map[0][1] = pi[2];
831 __setup("mcdx=", mcdx_setup);
835 /* DIRTY PART ******************************************************/
837 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
838 /* This routine is used for sleeping.
839 * A jifs value <0 means NO sleeping,
840 * =0 means minimal sleeping (let the kernel
841 * run for other processes)
842 * >0 means at least sleep for that amount.
843 * May be we could use a simple count loop w/ jumps to itself, but
844 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
849 xtrace(SLEEP, "*** delay: sleepq\n");
850 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
851 xtrace(SLEEP, "delay awoken\n");
852 if (signal_pending(current)) {
853 xtrace(SLEEP, "got signal\n");
857 static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
859 struct s_drive_stuff *stuffp;
862 stuffp = mcdx_irq_map[irq];
864 if (stuffp == NULL) {
865 xwarn("mcdx: no device for intr %d\n", irq);
869 if (!stuffp->busy && stuffp->pending)
873 /* get the interrupt status */
874 b = inb((unsigned int) stuffp->rreg_status);
875 stuffp->introk = ~b & MCDX_RBIT_DTEN;
877 /* NOTE: We only should get interrupts if the data we
878 * requested are ready to transfer.
879 * But the drive seems to generate ``asynchronous'' interrupts
880 * on several error conditions too. (Despite the err int enable
881 * setting during initialisation) */
883 /* if not ok, read the next byte as the drives status */
884 if (!stuffp->introk) {
885 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
886 if (~b & MCDX_RBIT_STEN) {
887 xinfo("intr() irq %d status 0x%02x\n",
888 irq, inb((unsigned int) stuffp->rreg_data));
890 xinfo("intr() irq %d ambiguous hw status\n", irq);
893 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
897 wake_up_interruptible(&stuffp->busyq);
901 static int mcdx_talk(struct s_drive_stuff *stuffp,
902 const unsigned char *cmd, size_t cmdlen,
903 void *buffer, size_t size, unsigned int timeout, int tries)
904 /* Send a command to the drive, wait for the result.
905 * returns -1 on timeout, drive status otherwise
906 * If buffer is not zero, the result (length size) is stored there.
907 * If buffer is zero the size should be the number of bytes to read
908 * from the drive. These bytes are discarded.
915 /* Somebody wants the data read? */
916 if ((discard = (buffer == NULL)))
919 while (stuffp->lock) {
920 xtrace(SLEEP, "*** talk: lockq\n");
921 interruptible_sleep_on(&stuffp->lockq);
922 xtrace(SLEEP, "talk: awoken\n");
927 /* An operation other then reading data destroys the
928 * data already requested and remembered in stuffp->request, ... */
931 #if MCDX_DEBUG & TALK
935 "talk() %d / %d tries, res.size %d, command 0x%02x",
936 tries, timeout, size, (unsigned char) cmd[0]);
937 for (i = 1; i < cmdlen; i++)
938 xtrace(TALK, " 0x%02x", cmd[i]);
943 /* give up if all tries are done (bad) or if the status
945 for (st = -1; st == -1 && tries; tries--) {
947 char *bp = (char *) buffer;
950 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
951 xtrace(TALK, "talk() command sent\n");
953 /* get the status byte */
954 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
955 xinfo("talk() %02x timed out (status), %d tr%s left\n",
956 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
964 xtrace(TALK, "talk() got status 0x%02x\n", st);
968 xwarn("command error cmd = %02x %s \n",
969 cmd[0], cmdlen > 1 ? "..." : "");
975 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
976 stuffp->audiostatus =
977 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
978 CDROM_AUDIO_NO_STATUS;
979 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
980 && e_audiobusy(st) == 0)
981 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
985 xinfo("talk() media changed\n");
986 stuffp->xxx = stuffp->yyy = 1;
989 /* now actually get the data */
991 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
992 xinfo("talk() %02x timed out (data), %d tr%s left\n",
994 tries == 2 ? "y" : "ies");
1000 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
1005 if (!tries && st == -1)
1006 xinfo("talk() giving up\n");
1010 wake_up_interruptible(&stuffp->lockq);
1012 xtrace(TALK, "talk() done with 0x%02x\n", st);
1016 /* MODULE STUFF ***********************************************************/
1020 int __mcdx_init(void)
1026 for (i = 0; i < MCDX_NDRIVES; i++) {
1027 if (mcdx_stuffp[i]) {
1028 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1040 void __exit mcdx_exit(void)
1044 xinfo("cleanup_module called\n");
1046 for (i = 0; i < MCDX_NDRIVES; i++) {
1047 struct s_drive_stuff *stuffp;
1048 if (unregister_cdrom(&mcdx_info)) {
1049 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1052 stuffp = mcdx_stuffp[i];
1055 release_region((unsigned long) stuffp->wreg_data,
1057 free_irq(stuffp->irq, NULL);
1059 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1063 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1065 mcdx_stuffp[i] = NULL;
1069 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1070 xwarn("cleanup() unregister_blkdev() failed\n");
1072 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1075 xinfo("cleanup() succeeded\n");
1080 module_init(__mcdx_init);
1082 module_exit(mcdx_exit);
1085 /* Support functions ************************************************/
1087 int __init mcdx_init_drive(int drive)
1089 struct s_version version;
1090 struct s_drive_stuff *stuffp;
1091 int size = sizeof(*stuffp);
1094 mcdx_blocksizes[drive] = 0;
1096 xtrace(INIT, "init() try drive %d\n", drive);
1098 xtrace(INIT, "kmalloc space for stuffpt's\n");
1099 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1100 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1101 xwarn("init() malloc failed\n");
1105 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1106 sizeof(*stuffp), stuffp);
1108 /* set default values */
1109 memset(stuffp, 0, sizeof(*stuffp));
1111 stuffp->present = 0; /* this should be 0 already */
1112 stuffp->toc = NULL; /* this should be NULL already */
1114 /* setup our irq and i/o addresses */
1115 stuffp->irq = irq(mcdx_drive_map[drive]);
1116 stuffp->wreg_data = stuffp->rreg_data =
1117 port(mcdx_drive_map[drive]);
1118 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1119 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1120 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1122 init_waitqueue_head(&stuffp->busyq);
1123 init_waitqueue_head(&stuffp->lockq);
1124 init_waitqueue_head(&stuffp->sleepq);
1126 /* check if i/o addresses are available */
1127 if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1128 xwarn("0x%3p,%d: Init failed. "
1129 "I/O ports (0x%3p..0x%3p) already in use.\n",
1130 stuffp->wreg_data, stuffp->irq,
1132 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1133 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1135 xtrace(INIT, "init() continue at next drive\n");
1136 return 0; /* next drive */
1139 xtrace(INIT, "init() i/o port is available at 0x%3p\n",
1141 xtrace(INIT, "init() hardware reset\n");
1142 mcdx_reset(stuffp, HARD, 1);
1144 xtrace(INIT, "init() get version\n");
1145 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1146 /* failed, next drive */
1147 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1148 MCDX, stuffp->wreg_data, stuffp->irq);
1149 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 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1177 MCDX, stuffp->wreg_data, stuffp->irq);
1179 return 0; /* next drive */
1182 xtrace(INIT, "init() register blkdev\n");
1183 if (devfs_register_blkdev(MAJOR_NR, "mcdx", &mcdx_bdops) != 0) {
1184 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1185 MCDX, stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1190 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1191 read_ahead[MAJOR_NR] = READ_AHEAD;
1192 blksize_size[MAJOR_NR] = mcdx_blocksizes;
1194 xtrace(INIT, "init() subscribe irq and i/o\n");
1195 mcdx_irq_map[stuffp->irq] = stuffp;
1196 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1197 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1198 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1200 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1204 request_region((unsigned int) stuffp->wreg_data,
1205 MCDX_IO_SIZE, "mcdx");
1207 xtrace(INIT, "init() get garbage\n");
1210 mcdx_delay(stuffp, HZ / 2);
1211 for (i = 100; i; i--)
1212 (void) inb((unsigned int) stuffp->rreg_status);
1217 /* irq 11 -> channel register */
1218 outb(0x50, (unsigned int) stuffp->wreg_chn);
1221 xtrace(INIT, "init() set non dma but irq mode\n");
1222 mcdx_config(stuffp, 1);
1224 stuffp->minor = drive;
1226 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1227 " (Firmware version %c %x)\n",
1228 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1229 mcdx_stuffp[drive] = stuffp;
1230 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1231 mcdx_info.dev = MKDEV(MAJOR_NR, 0);
1232 if (register_cdrom(&mcdx_info) != 0) {
1233 printk("Cannot register Mitsumi CD-ROM!\n");
1234 release_region((unsigned long) stuffp->wreg_data,
1236 free_irq(stuffp->irq, NULL);
1238 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1239 xwarn("cleanup() unregister_blkdev() failed\n");
1240 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1243 devfs_plain_cdrom(&mcdx_info, &mcdx_bdops);
1248 int __init mcdx_init(void)
1252 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1254 xwarn("Version 2.14(hs) \n");
1257 xwarn("$Id: mcdx.c,v 1.1.1.1 2005/04/11 02:50:17 jack Exp $\n");
1259 /* zero the pointer array */
1260 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1261 mcdx_stuffp[drive] = NULL;
1263 /* do the initialisation */
1264 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1265 switch (mcdx_init_drive(drive)) {
1275 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1276 char *p, int sector, int nr_sectors)
1277 /* This seems to do the actually transfer. But it does more. It
1278 keeps track of errors occurred and will (if possible) fall back
1279 to single speed on error.
1280 Return: -1 on timeout or other error
1281 else status byte (as in stuff->st) */
1285 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1293 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1294 xwarn("XXX Already reading 1x -- no chance\n");
1298 xwarn("XXX Fallback to 1x\n");
1300 stuffp->readcmd = READ1X;
1301 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1307 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1308 char *p, int sector, int nr_sectors)
1309 /* This does actually the transfer from the drive.
1310 Return: -1 on timeout or other error
1311 else status byte (as in stuff->st) */
1317 if (stuffp->audio) {
1318 xwarn("Attempt to read from audio CD.\n");
1322 if (!stuffp->readcmd) {
1323 xinfo("Can't transfer from missing disk.\n");
1327 while (stuffp->lock) {
1328 interruptible_sleep_on(&stuffp->lockq);
1331 if (stuffp->valid && (sector >= stuffp->pending)
1332 && (sector < stuffp->low_border)) {
1334 /* All (or at least a part of the sectors requested) seems
1335 * to be already requested, so we don't need to bother the
1336 * drive with new requests ...
1337 * Wait for the drive become idle, but first
1338 * check for possible occurred errors --- the drive
1339 * seems to report them asynchronously */
1342 border = stuffp->high_border < (border =
1343 sector + nr_sectors)
1344 ? stuffp->high_border : border;
1346 stuffp->lock = current->pid;
1350 while (stuffp->busy) {
1353 interruptible_sleep_on_timeout
1354 (&stuffp->busyq, 5 * HZ);
1356 if (!stuffp->introk) {
1358 "error via interrupt\n");
1359 } else if (!timeout) {
1360 xtrace(XFER, "timeout\n");
1361 } else if (signal_pending(current)) {
1362 xtrace(XFER, "signal\n");
1370 wake_up_interruptible(&stuffp->lockq);
1371 xtrace(XFER, "transfer() done (-1)\n");
1375 /* check if we need to set the busy flag (as we
1376 * expect an interrupt */
1377 stuffp->busy = (3 == (stuffp->pending & 3));
1379 /* Test if it's the first sector of a block,
1380 * there we have to skip some bytes as we read raw data */
1381 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1383 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1385 insb((unsigned int) stuffp->rreg_data, p,
1389 /* now actually read the data */
1390 insb((unsigned int) stuffp->rreg_data, p, 512);
1392 /* test if it's the last sector of a block,
1393 * if so, we have to handle XA special */
1394 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1395 char dummy[CD_XA_TAIL];
1396 insb((unsigned int) stuffp->rreg_data,
1397 &dummy[0], CD_XA_TAIL);
1400 if (stuffp->pending == sector) {
1405 } while (++(stuffp->pending) < border);
1408 wake_up_interruptible(&stuffp->lockq);
1412 /* The requested sector(s) is/are out of the
1413 * already requested range, so we have to bother the drive
1414 * with a new request. */
1416 static unsigned char cmd[] = {
1422 cmd[0] = stuffp->readcmd;
1424 /* The numbers held in ->pending, ..., should be valid */
1426 stuffp->pending = sector & ~3;
1428 /* do some sanity checks */
1429 if (stuffp->pending > stuffp->lastsector) {
1431 ("transfer() sector %d from nirvana requested.\n",
1433 stuffp->status = MCDX_ST_EOM;
1435 xtrace(XFER, "transfer() done (-1)\n");
1439 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1440 > stuffp->lastsector + 1) {
1441 xtrace(XFER, "cut low_border\n");
1442 stuffp->low_border = stuffp->lastsector + 1;
1444 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1445 > stuffp->lastsector + 1) {
1446 xtrace(XFER, "cut high_border\n");
1447 stuffp->high_border = stuffp->lastsector + 1;
1450 { /* Convert the sector to be requested to MSF format */
1451 struct cdrom_msf0 pending;
1452 log2msf(stuffp->pending / 4, &pending);
1453 cmd[1] = pending.minute;
1454 cmd[2] = pending.second;
1455 cmd[3] = pending.frame;
1460 char) ((stuffp->high_border - stuffp->pending) / 4);
1461 xtrace(XFER, "[%2d]\n", cmd[6]);
1464 /* Now really issue the request command */
1465 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1469 if (stuffp->int_err) {
1471 stuffp->int_err = 0;
1476 stuffp->low_border = (stuffp->low_border +=
1478 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1484 /* Access to elements of the mcdx_drive_map members */
1486 static char *port(int *ip)
1488 return (char *) ip[0];
1490 static int irq(int *ip)
1495 /* Misc number converters */
1497 static unsigned int bcd2uint(unsigned char c)
1499 return (c >> 4) * 10 + (c & 0x0f);
1502 static unsigned int uint2bcd(unsigned int ival)
1504 return ((ival / 10) << 4) | (ival % 10);
1507 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1510 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1511 pmsf->second = uint2bcd(l / 75);
1512 pmsf->frame = uint2bcd(l % 75);
1515 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1517 return bcd2uint(pmsf->frame)
1518 + bcd2uint(pmsf->second) * 75
1519 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1522 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1523 /* Read the toc entries from the CD,
1524 * Return: -1 on failure, else 0 */
1528 xtrace(READTOC, "ioctl() toc already read\n");
1532 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1533 stuffp->di.n_last - stuffp->di.n_first + 1);
1535 if (-1 == mcdx_hold(stuffp, 1))
1538 xtrace(READTOC, "ioctl() tocmode\n");
1539 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1542 /* all seems to be ok so far ... malloc */
1546 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1547 stuffp->di.n_first + 2);
1549 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1550 stuffp->toc = kmalloc(size, GFP_KERNEL);
1552 xwarn("Cannot malloc %d bytes for toc\n", size);
1553 mcdx_setdrivemode(stuffp, DATA, 1);
1558 /* now read actually the index */
1564 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1566 stuffp->toc[trk].index = 0;
1568 for (retries = 300; retries; retries--) { /* why 300? */
1569 struct s_subqcode q;
1572 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1573 mcdx_setdrivemode(stuffp, DATA, 1);
1577 idx = bcd2uint(q.index);
1580 && (idx <= stuffp->di.n_last)
1582 && (stuffp->toc[idx - stuffp->di.n_first].
1584 stuffp->toc[idx - stuffp->di.n_first] = q;
1586 "ioctl() toc idx %d (trk %d)\n",
1594 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1595 sizeof(stuffp->toc[0]));
1596 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1597 1].dt = stuffp->di.msf_leadout;
1600 /* unset toc mode */
1601 xtrace(READTOC, "ioctl() undo toc mode\n");
1602 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1605 #if MCDX_DEBUG && READTOC
1609 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1611 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1612 " %02x:%02x.%02x %02x:%02x.%02x\n",
1613 trk + stuffp->di.n_first,
1614 stuffp->toc[trk].control,
1615 stuffp->toc[trk].tno,
1616 stuffp->toc[trk].index,
1617 stuffp->toc[trk].tt.minute,
1618 stuffp->toc[trk].tt.second,
1619 stuffp->toc[trk].tt.frame,
1620 stuffp->toc[trk].dt.minute,
1621 stuffp->toc[trk].dt.second,
1622 stuffp->toc[trk].dt.frame);
1630 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1632 unsigned char cmd[7] = {
1636 if (!stuffp->readcmd) {
1637 xinfo("Can't play from missing disk.\n");
1641 cmd[0] = stuffp->playcmd;
1643 cmd[1] = msf->cdmsf_min0;
1644 cmd[2] = msf->cdmsf_sec0;
1645 cmd[3] = msf->cdmsf_frame0;
1646 cmd[4] = msf->cdmsf_min1;
1647 cmd[5] = msf->cdmsf_sec1;
1648 cmd[6] = msf->cdmsf_frame1;
1650 xtrace(PLAYMSF, "ioctl(): play %x "
1651 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1652 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1654 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1656 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1657 xwarn("playmsf() timeout\n");
1661 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1666 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1668 struct s_subqcode *p;
1669 struct cdrom_msf msf;
1671 if (-1 == mcdx_readtoc(stuffp))
1675 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1679 msf.cdmsf_min0 = p->dt.minute;
1680 msf.cdmsf_sec0 = p->dt.second;
1681 msf.cdmsf_frame0 = p->dt.frame;
1684 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1689 msf.cdmsf_min1 = p->dt.minute;
1690 msf.cdmsf_sec1 = p->dt.second;
1691 msf.cdmsf_frame1 = p->dt.frame;
1693 return mcdx_playmsf(stuffp, &msf);
1697 /* Drive functions ************************************************/
1699 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1701 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1703 if (!stuffp->present)
1705 if (!(stuffp->present & DOOR))
1708 if (position) /* 1: eject */
1709 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1711 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1715 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1717 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1720 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1722 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1725 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1726 struct s_subqcode *sub, int tries)
1731 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1734 sub->control = buf[1];
1736 sub->index = buf[3];
1737 sub->tt.minute = buf[4];
1738 sub->tt.second = buf[5];
1739 sub->tt.frame = buf[6];
1740 sub->dt.minute = buf[8];
1741 sub->dt.second = buf[9];
1742 sub->dt.frame = buf[10];
1747 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1748 struct s_multi *multi, int tries)
1753 if (stuffp->present & MULTI) {
1755 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1757 multi->multi = buf[1];
1758 multi->msf_last.minute = buf[2];
1759 multi->msf_last.second = buf[3];
1760 multi->msf_last.frame = buf[4];
1768 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1774 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1779 info->n_first = bcd2uint(buf[1]);
1780 info->n_last = bcd2uint(buf[2]);
1781 info->msf_leadout.minute = buf[3];
1782 info->msf_leadout.second = buf[4];
1783 info->msf_leadout.frame = buf[5];
1784 info->msf_first.minute = buf[6];
1785 info->msf_first.second = buf[7];
1786 info->msf_first.frame = buf[8];
1791 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1797 xtrace(HW, "setdrivemode() %d\n", mode);
1799 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1819 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1822 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1825 unsigned char cmd[2] = { 0xa0 };
1826 xtrace(HW, "setdatamode() %d\n", mode);
1840 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1843 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1847 xtrace(HW, "config()\n");
1851 cmd[1] = 0x10; /* irq enable */
1852 cmd[2] = 0x05; /* pre, err irq enable */
1854 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1857 cmd[1] = 0x02; /* dma select */
1858 cmd[2] = 0x00; /* no dma */
1860 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1863 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1869 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1870 1, buf, sizeof(buf), 2 * HZ, tries)))
1879 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1882 outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
1883 outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
1886 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1889 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1891 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1892 char cmd[2] = { 0xfe };
1894 if (!(stuffp->present & DOOR))
1896 if (stuffp->present & DOOR) {
1897 cmd[1] = lock ? 0x01 : 0x00;
1898 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1903 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1905 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1909 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1911 unsigned long timeout = to + jiffies;
1917 while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1918 if (time_after(jiffies, timeout))
1920 mcdx_delay(stuffp, delay);
1923 *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1928 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1929 struct cdrom_volctrl *vol, int tries)
1933 cmd[1] = vol->channel0;
1935 cmd[3] = vol->channel1;
1938 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1941 MODULE_LICENSE("GPL");