* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / cdrom / mcdx.c
blobfa3f363103565a159d82b88859345d1015d457b2
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?
50 #if RCS
51 static const char *mcdx_c_version
52 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
53 #endif
55 #include <linux/version.h>
56 #include <linux/module.h>
58 #include <linux/errno.h>
59 #include <linux/sched.h>
60 #include <linux/fs.h>
61 #include <linux/kernel.h>
62 #include <linux/cdrom.h>
63 #include <linux/ioport.h>
64 #include <linux/mm.h>
65 #include <linux/malloc.h>
66 #include <linux/init.h>
67 #include <asm/io.h>
68 #include <asm/uaccess.h>
70 #include <linux/major.h>
71 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
72 #include <linux/blk.h>
74 /* for compatible parameter passing with "insmod" */
75 #define mcdx_drive_map mcdx
76 #include "mcdx.h"
78 #ifndef HZ
79 #error HZ not defined
80 #endif
82 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
84 #if !MCDX_QUIET
85 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
86 #else
87 #define xinfo(fmt, args...) { ; }
88 #endif
90 #if MCDX_DEBUG
91 #define xtrace(lvl, fmt, args...) \
92 { if (lvl > 0) \
93 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
94 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
95 #else
96 #define xtrace(lvl, fmt, args...) { ; }
97 #define xdebug(fmt, args...) { ; }
98 #endif
100 /* CONSTANTS *******************************************************/
102 /* Following are the number of sectors we _request_ from the drive
103 every time an access outside the already requested range is done.
104 The _direct_ size is the number of sectors we're allowed to skip
105 directly (performing a read instead of requesting the new sector
106 needed */
107 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
108 const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
110 enum drivemodes { TOC, DATA, RAW, COOKED };
111 enum datamodes { MODE0, MODE1, MODE2 };
112 enum resetmodes { SOFT, HARD };
114 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
115 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
116 const int DOOR = 0x04; /* door locking capability */
117 const int MULTI = 0x08; /* multi session capability */
119 const unsigned char READ1X = 0xc0;
120 const unsigned char READ2X = 0xc1;
123 /* DECLARATIONS ****************************************************/
124 struct s_subqcode {
125 unsigned char control;
126 unsigned char tno;
127 unsigned char index;
128 struct cdrom_msf0 tt;
129 struct cdrom_msf0 dt;
132 struct s_diskinfo {
133 unsigned int n_first;
134 unsigned int n_last;
135 struct cdrom_msf0 msf_leadout;
136 struct cdrom_msf0 msf_first;
139 struct s_multi {
140 unsigned char multi;
141 struct cdrom_msf0 msf_last;
144 struct s_version {
145 unsigned char code;
146 unsigned char ver;
149 /* Per drive/controller stuff **************************************/
151 struct s_drive_stuff {
152 /* waitqueues */
153 wait_queue_head_t busyq;
154 wait_queue_head_t lockq;
155 wait_queue_head_t sleepq;
157 /* flags */
158 volatile int introk; /* status of last irq operation */
159 volatile int busy; /* drive performs an operation */
160 volatile int lock; /* exclusive usage */
162 /* cd infos */
163 struct s_diskinfo di;
164 struct s_multi multi;
165 struct s_subqcode* toc; /* first entry of the toc array */
166 struct s_subqcode start;
167 struct s_subqcode stop;
168 int xa; /* 1 if xa disk */
169 int audio; /* 1 if audio disk */
170 int audiostatus;
172 /* `buffer' control */
173 volatile int valid; /* pending, ..., values are valid */
174 volatile int pending; /* next sector to be read */
175 volatile int low_border; /* first sector not to be skipped direct */
176 volatile int high_border; /* first sector `out of area' */
177 #ifdef AK2
178 volatile int int_err;
179 #endif /* AK2 */
181 /* adds and odds */
182 void* wreg_data; /* w data */
183 void* wreg_reset; /* w hardware reset */
184 void* wreg_hcon; /* w hardware conf */
185 void* wreg_chn; /* w channel */
186 void* rreg_data; /* r data */
187 void* rreg_status; /* r status */
189 int irq; /* irq used by this drive */
190 int minor; /* minor number of this drive */
191 int present; /* drive present and its capabilities */
192 unsigned char readcmd; /* read cmd depends on single/double speed */
193 unsigned char playcmd; /* play should always be single speed */
194 unsigned int xxx; /* set if changed, reset while open */
195 unsigned int yyy; /* set if changed, reset by media_changed */
196 int users; /* keeps track of open/close */
197 int lastsector; /* last block accessible */
198 int status; /* last operation's error / status */
199 int readerrs; /* # of blocks read w/o error */
203 /* Prototypes ******************************************************/
205 /* The following prototypes are already declared elsewhere. They are
206 repeated here to show what's going on. And to sense, if they're
207 changed elsewhere. */
209 /* declared in blk.h */
210 int mcdx_init(void);
211 void do_mcdx_request(void);
213 /* already declared in init/main */
214 void mcdx_setup(char *, int *);
216 /* Indirect exported functions. These functions are exported by their
217 addresses, such as mcdx_open and mcdx_close in the
218 structure mcdx_dops. */
220 /* ??? exported by the mcdx_sigaction struct */
221 static void mcdx_intr(int, void *, struct pt_regs*);
223 /* exported by file_ops */
224 static int mcdx_open(struct cdrom_device_info * cdi, int purpose);
225 static void mcdx_close(struct cdrom_device_info * cdi);
226 static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr);
227 static int mcdx_tray_move(struct cdrom_device_info * cdi, int position);
228 static int mcdx_lockdoor(struct cdrom_device_info * cdi, int lock);
229 static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
230 void * arg);
232 /* misc internal support functions */
233 static void log2msf(unsigned int, struct cdrom_msf0*);
234 static unsigned int msf2log(const struct cdrom_msf0*);
235 static unsigned int uint2bcd(unsigned int);
236 static unsigned int bcd2uint(unsigned char);
237 static char *port(int*);
238 static int irq(int*);
239 static void mcdx_delay(struct s_drive_stuff*, long jifs);
240 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
241 static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
243 static int mcdx_config(struct s_drive_stuff*, int);
244 static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
245 static int mcdx_stop(struct s_drive_stuff*, int);
246 static int mcdx_hold(struct s_drive_stuff*, int);
247 static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
248 static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
249 static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
250 static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
251 static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
252 static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
253 static int mcdx_getstatus(struct s_drive_stuff*, int);
254 static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
255 static int mcdx_talk(struct s_drive_stuff*,
256 const unsigned char* cmd, size_t,
257 void *buffer, size_t size,
258 unsigned int timeout, int);
259 static int mcdx_readtoc(struct s_drive_stuff*);
260 static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
261 static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
262 static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
264 /* static variables ************************************************/
266 static int mcdx_blocksizes[MCDX_NDRIVES];
267 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
268 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
269 static struct s_drive_stuff* mcdx_irq_map[16] =
270 {0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0};
272 MODULE_PARM(mcdx, "1-4i");
274 static struct cdrom_device_ops mcdx_dops = {
275 mcdx_open, /* open */
276 mcdx_close, /* release */
277 NULL, /* drive status */
278 mcdx_media_changed, /* media changed */
279 mcdx_tray_move, /* tray move */
280 mcdx_lockdoor, /* lock door */
281 NULL, /* select speed */
282 NULL, /* select disc */
283 NULL, /* get last session */
284 NULL, /* get universal product code */
285 NULL, /* hard reset */
286 mcdx_audio_ioctl, /* audio ioctl */
287 NULL, /* device-specific ioctl */
288 CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO
289 | CDC_DRIVE_STATUS, /* capability */
290 0, /* number of minor devices */
293 static struct cdrom_device_info mcdx_info = {
294 &mcdx_dops, /* device operations */
295 NULL, /* link */
296 NULL, /* handle */
297 0, /* dev */
298 0, /* mask */
299 2, /* maximum speed */
300 1, /* number of discs */
301 0, /* options, not owned */
302 0, /* mc_flags, not owned */
303 0, /* use count, not owned */
304 "mcdx", /* name of the device type */
309 /* KERNEL INTERFACE FUNCTIONS **************************************/
312 static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
313 void * arg)
315 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
317 if (!stuffp->present) return -ENXIO;
319 if (stuffp->xxx)
321 if(-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1))
323 stuffp->lastsector = -1;
325 else
327 stuffp->lastsector = (CD_FRAMESIZE / 512)
328 * msf2log(&stuffp->di.msf_leadout) - 1;
331 if (stuffp->toc)
333 kfree(stuffp->toc);
334 stuffp->toc = NULL;
335 if (-1 == mcdx_readtoc(stuffp)) return -1;
338 stuffp->xxx=0;
341 switch (cmd) {
342 case CDROMSTART: {
343 xtrace(IOCTL, "ioctl() START\n");
344 /* Spin up the drive. Don't think we can do this.
345 * For now, ignore it.
347 return 0;
350 case CDROMSTOP: {
351 xtrace(IOCTL, "ioctl() STOP\n");
352 stuffp->audiostatus = CDROM_AUDIO_INVALID;
353 if (-1 == mcdx_stop(stuffp, 1))
354 return -EIO;
355 return 0;
358 case CDROMPLAYTRKIND: {
359 struct cdrom_ti *ti=(struct cdrom_ti *) arg;
361 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
362 if ((ti->cdti_trk0 < stuffp->di.n_first)
363 || (ti->cdti_trk0 > stuffp->di.n_last)
364 || (ti->cdti_trk1 < stuffp->di.n_first))
365 return -EINVAL;
366 if (ti->cdti_trk1 > stuffp->di.n_last)
367 ti->cdti_trk1 = stuffp->di.n_last;
368 xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti->cdti_trk0, ti->cdti_trk1);
369 return mcdx_playtrk(stuffp, ti);
372 case CDROMPLAYMSF: {
373 struct cdrom_msf *msf=(struct cdrom_msf *) arg;
375 xtrace(IOCTL, "ioctl() PLAYMSF\n");
377 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
378 && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
380 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
381 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
382 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
384 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
385 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
386 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
388 stuffp->stop.dt.minute = msf->cdmsf_min1;
389 stuffp->stop.dt.second = msf->cdmsf_sec1;
390 stuffp->stop.dt.frame = msf->cdmsf_frame1;
392 return mcdx_playmsf(stuffp, msf);
395 case CDROMRESUME: {
396 xtrace(IOCTL, "ioctl() RESUME\n");
397 return mcdx_playtrk(stuffp, NULL);
400 case CDROMREADTOCENTRY: {
401 struct cdrom_tocentry *entry=(struct cdrom_tocentry *) arg;
402 struct s_subqcode *tp = NULL;
403 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
405 if (-1 == mcdx_readtoc(stuffp)) return -1;
406 if (entry->cdte_track == CDROM_LEADOUT)
407 tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
408 else if (entry->cdte_track > stuffp->di.n_last
409 || entry->cdte_track < stuffp->di.n_first) return -EINVAL;
410 else tp = &stuffp->toc[entry->cdte_track - stuffp->di.n_first];
412 if (NULL == tp)
413 return -EIO;
414 entry->cdte_adr = tp->control;
415 entry->cdte_ctrl = tp->control >> 4;
416 /* Always return stuff in MSF, and let the Uniform cdrom driver
417 worry about what the user actually wants */
418 entry->cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
419 entry->cdte_addr.msf.second = bcd2uint(tp->dt.second);
420 entry->cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
421 return 0;
424 case CDROMSUBCHNL: {
425 struct cdrom_subchnl *sub= (struct cdrom_subchnl *)arg;
426 struct s_subqcode q;
428 xtrace(IOCTL, "ioctl() SUBCHNL\n");
430 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
431 return -EIO;
433 xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus);
434 sub->cdsc_audiostatus = stuffp->audiostatus;
435 sub->cdsc_adr = q.control;
436 sub->cdsc_ctrl = q.control >> 4;
437 sub->cdsc_trk = bcd2uint(q.tno);
438 sub->cdsc_ind = bcd2uint(q.index);
440 xtrace(SUBCHNL, "trk %d, ind %d\n",
441 sub->cdsc_trk, sub->cdsc_ind);
442 /* Always return stuff in MSF, and let the Uniform cdrom driver
443 worry about what the user actually wants */
444 sub->cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
445 sub->cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
446 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
447 sub->cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
448 sub->cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
449 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
450 xtrace(SUBCHNL,
451 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
452 sub->cdsc_absaddr.msf.minute, sub->cdsc_absaddr.msf.second,
453 sub->cdsc_absaddr.msf.frame, sub->cdsc_reladdr.msf.minute,
454 sub->cdsc_reladdr.msf.second, sub->cdsc_reladdr.msf.frame);
456 return 0;
459 case CDROMREADTOCHDR: {
460 struct cdrom_tochdr *toc=(struct cdrom_tochdr *) arg;
462 xtrace(IOCTL, "ioctl() READTOCHDR\n");
463 toc->cdth_trk0 = stuffp->di.n_first;
464 toc->cdth_trk1 = stuffp->di.n_last;
465 xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
466 stuffp->di.n_first, stuffp->di.n_last);
467 return 0;
470 case CDROMPAUSE: {
471 xtrace(IOCTL, "ioctl() PAUSE\n");
472 if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
473 if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
474 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
475 if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
476 return -EIO;
477 return 0;
480 case CDROMMULTISESSION: {
481 struct cdrom_multisession *ms=(struct cdrom_multisession *) arg;
482 xtrace(IOCTL, "ioctl() MULTISESSION\n");
483 /* Always return stuff in LBA, and let the Uniform cdrom driver
484 worry about what the user actually wants */
485 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
486 ms->xa_flag = !!stuffp->multi.multi;
487 xtrace(MS, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
488 ms->xa_flag, ms->addr.lba, stuffp->multi.msf_last.minute,
489 stuffp->multi.msf_last.second,stuffp->multi.msf_last.frame);
491 return 0;
494 case CDROMEJECT: {
495 xtrace(IOCTL, "ioctl() EJECT\n");
496 if (stuffp->users > 1) return -EBUSY;
497 return(mcdx_tray_move(cdi, 1));
500 case CDROMCLOSETRAY: {
501 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
502 return(mcdx_tray_move(cdi, 0));
505 case CDROMVOLCTRL: {
506 struct cdrom_volctrl *volctrl=(struct cdrom_volctrl *)arg;
507 xtrace(IOCTL, "ioctl() VOLCTRL\n");
509 #if 0 /* not tested! */
510 /* adjust for the weirdness of workman (md) */
511 /* can't test it (hs) */
512 volctrl.channel2 = volctrl.channel1;
513 volctrl.channel1 = volctrl.channel3 = 0x00;
514 #endif
515 return mcdx_setattentuator(stuffp, volctrl, 2);
518 default:
519 xwarn("ioctl(): unknown request 0x%04x\n", cmd);
520 return -EINVAL;
524 void do_mcdx_request()
526 int dev;
527 struct s_drive_stuff *stuffp;
529 again:
531 if (CURRENT == NULL) {
532 xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
533 return;
536 if (CURRENT->rq_status == RQ_INACTIVE) {
537 xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n");
538 return;
541 INIT_REQUEST;
543 dev = MINOR(CURRENT->rq_dev);
544 stuffp = mcdx_stuffp[dev];
546 if ((dev < 0)
547 || (dev >= MCDX_NDRIVES)
548 || !stuffp
549 || (!stuffp->present)) {
550 xwarn("do_request(): bad device: %s\n",
551 kdevname(CURRENT->rq_dev));
552 xtrace(REQUEST, "end_request(0): bad device\n");
553 end_request(0); return;
556 if (stuffp->audio) {
557 xwarn("do_request() attempt to read from audio cd\n");
558 xtrace(REQUEST, "end_request(0): read from audio\n");
559 end_request(0); return;
562 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
563 CURRENT->sector, CURRENT->nr_sectors);
565 switch (CURRENT->cmd) {
566 case WRITE:
567 xwarn("do_request(): attempt to write to cd!!\n");
568 xtrace(REQUEST, "end_request(0): write\n");
569 end_request(0); return;
571 case READ:
572 stuffp->status = 0;
573 while (CURRENT->nr_sectors) {
574 int i;
576 i = mcdx_transfer(stuffp,
577 CURRENT->buffer,
578 CURRENT->sector,
579 CURRENT->nr_sectors);
581 if (i == -1) {
582 end_request(0);
583 goto again;
585 CURRENT->sector += i;
586 CURRENT->nr_sectors -= i;
587 CURRENT->buffer += (i * 512);
589 end_request(1);
590 goto again;
592 xtrace(REQUEST, "end_request(1)\n");
593 end_request(1);
594 break;
596 default:
597 panic(MCDX "do_request: unknown command.\n");
598 break;
601 goto again;
604 static int
605 mcdx_open(struct cdrom_device_info * cdi, int purpose)
607 struct s_drive_stuff *stuffp;
608 xtrace(OPENCLOSE, "open()\n");
609 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
610 if (!stuffp->present) return -ENXIO;
612 /* Make the modules looking used ... (thanx bjorn).
613 * But we shouldn't forget to decrement the module counter
614 * on error return */
615 MOD_INC_USE_COUNT;
617 /* this is only done to test if the drive talks with us */
618 if (-1 == mcdx_getstatus(stuffp, 1)) {
619 MOD_DEC_USE_COUNT;
620 return -EIO;
623 if (stuffp->xxx) {
625 xtrace(OPENCLOSE, "open() media changed\n");
626 stuffp->audiostatus = CDROM_AUDIO_INVALID;
627 stuffp->readcmd = 0;
628 xtrace(OPENCLOSE, "open() Request multisession info\n");
629 if (-1 == mcdx_requestmultidiskinfo( stuffp, &stuffp->multi, 6))
630 xinfo("No multidiskinfo\n");
631 } else {
632 /* multisession ? */
633 if (!stuffp->multi.multi)
634 stuffp->multi.msf_last.second = 2;
636 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
637 stuffp->multi.multi,
638 stuffp->multi.msf_last.minute,
639 stuffp->multi.msf_last.second,
640 stuffp->multi.msf_last.frame);
642 { ; } /* got multisession information */
643 /* request the disks table of contents (aka diskinfo) */
644 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
646 stuffp->lastsector = -1;
648 } else {
650 stuffp->lastsector = (CD_FRAMESIZE / 512)
651 * msf2log(&stuffp->di.msf_leadout) - 1;
653 xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
654 stuffp->di.n_first,
655 stuffp->di.msf_first.minute,
656 stuffp->di.msf_first.second,
657 stuffp->di.msf_first.frame,
658 msf2log(&stuffp->di.msf_first));
659 xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
660 stuffp->di.n_last,
661 stuffp->di.msf_leadout.minute,
662 stuffp->di.msf_leadout.second,
663 stuffp->di.msf_leadout.frame,
664 msf2log(&stuffp->di.msf_leadout));
667 if (stuffp->toc) {
668 xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc);
669 kfree(stuffp->toc);
671 stuffp->toc = NULL;
674 xtrace(OPENCLOSE, "open() init irq generation\n");
675 if (-1 == mcdx_config(stuffp, 1)) {
676 MOD_DEC_USE_COUNT;
677 return -EIO;
680 #if FALLBACK
681 /* Set the read speed */
682 xwarn("AAA %x AAA\n", stuffp->readcmd);
683 if (stuffp->readerrs) stuffp->readcmd = READ1X;
684 else stuffp->readcmd =
685 stuffp->present | SINGLE ? READ1X : READ2X;
686 xwarn("XXX %x XXX\n", stuffp->readcmd);
687 #else
688 stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X;
689 #endif
691 /* try to get the first sector, iff any ... */
692 if (stuffp->lastsector >= 0) {
693 char buf[512];
694 int ans;
695 int tries;
697 stuffp->xa = 0;
698 stuffp->audio = 0;
700 for (tries = 6; tries; tries--) {
702 stuffp->introk = 1;
704 xtrace(OPENCLOSE, "open() try as %s\n",
705 stuffp->xa ? "XA" : "normal");
706 /* set data mode */
707 if (-1 == (ans = mcdx_setdatamode(stuffp,
708 stuffp->xa ? MODE2 : MODE1, 1))) {
709 /* MOD_DEC_USE_COUNT, return -EIO; */
710 stuffp->xa = 0;
711 break;
714 if ((stuffp->audio = e_audio(ans))) break;
716 while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1)))
719 if (ans == 1) break;
720 stuffp->xa = !stuffp->xa;
723 /* xa disks will be read in raw mode, others not */
724 if (-1 == mcdx_setdrivemode(stuffp,
725 stuffp->xa ? RAW : COOKED, 1)) {
726 MOD_DEC_USE_COUNT;
727 return -EIO;
729 if (stuffp->audio) {
730 xinfo("open() audio disk found\n");
731 } else if (stuffp->lastsector >= 0) {
732 xinfo("open() %s%s disk found\n",
733 stuffp->xa ? "XA / " : "",
734 stuffp->multi.multi ? "Multi Session" : "Single Session");
737 stuffp->xxx = 0;
738 stuffp->users++;
739 return 0;
742 static void mcdx_close(struct cdrom_device_info * cdi)
744 struct s_drive_stuff *stuffp;
746 xtrace(OPENCLOSE, "close()\n");
748 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
750 --stuffp->users;
752 MOD_DEC_USE_COUNT;
755 static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr)
756 /* Return: 1 if media changed since last call to this function
757 0 otherwise */
759 struct s_drive_stuff *stuffp;
761 xinfo("mcdx_media_changed called for device %s\n",
762 kdevname(cdi->dev));
764 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
765 mcdx_getstatus(stuffp, 1);
767 if (stuffp->yyy == 0) return 0;
769 stuffp->yyy = 0;
770 return 1;
773 void __init mcdx_setup(char *str, int *pi)
775 if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
776 if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
779 /* DIRTY PART ******************************************************/
781 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
782 /* This routine is used for sleeping.
783 * A jifs value <0 means NO sleeping,
784 * =0 means minimal sleeping (let the kernel
785 * run for other processes)
786 * >0 means at least sleep for that amount.
787 * May be we could use a simple count loop w/ jumps to itself, but
788 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
790 if (jifs < 0) return;
792 xtrace(SLEEP, "*** delay: sleepq\n");
793 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
794 xtrace(SLEEP, "delay awoken\n");
795 if (signal_pending(current)) {
796 xtrace(SLEEP, "got signal\n");
800 static void
801 mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
803 struct s_drive_stuff *stuffp;
804 unsigned char b;
806 stuffp = mcdx_irq_map[irq];
808 if (stuffp == NULL ) {
809 xwarn("mcdx: no device for intr %d\n", irq);
810 return;
813 #ifdef AK2
814 if ( !stuffp->busy && stuffp->pending )
815 stuffp->int_err = 1;
817 #endif /* AK2 */
818 /* get the interrupt status */
819 b = inb((unsigned int) stuffp->rreg_status);
820 stuffp->introk = ~b & MCDX_RBIT_DTEN;
822 /* NOTE: We only should get interrupts if the data we
823 * requested are ready to transfer.
824 * But the drive seems to generate ``asynchronous'' interrupts
825 * on several error conditions too. (Despite the err int enable
826 * setting during initialisation) */
828 /* if not ok, read the next byte as the drives status */
829 if (!stuffp->introk) {
830 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
831 if (~b & MCDX_RBIT_STEN) {
832 xinfo( "intr() irq %d status 0x%02x\n",
833 irq, inb((unsigned int) stuffp->rreg_data));
834 } else {
835 xinfo( "intr() irq %d ambiguous hw status\n", irq);
837 } else {
838 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
841 stuffp->busy = 0;
842 wake_up_interruptible(&stuffp->busyq);
846 static int
847 mcdx_talk (
848 struct s_drive_stuff *stuffp,
849 const unsigned char *cmd, size_t cmdlen,
850 void *buffer, size_t size,
851 unsigned int timeout, int tries)
852 /* Send a command to the drive, wait for the result.
853 * returns -1 on timeout, drive status otherwise
854 * If buffer is not zero, the result (length size) is stored there.
855 * If buffer is zero the size should be the number of bytes to read
856 * from the drive. These bytes are discarded.
859 int st;
860 char c;
861 int discard;
863 /* Somebody wants the data read? */
864 if ((discard = (buffer == NULL))) buffer = &c;
866 while (stuffp->lock) {
867 xtrace(SLEEP, "*** talk: lockq\n");
868 interruptible_sleep_on(&stuffp->lockq);
869 xtrace(SLEEP, "talk: awoken\n");
872 stuffp->lock = 1;
874 /* An operation other then reading data destroys the
875 * data already requested and remembered in stuffp->request, ... */
876 stuffp->valid = 0;
878 #if MCDX_DEBUG & TALK
880 unsigned char i;
881 xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x",
882 tries, timeout, size, (unsigned char) cmd[0]);
883 for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]);
884 xtrace(TALK, "\n");
886 #endif
888 /* give up if all tries are done (bad) or if the status
889 * st != -1 (good) */
890 for (st = -1; st == -1 && tries; tries--) {
892 char *bp = (char*) buffer;
893 size_t sz = size;
895 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
896 xtrace(TALK, "talk() command sent\n");
898 /* get the status byte */
899 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
900 xinfo("talk() %02x timed out (status), %d tr%s left\n",
901 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
902 continue;
904 st = *bp;
905 sz--;
906 if (!discard) bp++;
908 xtrace(TALK, "talk() got status 0x%02x\n", st);
910 /* command error? */
911 if (e_cmderr(st)) {
912 xwarn("command error cmd = %02x %s \n",
913 cmd[0], cmdlen > 1 ? "..." : "");
914 st = -1;
915 continue;
918 /* audio status? */
919 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
920 stuffp->audiostatus =
921 e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
922 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
923 && e_audiobusy(st) == 0)
924 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
926 /* media change? */
927 if (e_changed(st)) {
928 xinfo("talk() media changed\n");
929 stuffp->xxx = stuffp->yyy = 1;
932 /* now actually get the data */
933 while (sz--) {
934 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
935 xinfo("talk() %02x timed out (data), %d tr%s left\n",
936 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
937 st = -1; break;
939 if (!discard) bp++;
940 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
944 #if !MCDX_QUIET
945 if (!tries && st == -1) xinfo("talk() giving up\n");
946 #endif
948 stuffp->lock = 0;
949 wake_up_interruptible(&stuffp->lockq);
951 xtrace(TALK, "talk() done with 0x%02x\n", st);
952 return st;
955 /* MODULE STUFF ***********************************************************/
956 #ifdef MODULE
957 EXPORT_NO_SYMBOLS;
959 int init_module(void)
961 int i;
962 int drives = 0;
964 mcdx_init();
965 for (i = 0; i < MCDX_NDRIVES; i++) {
966 if (mcdx_stuffp[i]) {
967 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
968 i, mcdx_stuffp[i]);
969 drives++;
973 if (!drives)
974 return -EIO;
976 return 0;
979 void cleanup_module(void)
981 int i;
983 xinfo("cleanup_module called\n");
985 for (i = 0; i < MCDX_NDRIVES; i++) {
986 struct s_drive_stuff *stuffp;
987 if (unregister_cdrom(&mcdx_info)) {
988 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
989 return;
991 stuffp = mcdx_stuffp[i];
992 if (!stuffp) continue;
993 release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
994 free_irq(stuffp->irq, NULL);
995 if (stuffp->toc) {
996 xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc);
997 kfree(stuffp->toc);
999 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp);
1000 mcdx_stuffp[i] = NULL;
1001 kfree(stuffp);
1004 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1005 xwarn("cleanup() unregister_blkdev() failed\n");
1007 #if !MCDX_QUIET
1008 else xinfo("cleanup() succeeded\n");
1009 #endif
1012 #endif MODULE
1014 /* Support functions ************************************************/
1016 int __init mcdx_init_drive(int drive)
1018 struct s_version version;
1019 struct s_drive_stuff* stuffp;
1020 int size = sizeof(*stuffp);
1021 char msg[80];
1023 mcdx_blocksizes[drive] = 0;
1025 xtrace(INIT, "init() try drive %d\n", drive);
1027 xtrace(INIT, "kmalloc space for stuffpt's\n");
1028 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1029 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1030 xwarn("init() malloc failed\n");
1031 return 1;
1034 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1035 sizeof(*stuffp), stuffp);
1037 /* set default values */
1038 memset(stuffp, 0, sizeof(*stuffp));
1040 stuffp->present = 0; /* this should be 0 already */
1041 stuffp->toc = NULL; /* this should be NULL already */
1043 /* setup our irq and i/o addresses */
1044 stuffp->irq = irq(mcdx_drive_map[drive]);
1045 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1046 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1047 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1048 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1050 init_waitqueue_head(&stuffp->busyq);
1051 init_waitqueue_head(&stuffp->lockq);
1052 init_waitqueue_head(&stuffp->sleepq);
1054 /* check if i/o addresses are available */
1055 if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1056 xwarn("0x%3p,%d: Init failed. "
1057 "I/O ports (0x%3p..0x%3p) already in use.\n",
1058 stuffp->wreg_data, stuffp->irq,
1059 stuffp->wreg_data,
1060 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1061 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1062 kfree(stuffp);
1063 xtrace(INIT, "init() continue at next drive\n");
1064 return 0; /* next drive */
1067 xtrace(INIT, "init() i/o port is available at 0x%3p\n",
1068 stuffp->wreg_data);
1069 xtrace(INIT, "init() hardware reset\n");
1070 mcdx_reset(stuffp, HARD, 1);
1072 xtrace(INIT, "init() get version\n");
1073 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1074 /* failed, next drive */
1075 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1076 MCDX,
1077 stuffp->wreg_data, stuffp->irq);
1078 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1079 kfree(stuffp);
1080 xtrace(INIT, "init() continue at next drive\n");
1081 return 0;
1084 switch (version.code) {
1085 case 'D':
1086 stuffp->readcmd = READ2X;
1087 stuffp->present = DOUBLE | DOOR | MULTI;
1088 break;
1089 case 'F':
1090 stuffp->readcmd = READ1X;
1091 stuffp->present = SINGLE | DOOR | MULTI;
1092 break;
1093 case 'M':
1094 stuffp->readcmd = READ1X;
1095 stuffp->present = SINGLE;
1096 break;
1097 default:
1098 stuffp->present = 0; break;
1101 stuffp->playcmd = READ1X;
1103 if (!stuffp->present) {
1104 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1105 MCDX, stuffp->wreg_data, stuffp->irq);
1106 kfree(stuffp);
1107 return 0; /* next drive */
1110 xtrace(INIT, "init() register blkdev\n");
1111 if (register_blkdev(MAJOR_NR, "mcdx", &cdrom_fops) != 0) {
1112 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1113 MCDX,
1114 stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1115 kfree(stuffp);
1116 return 1;
1119 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1120 read_ahead[MAJOR_NR] = READ_AHEAD;
1121 blksize_size[MAJOR_NR] = mcdx_blocksizes;
1123 xtrace(INIT, "init() subscribe irq and i/o\n");
1124 mcdx_irq_map[stuffp->irq] = stuffp;
1125 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1126 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1127 MCDX,
1128 stuffp->wreg_data, stuffp->irq, stuffp->irq);
1129 stuffp->irq = 0;
1130 kfree(stuffp);
1131 return 0;
1133 request_region((unsigned int) stuffp->wreg_data,
1134 MCDX_IO_SIZE,
1135 "mcdx");
1137 xtrace(INIT, "init() get garbage\n");
1139 int i;
1140 mcdx_delay(stuffp, HZ/2);
1141 for (i = 100; i; i--)
1142 (void) inb((unsigned int) stuffp->rreg_status);
1146 #if WE_KNOW_WHY
1147 /* irq 11 -> channel register */
1148 outb(0x50, (unsigned int) stuffp->wreg_chn);
1149 #endif
1151 xtrace(INIT, "init() set non dma but irq mode\n");
1152 mcdx_config(stuffp, 1);
1154 stuffp->minor = drive;
1156 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1157 " (Firmware version %c %x)\n",
1158 stuffp->wreg_data, stuffp->irq, version.code,
1159 version.ver);
1160 mcdx_stuffp[drive] = stuffp;
1161 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1162 mcdx_info.dev = MKDEV(MAJOR_NR,0);
1163 if (register_cdrom(&mcdx_info) != 0) {
1164 printk("Cannot register Mitsumi CD-ROM!\n");
1165 release_region((unsigned long) stuffp->wreg_data,
1166 MCDX_IO_SIZE);
1167 free_irq(stuffp->irq, NULL);
1168 kfree(stuffp);
1169 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1170 xwarn("cleanup() unregister_blkdev() failed\n");
1171 return 2;
1173 printk(msg);
1174 return 0;
1177 int __init mcdx_init(void)
1179 int drive;
1180 #ifdef MODULE
1181 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1182 #else
1183 xwarn("Version 2.14(hs) \n");
1184 #endif
1186 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1188 /* zero the pointer array */
1189 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1190 mcdx_stuffp[drive] = NULL;
1192 /* do the initialisation */
1193 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1194 switch(mcdx_init_drive(drive)) {
1195 case 2:
1196 return -EIO;
1197 case 1:
1198 break;
1201 return 0;
1204 static int
1205 mcdx_transfer(struct s_drive_stuff *stuffp,
1206 char *p, int sector, int nr_sectors)
1207 /* This seems to do the actually transfer. But it does more. It
1208 keeps track of errors occurred and will (if possible) fall back
1209 to single speed on error.
1210 Return: -1 on timeout or other error
1211 else status byte (as in stuff->st) */
1213 int ans;
1215 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1216 return ans;
1217 #if FALLBACK
1218 if (-1 == ans) stuffp->readerrs++;
1219 else return ans;
1221 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1222 xwarn("XXX Already reading 1x -- no chance\n");
1223 return -1;
1226 xwarn("XXX Fallback to 1x\n");
1228 stuffp->readcmd = READ1X;
1229 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1230 #endif
1235 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1236 char *p, int sector, int nr_sectors)
1237 /* This does actually the transfer from the drive.
1238 Return: -1 on timeout or other error
1239 else status byte (as in stuff->st) */
1241 int border;
1242 int done = 0;
1243 long timeout;
1245 if (stuffp->audio) {
1246 xwarn("Attempt to read from audio CD.\n");
1247 return -1;
1250 if (!stuffp->readcmd) {
1251 xinfo("Can't transfer from missing disk.\n");
1252 return -1;
1255 while (stuffp->lock) {
1256 interruptible_sleep_on(&stuffp->lockq);
1259 if (stuffp->valid
1260 && (sector >= stuffp->pending)
1261 && (sector < stuffp->low_border)) {
1263 /* All (or at least a part of the sectors requested) seems
1264 * to be already requested, so we don't need to bother the
1265 * drive with new requests ...
1266 * Wait for the drive become idle, but first
1267 * check for possible occurred errors --- the drive
1268 * seems to report them asynchronously */
1271 border = stuffp->high_border < (border = sector + nr_sectors)
1272 ? stuffp->high_border : border;
1274 stuffp->lock = current->pid;
1276 do {
1278 while (stuffp->busy) {
1280 timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ);
1282 if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }
1283 else if (!timeout) { xtrace(XFER, "timeout\n"); }
1284 else if (signal_pending(current)) {
1285 xtrace(XFER, "signal\n");
1286 } else continue;
1288 stuffp->lock = 0;
1289 stuffp->busy = 0;
1290 stuffp->valid = 0;
1292 wake_up_interruptible(&stuffp->lockq);
1293 xtrace(XFER, "transfer() done (-1)\n");
1294 return -1;
1297 /* check if we need to set the busy flag (as we
1298 * expect an interrupt */
1299 stuffp->busy = (3 == (stuffp->pending & 3));
1301 /* Test if it's the first sector of a block,
1302 * there we have to skip some bytes as we read raw data */
1303 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1304 const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
1305 insb((unsigned int) stuffp->rreg_data, p, HEAD);
1308 /* now actually read the data */
1309 insb((unsigned int) stuffp->rreg_data, p, 512);
1311 /* test if it's the last sector of a block,
1312 * if so, we have to handle XA special */
1313 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1314 char dummy[CD_XA_TAIL];
1315 insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1318 if (stuffp->pending == sector) {
1319 p += 512;
1320 done++;
1321 sector++;
1323 } while (++(stuffp->pending) < border);
1325 stuffp->lock = 0;
1326 wake_up_interruptible(&stuffp->lockq);
1328 } else {
1330 /* The requested sector(s) is/are out of the
1331 * already requested range, so we have to bother the drive
1332 * with a new request. */
1334 static unsigned char cmd[] = {
1336 0, 0, 0,
1337 0, 0, 0
1340 cmd[0] = stuffp->readcmd;
1342 /* The numbers held in ->pending, ..., should be valid */
1343 stuffp->valid = 1;
1344 stuffp->pending = sector & ~3;
1346 /* do some sanity checks */
1347 if (stuffp->pending > stuffp->lastsector) {
1348 xwarn("transfer() sector %d from nirvana requested.\n",
1349 stuffp->pending);
1350 stuffp->status = MCDX_ST_EOM;
1351 stuffp->valid = 0;
1352 xtrace(XFER, "transfer() done (-1)\n");
1353 return -1;
1356 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1357 > stuffp->lastsector + 1) {
1358 xtrace(XFER, "cut low_border\n");
1359 stuffp->low_border = stuffp->lastsector + 1;
1361 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1362 > stuffp->lastsector + 1) {
1363 xtrace(XFER, "cut high_border\n");
1364 stuffp->high_border = stuffp->lastsector + 1;
1367 { /* Convert the sector to be requested to MSF format */
1368 struct cdrom_msf0 pending;
1369 log2msf(stuffp->pending / 4, &pending);
1370 cmd[1] = pending.minute;
1371 cmd[2] = pending.second;
1372 cmd[3] = pending.frame;
1375 cmd[6] = (unsigned char) ((stuffp->high_border - stuffp->pending) / 4);
1376 xtrace(XFER, "[%2d]\n", cmd[6]);
1378 stuffp->busy = 1;
1379 /* Now really issue the request command */
1380 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1383 #ifdef AK2
1384 if ( stuffp->int_err ) {
1385 stuffp->valid = 0;
1386 stuffp->int_err = 0;
1387 return -1;
1389 #endif /* AK2 */
1391 stuffp->low_border = (stuffp->low_border += done) < stuffp->high_border
1392 ? stuffp->low_border : stuffp->high_border;
1394 return done;
1398 /* Access to elements of the mcdx_drive_map members */
1400 static char* port(int *ip) { return (char*) ip[0]; }
1401 static int irq(int *ip) { return ip[1]; }
1403 /* Misc number converters */
1405 static unsigned int bcd2uint(unsigned char c)
1406 { return (c >> 4) * 10 + (c & 0x0f); }
1408 static unsigned int uint2bcd(unsigned int ival)
1409 { return ((ival / 10) << 4) | (ival % 10); }
1411 static void log2msf(unsigned int l, struct cdrom_msf0* pmsf)
1413 l += CD_MSF_OFFSET;
1414 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1415 pmsf->second = uint2bcd(l / 75);
1416 pmsf->frame = uint2bcd(l % 75);
1419 static unsigned int msf2log(const struct cdrom_msf0* pmsf)
1421 return bcd2uint(pmsf->frame)
1422 + bcd2uint(pmsf->second) * 75
1423 + bcd2uint(pmsf->minute) * 4500
1424 - CD_MSF_OFFSET;
1427 int mcdx_readtoc(struct s_drive_stuff* stuffp)
1428 /* Read the toc entries from the CD,
1429 * Return: -1 on failure, else 0 */
1432 if (stuffp->toc) {
1433 xtrace(READTOC, "ioctl() toc already read\n");
1434 return 0;
1437 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1438 stuffp->di.n_last - stuffp->di.n_first + 1);
1440 if (-1 == mcdx_hold(stuffp, 1)) return -1;
1442 xtrace(READTOC, "ioctl() tocmode\n");
1443 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
1445 /* all seems to be ok so far ... malloc */
1447 int size;
1448 size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
1450 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1451 stuffp->toc = kmalloc(size, GFP_KERNEL);
1452 if (!stuffp->toc) {
1453 xwarn("Cannot malloc %d bytes for toc\n", size);
1454 mcdx_setdrivemode(stuffp, DATA, 1);
1455 return -EIO;
1459 /* now read actually the index */
1461 int trk;
1462 int retries;
1464 for (trk = 0;
1465 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1466 trk++)
1467 stuffp->toc[trk].index = 0;
1469 for (retries = 300; retries; retries--) { /* why 300? */
1470 struct s_subqcode q;
1471 unsigned int idx;
1473 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1474 mcdx_setdrivemode(stuffp, DATA, 1);
1475 return -EIO;
1478 idx = bcd2uint(q.index);
1480 if ((idx > 0)
1481 && (idx <= stuffp->di.n_last)
1482 && (q.tno == 0)
1483 && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
1484 stuffp->toc[idx - stuffp->di.n_first] = q;
1485 xtrace(READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk);
1486 trk--;
1488 if (trk == 0) break;
1490 memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1],
1491 0, sizeof(stuffp->toc[0]));
1492 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
1493 = stuffp->di.msf_leadout;
1496 /* unset toc mode */
1497 xtrace(READTOC, "ioctl() undo toc mode\n");
1498 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1499 return -EIO;
1501 #if MCDX_DEBUG && READTOC
1502 { int trk;
1503 for (trk = 0;
1504 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1505 trk++)
1506 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1507 " %02x:%02x.%02x %02x:%02x.%02x\n",
1508 trk + stuffp->di.n_first,
1509 stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
1510 stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
1511 stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame);
1513 #endif
1515 return 0;
1518 static int
1519 mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
1521 unsigned char cmd[7] = {
1522 0, 0, 0, 0, 0, 0, 0
1525 if (!stuffp->readcmd) {
1526 xinfo("Can't play from missing disk.\n");
1527 return -1;
1530 cmd[0] = stuffp->playcmd;
1532 cmd[1] = msf->cdmsf_min0;
1533 cmd[2] = msf->cdmsf_sec0;
1534 cmd[3] = msf->cdmsf_frame0;
1535 cmd[4] = msf->cdmsf_min1;
1536 cmd[5] = msf->cdmsf_sec1;
1537 cmd[6] = msf->cdmsf_frame1;
1539 xtrace(PLAYMSF, "ioctl(): play %x "
1540 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1541 cmd[0], cmd[1], cmd[2], cmd[3],
1542 cmd[4], cmd[5], cmd[6]);
1544 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1546 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1547 xwarn("playmsf() timeout\n");
1548 return -1;
1551 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1552 return 0;
1555 static int
1556 mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
1558 struct s_subqcode* p;
1559 struct cdrom_msf msf;
1561 if (-1 == mcdx_readtoc(stuffp)) return -1;
1563 if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1564 else p = &stuffp->start;
1566 msf.cdmsf_min0 = p->dt.minute;
1567 msf.cdmsf_sec0 = p->dt.second;
1568 msf.cdmsf_frame0 = p->dt.frame;
1570 if (ti) {
1571 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1572 stuffp->stop = *p;
1573 } else p = &stuffp->stop;
1575 msf.cdmsf_min1 = p->dt.minute;
1576 msf.cdmsf_sec1 = p->dt.second;
1577 msf.cdmsf_frame1 = p->dt.frame;
1579 return mcdx_playmsf(stuffp, &msf);
1583 /* Drive functions ************************************************/
1585 static int
1586 mcdx_tray_move(struct cdrom_device_info * cdi, int position)
1588 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1590 if (!stuffp->present)
1591 return -ENXIO;
1592 if (!(stuffp->present & DOOR))
1593 return -ENOSYS;
1595 if (position) /* 1: eject */
1596 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1597 else /* 0: close */
1598 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1599 return 1;
1602 static int
1603 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1604 { return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
1606 static int
1607 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1608 { return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
1610 static int
1611 mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1612 struct s_subqcode *sub,
1613 int tries)
1615 char buf[11];
1616 int ans;
1618 if (-1 == (ans = mcdx_talk(
1619 stuffp, "\x20", 1, buf, sizeof(buf),
1620 2 * HZ, tries)))
1621 return -1;
1622 sub->control = buf[1];
1623 sub->tno = buf[2];
1624 sub->index = buf[3];
1625 sub->tt.minute = buf[4];
1626 sub->tt.second = buf[5];
1627 sub->tt.frame = buf[6];
1628 sub->dt.minute = buf[8];
1629 sub->dt.second = buf[9];
1630 sub->dt.frame = buf[10];
1632 return ans;
1635 static int
1636 mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
1638 char buf[5];
1639 int ans;
1641 if (stuffp->present & MULTI) {
1642 ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries);
1643 multi->multi = buf[1];
1644 multi->msf_last.minute = buf[2];
1645 multi->msf_last.second = buf[3];
1646 multi->msf_last.frame = buf[4];
1647 return ans;
1648 } else {
1649 multi->multi = 0;
1650 return 0;
1654 static int
1655 mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
1657 char buf[9];
1658 int ans;
1659 ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1660 if (ans == -1) {
1661 info->n_first = 0;
1662 info->n_last = 0;
1663 } else {
1664 info->n_first = bcd2uint(buf[1]);
1665 info->n_last = bcd2uint(buf[2]);
1666 info->msf_leadout.minute = buf[3];
1667 info->msf_leadout.second = buf[4];
1668 info->msf_leadout.frame = buf[5];
1669 info->msf_first.minute = buf[6];
1670 info->msf_first.second = buf[7];
1671 info->msf_first.frame = buf[8];
1673 return ans;
1676 static int
1677 mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
1679 char cmd[2];
1680 int ans;
1682 xtrace(HW, "setdrivemode() %d\n", mode);
1684 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1685 return -1;
1687 switch (mode) {
1688 case TOC: cmd[1] |= 0x04; break;
1689 case DATA: cmd[1] &= ~0x04; break;
1690 case RAW: cmd[1] |= 0x40; break;
1691 case COOKED: cmd[1] &= ~0x40; break;
1692 default: break;
1694 cmd[0] = 0x50;
1695 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1698 static int
1699 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
1701 unsigned char cmd[2] = { 0xa0 };
1702 xtrace(HW, "setdatamode() %d\n", mode);
1703 switch (mode) {
1704 case MODE0: cmd[1] = 0x00; break;
1705 case MODE1: cmd[1] = 0x01; break;
1706 case MODE2: cmd[1] = 0x02; break;
1707 default: return -EINVAL;
1709 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1712 static int
1713 mcdx_config(struct s_drive_stuff *stuffp, int tries)
1715 char cmd[4];
1717 xtrace(HW, "config()\n");
1719 cmd[0] = 0x90;
1721 cmd[1] = 0x10; /* irq enable */
1722 cmd[2] = 0x05; /* pre, err irq enable */
1724 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1725 return -1;
1727 cmd[1] = 0x02; /* dma select */
1728 cmd[2] = 0x00; /* no dma */
1730 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1733 static int
1734 mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
1736 char buf[3];
1737 int ans;
1739 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1740 1, buf, sizeof(buf), 2 * HZ, tries)))
1741 return ans;
1743 ver->code = buf[1];
1744 ver->ver = buf[2];
1746 return ans;
1749 static int
1750 mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1752 if (mode == HARD) {
1753 outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
1754 outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
1755 return 0;
1756 } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1759 static int mcdx_lockdoor(struct cdrom_device_info * cdi, int lock)
1761 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1762 char cmd[2] = { 0xfe };
1764 if (!(stuffp->present & DOOR))
1765 return -ENOSYS;
1766 if (stuffp->present & DOOR) {
1767 cmd[1] = lock ? 0x01 : 0x00;
1768 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1769 } else return 0;
1772 static int
1773 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1774 { return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
1776 static int
1777 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
1779 unsigned long timeout = to + jiffies;
1780 char c;
1782 if (!buf) buf = &c;
1784 while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1785 if (time_after(jiffies, timeout)) return -1;
1786 mcdx_delay(stuffp, delay);
1789 *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1791 return 0;
1794 static int
1795 mcdx_setattentuator(
1796 struct s_drive_stuff* stuffp,
1797 struct cdrom_volctrl* vol,
1798 int tries)
1800 char cmd[5];
1801 cmd[0] = 0xae;
1802 cmd[1] = vol->channel0;
1803 cmd[2] = 0;
1804 cmd[3] = vol->channel1;
1805 cmd[4] = 0;
1807 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1810 /* ex:set ts=4 sw=4 ai si: */