Revert last change. Bug noticed by Linus.
[linux-2.6/linux-mips.git] / drivers / cdrom / mcdx.c
blobac667047b28f860e20d9b34415de0de19d6e138c
1 /*
2 * The Mitsumi CDROM interface
3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4 * VERSION: 2.14(hs)
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]
13 * -- Please --
14 * mail me (heiko@lotte.sax.de). When my last drive goes
15 * ballistic no more driver support will be available from me!
16 *************************************************************
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2, or (at your option)
21 * any later version.
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.
32 * Thanks to
33 * The Linux Community at all and ...
34 * Martin Harriss (he wrote the first Mitsumi Driver)
35 * Eberhard Moenkeberg (he gave me much support and the initial kick)
36 * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
37 * improved the original driver)
38 * Jon Tombs, Bjorn Ekwall (module support)
39 * Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
40 * Gerd Knorr (he lent me his PhotoCD)
41 * Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
42 * Andreas Kies (testing the mysterious hang-ups)
43 * Heiko Eissfeldt (VERIFY_READ/WRITE)
44 * Marcin Dalecki (improved performance, shortened code)
45 * ... somebody forgotten?
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>
54 #if RCS
55 static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57 #endif
59 #include <linux/version.h>
60 #include <linux/module.h>
62 #include <linux/errno.h>
63 #include <linux/sched.h>
64 #include <linux/fs.h>
65 #include <linux/kernel.h>
66 #include <linux/cdrom.h>
67 #include <linux/ioport.h>
68 #include <linux/mm.h>
69 #include <linux/malloc.h>
70 #include <linux/init.h>
71 #include <asm/io.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
81 #include "mcdx.h"
83 #ifndef HZ
84 #error HZ not defined
85 #endif
87 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
89 #if !MCDX_QUIET
90 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
91 #else
92 #define xinfo(fmt, args...) { ; }
93 #endif
95 #if MCDX_DEBUG
96 #define xtrace(lvl, fmt, args...) \
97 { if (lvl > 0) \
98 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
99 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
100 #else
101 #define xtrace(lvl, fmt, args...) { ; }
102 #define xdebug(fmt, args...) { ; }
103 #endif
105 /* CONSTANTS *******************************************************/
107 /* Following are the number of sectors we _request_ from the drive
108 every time an access outside the already requested range is done.
109 The _direct_ size is the number of sectors we're allowed to skip
110 directly (performing a read instead of requesting the new sector
111 needed */
112 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
113 const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
115 enum drivemodes { TOC, DATA, RAW, COOKED };
116 enum datamodes { MODE0, MODE1, MODE2 };
117 enum resetmodes { SOFT, HARD };
119 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
120 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
121 const int DOOR = 0x04; /* door locking capability */
122 const int MULTI = 0x08; /* multi session capability */
124 const unsigned char READ1X = 0xc0;
125 const unsigned char READ2X = 0xc1;
128 /* DECLARATIONS ****************************************************/
129 struct s_subqcode {
130 unsigned char control;
131 unsigned char tno;
132 unsigned char index;
133 struct cdrom_msf0 tt;
134 struct cdrom_msf0 dt;
137 struct s_diskinfo {
138 unsigned int n_first;
139 unsigned int n_last;
140 struct cdrom_msf0 msf_leadout;
141 struct cdrom_msf0 msf_first;
144 struct s_multi {
145 unsigned char multi;
146 struct cdrom_msf0 msf_last;
149 struct s_version {
150 unsigned char code;
151 unsigned char ver;
154 /* Per drive/controller stuff **************************************/
156 struct s_drive_stuff {
157 /* waitqueues */
158 wait_queue_head_t busyq;
159 wait_queue_head_t lockq;
160 wait_queue_head_t sleepq;
162 /* flags */
163 volatile int introk; /* status of last irq operation */
164 volatile int busy; /* drive performs an operation */
165 volatile int lock; /* exclusive usage */
167 /* cd infos */
168 struct s_diskinfo di;
169 struct s_multi multi;
170 struct s_subqcode* toc; /* first entry of the toc array */
171 struct s_subqcode start;
172 struct s_subqcode stop;
173 int xa; /* 1 if xa disk */
174 int audio; /* 1 if audio disk */
175 int audiostatus;
177 /* `buffer' control */
178 volatile int valid; /* pending, ..., values are valid */
179 volatile int pending; /* next sector to be read */
180 volatile int low_border; /* first sector not to be skipped direct */
181 volatile int high_border; /* first sector `out of area' */
182 #ifdef AK2
183 volatile int int_err;
184 #endif /* AK2 */
186 /* adds and odds */
187 void* wreg_data; /* w data */
188 void* wreg_reset; /* w hardware reset */
189 void* wreg_hcon; /* w hardware conf */
190 void* wreg_chn; /* w channel */
191 void* rreg_data; /* r data */
192 void* rreg_status; /* r status */
194 int irq; /* irq used by this drive */
195 int minor; /* minor number of 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 */
208 /* Prototypes ******************************************************/
210 /* The following prototypes are already declared elsewhere. They are
211 repeated here to show what's going on. And to sense, if they're
212 changed elsewhere. */
214 /* declared in blk.h */
215 int mcdx_init(void);
216 void do_mcdx_request(request_queue_t * q);
219 /* Indirect exported functions. These functions are exported by their
220 addresses, such as mcdx_open and mcdx_close in the
221 structure mcdx_dops. */
223 /* ??? exported by the mcdx_sigaction struct */
224 static void mcdx_intr(int, void *, struct pt_regs*);
226 /* exported by file_ops */
227 static int mcdx_open(struct cdrom_device_info * cdi, int purpose);
228 static void mcdx_close(struct cdrom_device_info * cdi);
229 static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr);
230 static int mcdx_tray_move(struct cdrom_device_info * cdi, int position);
231 static int mcdx_lockdoor(struct cdrom_device_info * cdi, int lock);
232 static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
233 void * arg);
235 /* misc internal support functions */
236 static void log2msf(unsigned int, struct cdrom_msf0*);
237 static unsigned int msf2log(const struct cdrom_msf0*);
238 static unsigned int uint2bcd(unsigned int);
239 static unsigned int bcd2uint(unsigned char);
240 static char *port(int*);
241 static int irq(int*);
242 static void mcdx_delay(struct s_drive_stuff*, long jifs);
243 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
244 static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
246 static int mcdx_config(struct s_drive_stuff*, int);
247 static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
248 static int mcdx_stop(struct s_drive_stuff*, int);
249 static int mcdx_hold(struct s_drive_stuff*, int);
250 static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
251 static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
252 static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
253 static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
254 static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
255 static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
256 static int mcdx_getstatus(struct s_drive_stuff*, int);
257 static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
258 static int mcdx_talk(struct s_drive_stuff*,
259 const unsigned char* cmd, size_t,
260 void *buffer, size_t size,
261 unsigned int timeout, int);
262 static int mcdx_readtoc(struct s_drive_stuff*);
263 static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
264 static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
265 static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
267 /* static variables ************************************************/
269 static int mcdx_blocksizes[MCDX_NDRIVES];
270 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
271 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
272 static struct s_drive_stuff* mcdx_irq_map[16] =
273 {0, 0, 0, 0, 0, 0, 0, 0,
274 0, 0, 0, 0, 0, 0, 0, 0};
275 MODULE_PARM(mcdx, "1-4i");
277 static struct cdrom_device_ops mcdx_dops = {
278 mcdx_open, /* open */
279 mcdx_close, /* release */
280 NULL, /* drive status */
281 mcdx_media_changed, /* media changed */
282 mcdx_tray_move, /* tray move */
283 mcdx_lockdoor, /* lock door */
284 NULL, /* select speed */
285 NULL, /* select disc */
286 NULL, /* get last session */
287 NULL, /* get universal product code */
288 NULL, /* hard reset */
289 mcdx_audio_ioctl, /* audio ioctl */
290 NULL, /* device-specific ioctl */
291 CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO
292 | CDC_DRIVE_STATUS, /* capability */
293 0, /* number of minor devices */
296 static struct cdrom_device_info mcdx_info = {
297 &mcdx_dops, /* device operations */
298 NULL, /* link */
299 NULL, /* handle */
300 0, /* de, devfs */
301 0, /* dev */
302 0, /* mask */
303 2, /* maximum speed */
304 1, /* number of discs */
305 0, /* options, not owned */
306 0, /* mc_flags, not owned */
307 0, /* use count, not owned */
308 "mcdx", /* name of the device type */
313 /* KERNEL INTERFACE FUNCTIONS **************************************/
316 static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
317 void * arg)
319 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
321 if (!stuffp->present) return -ENXIO;
323 if (stuffp->xxx)
325 if(-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1))
327 stuffp->lastsector = -1;
329 else
331 stuffp->lastsector = (CD_FRAMESIZE / 512)
332 * msf2log(&stuffp->di.msf_leadout) - 1;
335 if (stuffp->toc)
337 kfree(stuffp->toc);
338 stuffp->toc = NULL;
339 if (-1 == mcdx_readtoc(stuffp)) return -1;
342 stuffp->xxx=0;
345 switch (cmd) {
346 case CDROMSTART: {
347 xtrace(IOCTL, "ioctl() START\n");
348 /* Spin up the drive. Don't think we can do this.
349 * For now, ignore it.
351 return 0;
354 case CDROMSTOP: {
355 xtrace(IOCTL, "ioctl() STOP\n");
356 stuffp->audiostatus = CDROM_AUDIO_INVALID;
357 if (-1 == mcdx_stop(stuffp, 1))
358 return -EIO;
359 return 0;
362 case CDROMPLAYTRKIND: {
363 struct cdrom_ti *ti=(struct cdrom_ti *) arg;
365 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
366 if ((ti->cdti_trk0 < stuffp->di.n_first)
367 || (ti->cdti_trk0 > stuffp->di.n_last)
368 || (ti->cdti_trk1 < stuffp->di.n_first))
369 return -EINVAL;
370 if (ti->cdti_trk1 > stuffp->di.n_last)
371 ti->cdti_trk1 = stuffp->di.n_last;
372 xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti->cdti_trk0, ti->cdti_trk1);
373 return mcdx_playtrk(stuffp, ti);
376 case CDROMPLAYMSF: {
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))) return -EIO;
384 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
385 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
386 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
388 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
389 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
390 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
392 stuffp->stop.dt.minute = msf->cdmsf_min1;
393 stuffp->stop.dt.second = msf->cdmsf_sec1;
394 stuffp->stop.dt.frame = msf->cdmsf_frame1;
396 return mcdx_playmsf(stuffp, msf);
399 case CDROMRESUME: {
400 xtrace(IOCTL, "ioctl() RESUME\n");
401 return mcdx_playtrk(stuffp, NULL);
404 case CDROMREADTOCENTRY: {
405 struct cdrom_tocentry *entry=(struct cdrom_tocentry *) arg;
406 struct s_subqcode *tp = NULL;
407 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
409 if (-1 == mcdx_readtoc(stuffp)) return -1;
410 if (entry->cdte_track == CDROM_LEADOUT)
411 tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
412 else if (entry->cdte_track > stuffp->di.n_last
413 || entry->cdte_track < stuffp->di.n_first) return -EINVAL;
414 else tp = &stuffp->toc[entry->cdte_track - stuffp->di.n_first];
416 if (NULL == tp)
417 return -EIO;
418 entry->cdte_adr = tp->control;
419 entry->cdte_ctrl = tp->control >> 4;
420 /* Always return stuff in MSF, and let the Uniform cdrom driver
421 worry about what the user actually wants */
422 entry->cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
423 entry->cdte_addr.msf.second = bcd2uint(tp->dt.second);
424 entry->cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
425 return 0;
428 case CDROMSUBCHNL: {
429 struct cdrom_subchnl *sub= (struct cdrom_subchnl *)arg;
430 struct s_subqcode q;
432 xtrace(IOCTL, "ioctl() SUBCHNL\n");
434 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
435 return -EIO;
437 xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus);
438 sub->cdsc_audiostatus = stuffp->audiostatus;
439 sub->cdsc_adr = q.control;
440 sub->cdsc_ctrl = q.control >> 4;
441 sub->cdsc_trk = bcd2uint(q.tno);
442 sub->cdsc_ind = bcd2uint(q.index);
444 xtrace(SUBCHNL, "trk %d, ind %d\n",
445 sub->cdsc_trk, sub->cdsc_ind);
446 /* Always return stuff in MSF, and let the Uniform cdrom driver
447 worry about what the user actually wants */
448 sub->cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
449 sub->cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
450 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
451 sub->cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
452 sub->cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
453 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
454 xtrace(SUBCHNL,
455 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
456 sub->cdsc_absaddr.msf.minute, sub->cdsc_absaddr.msf.second,
457 sub->cdsc_absaddr.msf.frame, sub->cdsc_reladdr.msf.minute,
458 sub->cdsc_reladdr.msf.second, sub->cdsc_reladdr.msf.frame);
460 return 0;
463 case CDROMREADTOCHDR: {
464 struct cdrom_tochdr *toc=(struct cdrom_tochdr *) arg;
466 xtrace(IOCTL, "ioctl() READTOCHDR\n");
467 toc->cdth_trk0 = stuffp->di.n_first;
468 toc->cdth_trk1 = stuffp->di.n_last;
469 xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
470 stuffp->di.n_first, stuffp->di.n_last);
471 return 0;
474 case CDROMPAUSE: {
475 xtrace(IOCTL, "ioctl() PAUSE\n");
476 if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
477 if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
478 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
479 if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
480 return -EIO;
481 return 0;
484 case CDROMMULTISESSION: {
485 struct cdrom_multisession *ms=(struct cdrom_multisession *) arg;
486 xtrace(IOCTL, "ioctl() MULTISESSION\n");
487 /* Always return stuff in LBA, and let the Uniform cdrom driver
488 worry about what the user actually wants */
489 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
490 ms->xa_flag = !!stuffp->multi.multi;
491 xtrace(MS, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
492 ms->xa_flag, ms->addr.lba, stuffp->multi.msf_last.minute,
493 stuffp->multi.msf_last.second,stuffp->multi.msf_last.frame);
495 return 0;
498 case CDROMEJECT: {
499 xtrace(IOCTL, "ioctl() EJECT\n");
500 if (stuffp->users > 1) return -EBUSY;
501 return(mcdx_tray_move(cdi, 1));
504 case CDROMCLOSETRAY: {
505 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
506 return(mcdx_tray_move(cdi, 0));
509 case CDROMVOLCTRL: {
510 struct cdrom_volctrl *volctrl=(struct cdrom_volctrl *)arg;
511 xtrace(IOCTL, "ioctl() VOLCTRL\n");
513 #if 0 /* not tested! */
514 /* adjust for the weirdness of workman (md) */
515 /* can't test it (hs) */
516 volctrl.channel2 = volctrl.channel1;
517 volctrl.channel1 = volctrl.channel3 = 0x00;
518 #endif
519 return mcdx_setattentuator(stuffp, volctrl, 2);
522 default:
523 xwarn("ioctl(): unknown request 0x%04x\n", cmd);
524 return -EINVAL;
528 void do_mcdx_request(request_queue_t * q)
530 int dev;
531 struct s_drive_stuff *stuffp;
533 again:
535 if (QUEUE_EMPTY) {
536 xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
537 return;
540 if (CURRENT->rq_status == RQ_INACTIVE) {
541 xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n");
542 return;
545 INIT_REQUEST;
547 dev = MINOR(CURRENT->rq_dev);
548 stuffp = mcdx_stuffp[dev];
550 if ((dev < 0)
551 || (dev >= MCDX_NDRIVES)
552 || !stuffp
553 || (!stuffp->present)) {
554 xwarn("do_request(): bad device: %s\n",
555 kdevname(CURRENT->rq_dev));
556 xtrace(REQUEST, "end_request(0): bad device\n");
557 end_request(0); return;
560 if (stuffp->audio) {
561 xwarn("do_request() attempt to read from audio cd\n");
562 xtrace(REQUEST, "end_request(0): read from audio\n");
563 end_request(0); return;
566 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
567 CURRENT->sector, CURRENT->nr_sectors);
569 switch (CURRENT->cmd) {
570 case WRITE:
571 xwarn("do_request(): attempt to write to cd!!\n");
572 xtrace(REQUEST, "end_request(0): write\n");
573 end_request(0); return;
575 case READ:
576 stuffp->status = 0;
577 while (CURRENT->nr_sectors) {
578 int i;
580 i = mcdx_transfer(stuffp,
581 CURRENT->buffer,
582 CURRENT->sector,
583 CURRENT->nr_sectors);
585 if (i == -1) {
586 end_request(0);
587 goto again;
589 CURRENT->sector += i;
590 CURRENT->nr_sectors -= i;
591 CURRENT->buffer += (i * 512);
593 end_request(1);
594 goto again;
596 xtrace(REQUEST, "end_request(1)\n");
597 end_request(1);
598 break;
600 default:
601 panic(MCDX "do_request: unknown command.\n");
602 break;
605 goto again;
608 static int
609 mcdx_open(struct cdrom_device_info * cdi, int purpose)
611 struct s_drive_stuff *stuffp;
612 xtrace(OPENCLOSE, "open()\n");
613 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
614 if (!stuffp->present) return -ENXIO;
616 /* Make the modules looking used ... (thanx bjorn).
617 * But we shouldn't forget to decrement the module counter
618 * on error return */
619 MOD_INC_USE_COUNT;
621 /* this is only done to test if the drive talks with us */
622 if (-1 == mcdx_getstatus(stuffp, 1)) {
623 MOD_DEC_USE_COUNT;
624 return -EIO;
627 if (stuffp->xxx) {
629 xtrace(OPENCLOSE, "open() media changed\n");
630 stuffp->audiostatus = CDROM_AUDIO_INVALID;
631 stuffp->readcmd = 0;
632 xtrace(OPENCLOSE, "open() Request multisession info\n");
633 if (-1 == mcdx_requestmultidiskinfo( stuffp, &stuffp->multi, 6))
634 xinfo("No multidiskinfo\n");
635 } else {
636 /* multisession ? */
637 if (!stuffp->multi.multi)
638 stuffp->multi.msf_last.second = 2;
640 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
641 stuffp->multi.multi,
642 stuffp->multi.msf_last.minute,
643 stuffp->multi.msf_last.second,
644 stuffp->multi.msf_last.frame);
646 { ; } /* got multisession information */
647 /* request the disks table of contents (aka diskinfo) */
648 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
650 stuffp->lastsector = -1;
652 } else {
654 stuffp->lastsector = (CD_FRAMESIZE / 512)
655 * msf2log(&stuffp->di.msf_leadout) - 1;
657 xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
658 stuffp->di.n_first,
659 stuffp->di.msf_first.minute,
660 stuffp->di.msf_first.second,
661 stuffp->di.msf_first.frame,
662 msf2log(&stuffp->di.msf_first));
663 xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
664 stuffp->di.n_last,
665 stuffp->di.msf_leadout.minute,
666 stuffp->di.msf_leadout.second,
667 stuffp->di.msf_leadout.frame,
668 msf2log(&stuffp->di.msf_leadout));
671 if (stuffp->toc) {
672 xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc);
673 kfree(stuffp->toc);
675 stuffp->toc = NULL;
678 xtrace(OPENCLOSE, "open() init irq generation\n");
679 if (-1 == mcdx_config(stuffp, 1)) {
680 MOD_DEC_USE_COUNT;
681 return -EIO;
684 #if FALLBACK
685 /* Set the read speed */
686 xwarn("AAA %x AAA\n", stuffp->readcmd);
687 if (stuffp->readerrs) stuffp->readcmd = READ1X;
688 else stuffp->readcmd =
689 stuffp->present | SINGLE ? READ1X : READ2X;
690 xwarn("XXX %x XXX\n", stuffp->readcmd);
691 #else
692 stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X;
693 #endif
695 /* try to get the first sector, iff any ... */
696 if (stuffp->lastsector >= 0) {
697 char buf[512];
698 int ans;
699 int tries;
701 stuffp->xa = 0;
702 stuffp->audio = 0;
704 for (tries = 6; tries; tries--) {
706 stuffp->introk = 1;
708 xtrace(OPENCLOSE, "open() try as %s\n",
709 stuffp->xa ? "XA" : "normal");
710 /* set data mode */
711 if (-1 == (ans = mcdx_setdatamode(stuffp,
712 stuffp->xa ? MODE2 : MODE1, 1))) {
713 /* MOD_DEC_USE_COUNT, return -EIO; */
714 stuffp->xa = 0;
715 break;
718 if ((stuffp->audio = e_audio(ans))) break;
720 while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1)))
723 if (ans == 1) break;
724 stuffp->xa = !stuffp->xa;
727 /* xa disks will be read in raw mode, others not */
728 if (-1 == mcdx_setdrivemode(stuffp,
729 stuffp->xa ? RAW : COOKED, 1)) {
730 MOD_DEC_USE_COUNT;
731 return -EIO;
733 if (stuffp->audio) {
734 xinfo("open() audio disk found\n");
735 } else if (stuffp->lastsector >= 0) {
736 xinfo("open() %s%s disk found\n",
737 stuffp->xa ? "XA / " : "",
738 stuffp->multi.multi ? "Multi Session" : "Single Session");
741 stuffp->xxx = 0;
742 stuffp->users++;
743 return 0;
746 static void mcdx_close(struct cdrom_device_info * cdi)
748 struct s_drive_stuff *stuffp;
750 xtrace(OPENCLOSE, "close()\n");
752 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
754 --stuffp->users;
756 MOD_DEC_USE_COUNT;
759 static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr)
760 /* Return: 1 if media changed since last call to this function
761 0 otherwise */
763 struct s_drive_stuff *stuffp;
765 xinfo("mcdx_media_changed called for device %s\n",
766 kdevname(cdi->dev));
768 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
769 mcdx_getstatus(stuffp, 1);
771 if (stuffp->yyy == 0) return 0;
773 stuffp->yyy = 0;
774 return 1;
777 #ifndef MODULE
778 static int __init mcdx_setup(char *str)
780 int pi[4];
781 (void)get_options(str, ARRAY_SIZE(pi), pi);
783 if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
784 if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
785 return 1;
788 __setup("mcdx=", mcdx_setup);
790 #endif
792 /* DIRTY PART ******************************************************/
794 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
795 /* This routine is used for sleeping.
796 * A jifs value <0 means NO sleeping,
797 * =0 means minimal sleeping (let the kernel
798 * run for other processes)
799 * >0 means at least sleep for that amount.
800 * May be we could use a simple count loop w/ jumps to itself, but
801 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
803 if (jifs < 0) return;
805 xtrace(SLEEP, "*** delay: sleepq\n");
806 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
807 xtrace(SLEEP, "delay awoken\n");
808 if (signal_pending(current)) {
809 xtrace(SLEEP, "got signal\n");
813 static void
814 mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
816 struct s_drive_stuff *stuffp;
817 unsigned char b;
819 stuffp = mcdx_irq_map[irq];
821 if (stuffp == NULL ) {
822 xwarn("mcdx: no device for intr %d\n", irq);
823 return;
826 #ifdef AK2
827 if ( !stuffp->busy && stuffp->pending )
828 stuffp->int_err = 1;
830 #endif /* AK2 */
831 /* get the interrupt status */
832 b = inb((unsigned int) stuffp->rreg_status);
833 stuffp->introk = ~b & MCDX_RBIT_DTEN;
835 /* NOTE: We only should get interrupts if the data we
836 * requested are ready to transfer.
837 * But the drive seems to generate ``asynchronous'' interrupts
838 * on several error conditions too. (Despite the err int enable
839 * setting during initialisation) */
841 /* if not ok, read the next byte as the drives status */
842 if (!stuffp->introk) {
843 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
844 if (~b & MCDX_RBIT_STEN) {
845 xinfo( "intr() irq %d status 0x%02x\n",
846 irq, inb((unsigned int) stuffp->rreg_data));
847 } else {
848 xinfo( "intr() irq %d ambiguous hw status\n", irq);
850 } else {
851 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
854 stuffp->busy = 0;
855 wake_up_interruptible(&stuffp->busyq);
859 static int
860 mcdx_talk (
861 struct s_drive_stuff *stuffp,
862 const unsigned char *cmd, size_t cmdlen,
863 void *buffer, size_t size,
864 unsigned int timeout, int tries)
865 /* Send a command to the drive, wait for the result.
866 * returns -1 on timeout, drive status otherwise
867 * If buffer is not zero, the result (length size) is stored there.
868 * If buffer is zero the size should be the number of bytes to read
869 * from the drive. These bytes are discarded.
872 int st;
873 char c;
874 int discard;
876 /* Somebody wants the data read? */
877 if ((discard = (buffer == NULL))) buffer = &c;
879 while (stuffp->lock) {
880 xtrace(SLEEP, "*** talk: lockq\n");
881 interruptible_sleep_on(&stuffp->lockq);
882 xtrace(SLEEP, "talk: awoken\n");
885 stuffp->lock = 1;
887 /* An operation other then reading data destroys the
888 * data already requested and remembered in stuffp->request, ... */
889 stuffp->valid = 0;
891 #if MCDX_DEBUG & TALK
893 unsigned char i;
894 xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x",
895 tries, timeout, size, (unsigned char) cmd[0]);
896 for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]);
897 xtrace(TALK, "\n");
899 #endif
901 /* give up if all tries are done (bad) or if the status
902 * st != -1 (good) */
903 for (st = -1; st == -1 && tries; tries--) {
905 char *bp = (char*) buffer;
906 size_t sz = size;
908 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
909 xtrace(TALK, "talk() command sent\n");
911 /* get the status byte */
912 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
913 xinfo("talk() %02x timed out (status), %d tr%s left\n",
914 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
915 continue;
917 st = *bp;
918 sz--;
919 if (!discard) bp++;
921 xtrace(TALK, "talk() got status 0x%02x\n", st);
923 /* command error? */
924 if (e_cmderr(st)) {
925 xwarn("command error cmd = %02x %s \n",
926 cmd[0], cmdlen > 1 ? "..." : "");
927 st = -1;
928 continue;
931 /* audio status? */
932 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
933 stuffp->audiostatus =
934 e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
935 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
936 && e_audiobusy(st) == 0)
937 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
939 /* media change? */
940 if (e_changed(st)) {
941 xinfo("talk() media changed\n");
942 stuffp->xxx = stuffp->yyy = 1;
945 /* now actually get the data */
946 while (sz--) {
947 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
948 xinfo("talk() %02x timed out (data), %d tr%s left\n",
949 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
950 st = -1; break;
952 if (!discard) bp++;
953 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
957 #if !MCDX_QUIET
958 if (!tries && st == -1) xinfo("talk() giving up\n");
959 #endif
961 stuffp->lock = 0;
962 wake_up_interruptible(&stuffp->lockq);
964 xtrace(TALK, "talk() done with 0x%02x\n", st);
965 return st;
968 /* MODULE STUFF ***********************************************************/
970 EXPORT_NO_SYMBOLS;
972 int __mcdx_init(void)
974 int i;
975 int drives = 0;
977 mcdx_init();
978 for (i = 0; i < MCDX_NDRIVES; i++) {
979 if (mcdx_stuffp[i]) {
980 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
981 i, mcdx_stuffp[i]);
982 drives++;
986 if (!drives)
987 return -EIO;
989 return 0;
992 void __exit mcdx_exit(void)
994 int i;
996 xinfo("cleanup_module called\n");
998 for (i = 0; i < MCDX_NDRIVES; i++) {
999 struct s_drive_stuff *stuffp;
1000 if (unregister_cdrom(&mcdx_info)) {
1001 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1002 return;
1004 stuffp = mcdx_stuffp[i];
1005 if (!stuffp) continue;
1006 release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
1007 free_irq(stuffp->irq, NULL);
1008 if (stuffp->toc) {
1009 xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc);
1010 kfree(stuffp->toc);
1012 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp);
1013 mcdx_stuffp[i] = NULL;
1014 kfree(stuffp);
1017 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1018 xwarn("cleanup() unregister_blkdev() failed\n");
1020 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1021 #if !MCDX_QUIET
1022 else xinfo("cleanup() succeeded\n");
1023 #endif
1026 #ifdef MODULE
1027 module_init(__mcdx_init);
1028 #endif
1029 module_exit(mcdx_exit);
1032 /* Support functions ************************************************/
1034 int __init mcdx_init_drive(int drive)
1036 struct s_version version;
1037 struct s_drive_stuff* stuffp;
1038 int size = sizeof(*stuffp);
1039 char msg[80];
1041 mcdx_blocksizes[drive] = 0;
1043 xtrace(INIT, "init() try drive %d\n", drive);
1045 xtrace(INIT, "kmalloc space for stuffpt's\n");
1046 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1047 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1048 xwarn("init() malloc failed\n");
1049 return 1;
1052 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1053 sizeof(*stuffp), stuffp);
1055 /* set default values */
1056 memset(stuffp, 0, sizeof(*stuffp));
1058 stuffp->present = 0; /* this should be 0 already */
1059 stuffp->toc = NULL; /* this should be NULL already */
1061 /* setup our irq and i/o addresses */
1062 stuffp->irq = irq(mcdx_drive_map[drive]);
1063 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1064 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1065 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1066 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1068 init_waitqueue_head(&stuffp->busyq);
1069 init_waitqueue_head(&stuffp->lockq);
1070 init_waitqueue_head(&stuffp->sleepq);
1072 /* check if i/o addresses are available */
1073 if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1074 xwarn("0x%3p,%d: Init failed. "
1075 "I/O ports (0x%3p..0x%3p) already in use.\n",
1076 stuffp->wreg_data, stuffp->irq,
1077 stuffp->wreg_data,
1078 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1079 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1080 kfree(stuffp);
1081 xtrace(INIT, "init() continue at next drive\n");
1082 return 0; /* next drive */
1085 xtrace(INIT, "init() i/o port is available at 0x%3p\n",
1086 stuffp->wreg_data);
1087 xtrace(INIT, "init() hardware reset\n");
1088 mcdx_reset(stuffp, HARD, 1);
1090 xtrace(INIT, "init() get version\n");
1091 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1092 /* failed, next drive */
1093 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1094 MCDX,
1095 stuffp->wreg_data, stuffp->irq);
1096 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1097 kfree(stuffp);
1098 xtrace(INIT, "init() continue at next drive\n");
1099 return 0;
1102 switch (version.code) {
1103 case 'D':
1104 stuffp->readcmd = READ2X;
1105 stuffp->present = DOUBLE | DOOR | MULTI;
1106 break;
1107 case 'F':
1108 stuffp->readcmd = READ1X;
1109 stuffp->present = SINGLE | DOOR | MULTI;
1110 break;
1111 case 'M':
1112 stuffp->readcmd = READ1X;
1113 stuffp->present = SINGLE;
1114 break;
1115 default:
1116 stuffp->present = 0; break;
1119 stuffp->playcmd = READ1X;
1121 if (!stuffp->present) {
1122 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1123 MCDX, stuffp->wreg_data, stuffp->irq);
1124 kfree(stuffp);
1125 return 0; /* next drive */
1128 xtrace(INIT, "init() register blkdev\n");
1129 if (devfs_register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) {
1130 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1131 MCDX,
1132 stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1133 kfree(stuffp);
1134 return 1;
1137 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1138 read_ahead[MAJOR_NR] = READ_AHEAD;
1139 blksize_size[MAJOR_NR] = mcdx_blocksizes;
1141 xtrace(INIT, "init() subscribe irq and i/o\n");
1142 mcdx_irq_map[stuffp->irq] = stuffp;
1143 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1144 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1145 MCDX,
1146 stuffp->wreg_data, stuffp->irq, stuffp->irq);
1147 stuffp->irq = 0;
1148 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1149 kfree(stuffp);
1150 return 0;
1152 request_region((unsigned int) stuffp->wreg_data,
1153 MCDX_IO_SIZE,
1154 "mcdx");
1156 xtrace(INIT, "init() get garbage\n");
1158 int i;
1159 mcdx_delay(stuffp, HZ/2);
1160 for (i = 100; i; i--)
1161 (void) inb((unsigned int) stuffp->rreg_status);
1165 #if WE_KNOW_WHY
1166 /* irq 11 -> channel register */
1167 outb(0x50, (unsigned int) stuffp->wreg_chn);
1168 #endif
1170 xtrace(INIT, "init() set non dma but irq mode\n");
1171 mcdx_config(stuffp, 1);
1173 stuffp->minor = drive;
1175 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1176 " (Firmware version %c %x)\n",
1177 stuffp->wreg_data, stuffp->irq, version.code,
1178 version.ver);
1179 mcdx_stuffp[drive] = stuffp;
1180 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1181 mcdx_info.dev = MKDEV(MAJOR_NR,0);
1182 if (register_cdrom(&mcdx_info) != 0) {
1183 printk("Cannot register Mitsumi CD-ROM!\n");
1184 release_region((unsigned long) stuffp->wreg_data,
1185 MCDX_IO_SIZE);
1186 free_irq(stuffp->irq, NULL);
1187 kfree(stuffp);
1188 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1189 xwarn("cleanup() unregister_blkdev() failed\n");
1190 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1191 return 2;
1193 printk(msg);
1194 return 0;
1197 int __init mcdx_init(void)
1199 int drive;
1200 #ifdef MODULE
1201 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1202 #else
1203 xwarn("Version 2.14(hs) \n");
1204 #endif
1206 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1208 /* zero the pointer array */
1209 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1210 mcdx_stuffp[drive] = NULL;
1212 /* do the initialisation */
1213 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1214 switch(mcdx_init_drive(drive)) {
1215 case 2:
1216 return -EIO;
1217 case 1:
1218 break;
1221 return 0;
1224 static int
1225 mcdx_transfer(struct s_drive_stuff *stuffp,
1226 char *p, int sector, int nr_sectors)
1227 /* This seems to do the actually transfer. But it does more. It
1228 keeps track of errors occurred and will (if possible) fall back
1229 to single speed on error.
1230 Return: -1 on timeout or other error
1231 else status byte (as in stuff->st) */
1233 int ans;
1235 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1236 return ans;
1237 #if FALLBACK
1238 if (-1 == ans) stuffp->readerrs++;
1239 else return ans;
1241 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1242 xwarn("XXX Already reading 1x -- no chance\n");
1243 return -1;
1246 xwarn("XXX Fallback to 1x\n");
1248 stuffp->readcmd = READ1X;
1249 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1250 #endif
1255 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1256 char *p, int sector, int nr_sectors)
1257 /* This does actually the transfer from the drive.
1258 Return: -1 on timeout or other error
1259 else status byte (as in stuff->st) */
1261 int border;
1262 int done = 0;
1263 long timeout;
1265 if (stuffp->audio) {
1266 xwarn("Attempt to read from audio CD.\n");
1267 return -1;
1270 if (!stuffp->readcmd) {
1271 xinfo("Can't transfer from missing disk.\n");
1272 return -1;
1275 while (stuffp->lock) {
1276 interruptible_sleep_on(&stuffp->lockq);
1279 if (stuffp->valid
1280 && (sector >= stuffp->pending)
1281 && (sector < stuffp->low_border)) {
1283 /* All (or at least a part of the sectors requested) seems
1284 * to be already requested, so we don't need to bother the
1285 * drive with new requests ...
1286 * Wait for the drive become idle, but first
1287 * check for possible occurred errors --- the drive
1288 * seems to report them asynchronously */
1291 border = stuffp->high_border < (border = sector + nr_sectors)
1292 ? stuffp->high_border : border;
1294 stuffp->lock = current->pid;
1296 do {
1298 while (stuffp->busy) {
1300 timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ);
1302 if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }
1303 else if (!timeout) { xtrace(XFER, "timeout\n"); }
1304 else if (signal_pending(current)) {
1305 xtrace(XFER, "signal\n");
1306 } else continue;
1308 stuffp->lock = 0;
1309 stuffp->busy = 0;
1310 stuffp->valid = 0;
1312 wake_up_interruptible(&stuffp->lockq);
1313 xtrace(XFER, "transfer() done (-1)\n");
1314 return -1;
1317 /* check if we need to set the busy flag (as we
1318 * expect an interrupt */
1319 stuffp->busy = (3 == (stuffp->pending & 3));
1321 /* Test if it's the first sector of a block,
1322 * there we have to skip some bytes as we read raw data */
1323 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1324 const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
1325 insb((unsigned int) stuffp->rreg_data, p, HEAD);
1328 /* now actually read the data */
1329 insb((unsigned int) stuffp->rreg_data, p, 512);
1331 /* test if it's the last sector of a block,
1332 * if so, we have to handle XA special */
1333 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1334 char dummy[CD_XA_TAIL];
1335 insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1338 if (stuffp->pending == sector) {
1339 p += 512;
1340 done++;
1341 sector++;
1343 } while (++(stuffp->pending) < border);
1345 stuffp->lock = 0;
1346 wake_up_interruptible(&stuffp->lockq);
1348 } else {
1350 /* The requested sector(s) is/are out of the
1351 * already requested range, so we have to bother the drive
1352 * with a new request. */
1354 static unsigned char cmd[] = {
1356 0, 0, 0,
1357 0, 0, 0
1360 cmd[0] = stuffp->readcmd;
1362 /* The numbers held in ->pending, ..., should be valid */
1363 stuffp->valid = 1;
1364 stuffp->pending = sector & ~3;
1366 /* do some sanity checks */
1367 if (stuffp->pending > stuffp->lastsector) {
1368 xwarn("transfer() sector %d from nirvana requested.\n",
1369 stuffp->pending);
1370 stuffp->status = MCDX_ST_EOM;
1371 stuffp->valid = 0;
1372 xtrace(XFER, "transfer() done (-1)\n");
1373 return -1;
1376 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1377 > stuffp->lastsector + 1) {
1378 xtrace(XFER, "cut low_border\n");
1379 stuffp->low_border = stuffp->lastsector + 1;
1381 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1382 > stuffp->lastsector + 1) {
1383 xtrace(XFER, "cut high_border\n");
1384 stuffp->high_border = stuffp->lastsector + 1;
1387 { /* Convert the sector to be requested to MSF format */
1388 struct cdrom_msf0 pending;
1389 log2msf(stuffp->pending / 4, &pending);
1390 cmd[1] = pending.minute;
1391 cmd[2] = pending.second;
1392 cmd[3] = pending.frame;
1395 cmd[6] = (unsigned char) ((stuffp->high_border - stuffp->pending) / 4);
1396 xtrace(XFER, "[%2d]\n", cmd[6]);
1398 stuffp->busy = 1;
1399 /* Now really issue the request command */
1400 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1403 #ifdef AK2
1404 if ( stuffp->int_err ) {
1405 stuffp->valid = 0;
1406 stuffp->int_err = 0;
1407 return -1;
1409 #endif /* AK2 */
1411 stuffp->low_border = (stuffp->low_border += done) < stuffp->high_border
1412 ? stuffp->low_border : stuffp->high_border;
1414 return done;
1418 /* Access to elements of the mcdx_drive_map members */
1420 static char* port(int *ip) { return (char*) ip[0]; }
1421 static int irq(int *ip) { return ip[1]; }
1423 /* Misc number converters */
1425 static unsigned int bcd2uint(unsigned char c)
1426 { return (c >> 4) * 10 + (c & 0x0f); }
1428 static unsigned int uint2bcd(unsigned int ival)
1429 { return ((ival / 10) << 4) | (ival % 10); }
1431 static void log2msf(unsigned int l, struct cdrom_msf0* pmsf)
1433 l += CD_MSF_OFFSET;
1434 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1435 pmsf->second = uint2bcd(l / 75);
1436 pmsf->frame = uint2bcd(l % 75);
1439 static unsigned int msf2log(const struct cdrom_msf0* pmsf)
1441 return bcd2uint(pmsf->frame)
1442 + bcd2uint(pmsf->second) * 75
1443 + bcd2uint(pmsf->minute) * 4500
1444 - CD_MSF_OFFSET;
1447 int mcdx_readtoc(struct s_drive_stuff* stuffp)
1448 /* Read the toc entries from the CD,
1449 * Return: -1 on failure, else 0 */
1452 if (stuffp->toc) {
1453 xtrace(READTOC, "ioctl() toc already read\n");
1454 return 0;
1457 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1458 stuffp->di.n_last - stuffp->di.n_first + 1);
1460 if (-1 == mcdx_hold(stuffp, 1)) return -1;
1462 xtrace(READTOC, "ioctl() tocmode\n");
1463 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
1465 /* all seems to be ok so far ... malloc */
1467 int size;
1468 size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
1470 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1471 stuffp->toc = kmalloc(size, GFP_KERNEL);
1472 if (!stuffp->toc) {
1473 xwarn("Cannot malloc %d bytes for toc\n", size);
1474 mcdx_setdrivemode(stuffp, DATA, 1);
1475 return -EIO;
1479 /* now read actually the index */
1481 int trk;
1482 int retries;
1484 for (trk = 0;
1485 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1486 trk++)
1487 stuffp->toc[trk].index = 0;
1489 for (retries = 300; retries; retries--) { /* why 300? */
1490 struct s_subqcode q;
1491 unsigned int idx;
1493 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1494 mcdx_setdrivemode(stuffp, DATA, 1);
1495 return -EIO;
1498 idx = bcd2uint(q.index);
1500 if ((idx > 0)
1501 && (idx <= stuffp->di.n_last)
1502 && (q.tno == 0)
1503 && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
1504 stuffp->toc[idx - stuffp->di.n_first] = q;
1505 xtrace(READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk);
1506 trk--;
1508 if (trk == 0) break;
1510 memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1],
1511 0, sizeof(stuffp->toc[0]));
1512 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
1513 = stuffp->di.msf_leadout;
1516 /* unset toc mode */
1517 xtrace(READTOC, "ioctl() undo toc mode\n");
1518 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1519 return -EIO;
1521 #if MCDX_DEBUG && READTOC
1522 { int trk;
1523 for (trk = 0;
1524 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1525 trk++)
1526 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1527 " %02x:%02x.%02x %02x:%02x.%02x\n",
1528 trk + stuffp->di.n_first,
1529 stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
1530 stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
1531 stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame);
1533 #endif
1535 return 0;
1538 static int
1539 mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
1541 unsigned char cmd[7] = {
1542 0, 0, 0, 0, 0, 0, 0
1545 if (!stuffp->readcmd) {
1546 xinfo("Can't play from missing disk.\n");
1547 return -1;
1550 cmd[0] = stuffp->playcmd;
1552 cmd[1] = msf->cdmsf_min0;
1553 cmd[2] = msf->cdmsf_sec0;
1554 cmd[3] = msf->cdmsf_frame0;
1555 cmd[4] = msf->cdmsf_min1;
1556 cmd[5] = msf->cdmsf_sec1;
1557 cmd[6] = msf->cdmsf_frame1;
1559 xtrace(PLAYMSF, "ioctl(): play %x "
1560 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1561 cmd[0], cmd[1], cmd[2], cmd[3],
1562 cmd[4], cmd[5], cmd[6]);
1564 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1566 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1567 xwarn("playmsf() timeout\n");
1568 return -1;
1571 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1572 return 0;
1575 static int
1576 mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
1578 struct s_subqcode* p;
1579 struct cdrom_msf msf;
1581 if (-1 == mcdx_readtoc(stuffp)) return -1;
1583 if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1584 else p = &stuffp->start;
1586 msf.cdmsf_min0 = p->dt.minute;
1587 msf.cdmsf_sec0 = p->dt.second;
1588 msf.cdmsf_frame0 = p->dt.frame;
1590 if (ti) {
1591 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1592 stuffp->stop = *p;
1593 } else p = &stuffp->stop;
1595 msf.cdmsf_min1 = p->dt.minute;
1596 msf.cdmsf_sec1 = p->dt.second;
1597 msf.cdmsf_frame1 = p->dt.frame;
1599 return mcdx_playmsf(stuffp, &msf);
1603 /* Drive functions ************************************************/
1605 static int
1606 mcdx_tray_move(struct cdrom_device_info * cdi, int position)
1608 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1610 if (!stuffp->present)
1611 return -ENXIO;
1612 if (!(stuffp->present & DOOR))
1613 return -ENOSYS;
1615 if (position) /* 1: eject */
1616 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1617 else /* 0: close */
1618 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1619 return 1;
1622 static int
1623 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1624 { return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
1626 static int
1627 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1628 { return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
1630 static int
1631 mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1632 struct s_subqcode *sub,
1633 int tries)
1635 char buf[11];
1636 int ans;
1638 if (-1 == (ans = mcdx_talk(
1639 stuffp, "\x20", 1, buf, sizeof(buf),
1640 2 * HZ, tries)))
1641 return -1;
1642 sub->control = buf[1];
1643 sub->tno = buf[2];
1644 sub->index = buf[3];
1645 sub->tt.minute = buf[4];
1646 sub->tt.second = buf[5];
1647 sub->tt.frame = buf[6];
1648 sub->dt.minute = buf[8];
1649 sub->dt.second = buf[9];
1650 sub->dt.frame = buf[10];
1652 return ans;
1655 static int
1656 mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
1658 char buf[5];
1659 int ans;
1661 if (stuffp->present & MULTI) {
1662 ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries);
1663 multi->multi = buf[1];
1664 multi->msf_last.minute = buf[2];
1665 multi->msf_last.second = buf[3];
1666 multi->msf_last.frame = buf[4];
1667 return ans;
1668 } else {
1669 multi->multi = 0;
1670 return 0;
1674 static int
1675 mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
1677 char buf[9];
1678 int ans;
1679 ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1680 if (ans == -1) {
1681 info->n_first = 0;
1682 info->n_last = 0;
1683 } else {
1684 info->n_first = bcd2uint(buf[1]);
1685 info->n_last = bcd2uint(buf[2]);
1686 info->msf_leadout.minute = buf[3];
1687 info->msf_leadout.second = buf[4];
1688 info->msf_leadout.frame = buf[5];
1689 info->msf_first.minute = buf[6];
1690 info->msf_first.second = buf[7];
1691 info->msf_first.frame = buf[8];
1693 return ans;
1696 static int
1697 mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
1699 char cmd[2];
1700 int ans;
1702 xtrace(HW, "setdrivemode() %d\n", mode);
1704 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1705 return -1;
1707 switch (mode) {
1708 case TOC: cmd[1] |= 0x04; break;
1709 case DATA: cmd[1] &= ~0x04; break;
1710 case RAW: cmd[1] |= 0x40; break;
1711 case COOKED: cmd[1] &= ~0x40; break;
1712 default: break;
1714 cmd[0] = 0x50;
1715 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1718 static int
1719 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
1721 unsigned char cmd[2] = { 0xa0 };
1722 xtrace(HW, "setdatamode() %d\n", mode);
1723 switch (mode) {
1724 case MODE0: cmd[1] = 0x00; break;
1725 case MODE1: cmd[1] = 0x01; break;
1726 case MODE2: cmd[1] = 0x02; break;
1727 default: return -EINVAL;
1729 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1732 static int
1733 mcdx_config(struct s_drive_stuff *stuffp, int tries)
1735 char cmd[4];
1737 xtrace(HW, "config()\n");
1739 cmd[0] = 0x90;
1741 cmd[1] = 0x10; /* irq enable */
1742 cmd[2] = 0x05; /* pre, err irq enable */
1744 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1745 return -1;
1747 cmd[1] = 0x02; /* dma select */
1748 cmd[2] = 0x00; /* no dma */
1750 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1753 static int
1754 mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
1756 char buf[3];
1757 int ans;
1759 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1760 1, buf, sizeof(buf), 2 * HZ, tries)))
1761 return ans;
1763 ver->code = buf[1];
1764 ver->ver = buf[2];
1766 return ans;
1769 static int
1770 mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1772 if (mode == HARD) {
1773 outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
1774 outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
1775 return 0;
1776 } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1779 static int mcdx_lockdoor(struct cdrom_device_info * cdi, int lock)
1781 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1782 char cmd[2] = { 0xfe };
1784 if (!(stuffp->present & DOOR))
1785 return -ENOSYS;
1786 if (stuffp->present & DOOR) {
1787 cmd[1] = lock ? 0x01 : 0x00;
1788 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1789 } else return 0;
1792 static int
1793 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1794 { return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
1796 static int
1797 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
1799 unsigned long timeout = to + jiffies;
1800 char c;
1802 if (!buf) buf = &c;
1804 while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1805 if (time_after(jiffies, timeout)) return -1;
1806 mcdx_delay(stuffp, delay);
1809 *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1811 return 0;
1814 static int
1815 mcdx_setattentuator(
1816 struct s_drive_stuff* stuffp,
1817 struct cdrom_volctrl* vol,
1818 int tries)
1820 char cmd[5];
1821 cmd[0] = 0xae;
1822 cmd[1] = vol->channel0;
1823 cmd[2] = 0;
1824 cmd[3] = vol->channel1;
1825 cmd[4] = 0;
1827 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1830 /* ex:set ts=4 sw=4 ai si: */