Rest of the merge.
[linux-2.6/linux-mips.git] / drivers / cdrom / mcd.c
blob44cde3738ca956395c7d2a945be83d36d55f2f7c
1 /*
2 linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
4 Copyright (C) 1992 Martin Harriss
6 martin@bdsi.com (no longer valid - where are you now, Martin?)
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 HISTORY
24 0.1 First attempt - internal use only
25 0.2 Cleaned up delays and use of timer - alpha release
26 0.3 Audio support added
27 0.3.1 Changes for mitsumi CRMC LU005S march version
28 (stud11@cc4.kuleuven.ac.be)
29 0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
30 (Jon Tombs <jon@robots.ox.ac.uk>)
31 0.3.3 Added more #defines and mcd_setup()
32 (Jon Tombs <jon@gtex02.us.es>)
34 October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
35 Braunschweig, Germany: rework to speed up data read operation.
36 Also enabled definition of irq and address from bootstrap, using the
37 environment.
38 November 93 added code for FX001 S,D (single & double speed).
39 February 94 added code for broken M 5/6 series of 16-bit single speed.
42 0.4
43 Added support for loadable MODULEs, so mcd can now also be loaded by
44 insmod and removed by rmmod during runtime.
45 Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
47 0.5
48 I added code for FX001 D to drop from double speed to single speed
49 when encountering errors... this helps with some "problematic" CD's
50 that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
51 severely scratched, or possibly slightly warped! I have noticed that
52 the Mitsumi 2x/4x drives are just less tolerant and the firmware is
53 not smart enough to drop speed, so let's just kludge it with software!
54 ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
55 Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
56 even WORSE! ;)
57 ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
58 certain "large" CD's that have data on the outside edge in your
59 DOS DRIVERS .... Accuracy counts... speed is secondary ;)
60 17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
61 07 July 1995 Modifications by Andrew J. Kroll
63 Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
65 Michael K. Johnson <johnsonm@redhat.com> added retries on open
66 for slow drives which take a while to recognize that they contain
67 a CD.
69 November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
70 March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
72 November 1999 -- Make kernel-parameter implementation work with 2.3.x
73 Removed init_module & cleanup_module in favor of
74 module_init & module_exit.
75 Torben Mathiasen <tmm@image.dk>
80 #include <linux/module.h>
82 #include <linux/errno.h>
83 #include <linux/signal.h>
84 #include <linux/sched.h>
85 #include <linux/mm.h>
86 #include <linux/timer.h>
87 #include <linux/fs.h>
88 #include <linux/kernel.h>
89 #include <linux/devfs_fs_kernel.h>
90 #include <linux/cdrom.h>
91 #include <linux/ioport.h>
92 #include <linux/string.h>
93 #include <linux/delay.h>
94 #include <linux/init.h>
95 #include <linux/config.h>
97 /* #define REALLY_SLOW_IO */
98 #include <asm/system.h>
99 #include <asm/io.h>
100 #include <asm/uaccess.h>
102 #define MAJOR_NR MITSUMI_CDROM_MAJOR
103 #include <linux/blk.h>
105 #define mcd_port mcd /* for compatible parameter passing with "insmod" */
106 #include "mcd.h"
108 static int mcd_blocksizes[1] = { 0, };
111 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
112 static int mcdDouble = 0;
114 /* How many sectors to hold at 1x speed counter */
115 static int mcd1xhold = 0;
117 /* Is the drive connected properly and responding?? */
118 static int mcdPresent = 0;
120 #if 0
121 #define TEST1 /* <int-..> */
122 #define TEST2 /* do_mcd_req */
123 #define TEST3 */ /* MCD_S_state */
124 #define TEST4 /* QUICK_LOOP-counter */
125 #define TEST5 */ /* port(1) state */
126 #endif
128 #if 1
129 #define QUICK_LOOP_DELAY udelay(45) /* use udelay */
130 #define QUICK_LOOP_COUNT 20
131 #else
132 #define QUICK_LOOP_DELAY
133 #define QUICK_LOOP_COUNT 140 /* better wait constant time */
134 #endif
135 /* #define DOUBLE_QUICK_ONLY */
137 #define CURRENT_VALID \
138 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
139 && CURRENT -> sector != -1)
141 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
142 #define MCD_BUF_SIZ 16
143 static volatile int mcd_transfer_is_active;
144 static char mcd_buf[2048*MCD_BUF_SIZ]; /* buffer for block size conversion */
145 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
146 static volatile int mcd_buf_in, mcd_buf_out = -1;
147 static volatile int mcd_error;
148 static int mcd_open_count;
149 enum mcd_state_e {
150 MCD_S_IDLE, /* 0 */
151 MCD_S_START, /* 1 */
152 MCD_S_MODE, /* 2 */
153 MCD_S_READ, /* 3 */
154 MCD_S_DATA, /* 4 */
155 MCD_S_STOP, /* 5 */
156 MCD_S_STOPPING /* 6 */
158 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
159 static int mcd_mode = -1;
160 static int MCMD_DATA_READ= MCMD_PLAY_READ;
161 #define READ_TIMEOUT 3000
162 #define WORK_AROUND_MITSUMI_BUG_92
163 #define WORK_AROUND_MITSUMI_BUG_93
164 #ifdef WORK_AROUND_MITSUMI_BUG_93
165 int mitsumi_bug_93_wait = 0;
166 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
168 static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
169 static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
170 MODULE_PARM(mcd, "1-2i");
172 static int McdTimeout, McdTries;
173 static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
175 static struct mcd_DiskInfo DiskInfo;
176 static struct mcd_Toc Toc[MAX_TRACKS];
177 static struct mcd_Play_msf mcd_Play;
179 static int audioStatus;
180 static char mcdDiskChanged;
181 static char tocUpToDate;
182 static char mcdVersion;
184 static void mcd_transfer(void);
185 static void mcd_poll(void);
186 static void mcd_invalidate_buffers(void);
187 static void hsg2msf(long hsg, struct msf *msf);
188 static void bin2bcd(unsigned char *p);
189 static int bcd2bin(unsigned char bcd);
190 static int mcdStatus(void);
191 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
192 static int getMcdStatus(int timeout);
193 static int GetQChannelInfo(struct mcd_Toc *qp);
194 static int updateToc(void);
195 static int GetDiskInfo(void);
196 static int GetToc(void);
197 static int getValue(unsigned char *result);
198 static int mcd_open(struct cdrom_device_info * cdi, int purpose);
199 static void mcd_release(struct cdrom_device_info * cdi);
200 static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr);
201 static int mcd_tray_move(struct cdrom_device_info * cdi, int position);
202 int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
203 void * arg);
204 int mcd_drive_status(struct cdrom_device_info * cdi, int slot_nr);
206 static struct cdrom_device_ops mcd_dops = {
207 mcd_open, /* open */
208 mcd_release, /* release */
209 mcd_drive_status, /* drive status */
210 //NULL, /* drive status */
211 mcd_media_changed, /* media changed */
212 mcd_tray_move, /* tray move */
213 NULL, /* lock door */
214 NULL, /* select speed */
215 NULL, /* select disc */
216 NULL, /* get last session */
217 NULL, /* get universal product code */
218 NULL, /* hard reset */
219 mcd_audio_ioctl, /* audio ioctl */
220 NULL, /* device-specific ioctl */
221 CDC_OPEN_TRAY | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO
222 | CDC_DRIVE_STATUS, /* capability */
223 0, /* number of minor devices */
226 static struct cdrom_device_info mcd_info = {
227 &mcd_dops, /* device operations */
228 NULL, /* link */
229 NULL, /* handle */
230 0, /* dev */
231 0, /* mask */
232 2, /* maximum speed */
233 1, /* number of discs */
234 0, /* options, not owned */
235 0, /* mc_flags, not owned */
236 0, /* use count, not owned */
237 "mcd", /* name of the device type */
240 #ifndef MODULE
241 static int __init mcd_setup(char *str)
243 int ints[9];
245 (void)get_options(str, ARRAY_SIZE(ints), ints);
247 if (ints[0] > 0)
248 mcd_port = ints[1];
249 if (ints[0] > 1)
250 mcd_irq = ints[2];
251 #ifdef WORK_AROUND_MITSUMI_BUG_93
252 if (ints[0] > 2)
253 mitsumi_bug_93_wait = ints[3];
254 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
256 return 1;
259 __setup("mcd=", mcd_setup);
261 #endif /* MODULE */
263 static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr)
265 int retval;
268 #if 1 /* the below is not reliable */
269 return 0;
270 #endif
272 if (cdi->dev) {
273 printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
274 return 0;
277 retval = mcdDiskChanged;
278 mcdDiskChanged = 0;
280 return retval;
285 * Do a 'get status' command and get the result. Only use from the top half
286 * because it calls 'getMcdStatus' which sleeps.
289 static int
290 statusCmd(void)
292 int st, retry;
294 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
296 outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
298 st = getMcdStatus(MCD_STATUS_DELAY);
299 if (st != -1)
300 break;
303 return st;
308 * Send a 'Play' command and get the status. Use only from the top half.
311 static int
312 mcdPlay(struct mcd_Play_msf *arg)
314 int retry, st;
316 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
318 sendMcdCmd(MCMD_PLAY_READ, arg);
319 st = getMcdStatus(2 * MCD_STATUS_DELAY);
320 if (st != -1)
321 break;
324 return st;
328 static int
329 mcd_tray_move(struct cdrom_device_info * cdi, int position)
331 int i;
332 if (position) {
333 /* Eject */
334 /* all drives can at least stop! */
335 if (audioStatus == CDROM_AUDIO_PLAY) {
336 outb(MCMD_STOP, MCDPORT(0));
337 i = getMcdStatus(MCD_STATUS_DELAY);
340 audioStatus = CDROM_AUDIO_NO_STATUS;
342 outb(MCMD_EJECT, MCDPORT(0));
344 * the status (i) shows failure on all but the FX drives.
345 * But nothing we can do about that in software!
346 * So just read the status and forget it. - Jon.
348 i = getMcdStatus(MCD_STATUS_DELAY);
349 return 0;
351 else
352 return -EINVAL;
355 long
356 msf2hsg(struct msf *mp)
358 return bcd2bin(mp -> frame)
359 + bcd2bin(mp -> sec) * 75
360 + bcd2bin(mp -> min) * 4500
361 - 150;
365 int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
366 void * arg)
368 int i, st;
369 struct mcd_Toc qInfo;
370 struct cdrom_ti *ti;
371 struct cdrom_tochdr *tocHdr;
372 struct cdrom_msf *msf;
373 struct cdrom_subchnl *subchnl;
374 struct cdrom_tocentry *entry;
375 struct mcd_Toc *tocPtr;
376 struct cdrom_volctrl *volctrl;
378 st = statusCmd();
379 if (st < 0)
380 return -EIO;
382 if (!tocUpToDate)
384 i = updateToc();
385 if (i < 0)
386 return i; /* error reading TOC */
389 switch (cmd)
391 case CDROMSTART: /* Spin up the drive */
392 /* Don't think we can do this. Even if we could,
393 * I think the drive times out and stops after a while
394 * anyway. For now, ignore it.
397 return 0;
399 case CDROMSTOP: /* Spin down the drive */
400 outb(MCMD_STOP, MCDPORT(0));
401 i = getMcdStatus(MCD_STATUS_DELAY);
403 /* should we do anything if it fails? */
405 audioStatus = CDROM_AUDIO_NO_STATUS;
406 return 0;
408 case CDROMPAUSE: /* Pause the drive */
409 if (audioStatus != CDROM_AUDIO_PLAY)
410 return -EINVAL;
412 outb(MCMD_STOP, MCDPORT(0));
413 i = getMcdStatus(MCD_STATUS_DELAY);
415 if (GetQChannelInfo(&qInfo) < 0)
417 /* didn't get q channel info */
419 audioStatus = CDROM_AUDIO_NO_STATUS;
420 return 0;
423 mcd_Play.start = qInfo.diskTime; /* remember restart point */
425 audioStatus = CDROM_AUDIO_PAUSED;
426 return 0;
428 case CDROMRESUME: /* Play it again, Sam */
429 if (audioStatus != CDROM_AUDIO_PAUSED)
430 return -EINVAL;
432 /* restart the drive at the saved position. */
434 i = mcdPlay(&mcd_Play);
435 if (i < 0)
437 audioStatus = CDROM_AUDIO_ERROR;
438 return -EIO;
441 audioStatus = CDROM_AUDIO_PLAY;
442 return 0;
444 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
446 ti=(struct cdrom_ti *) arg;
448 if (ti->cdti_trk0 < DiskInfo.first
449 || ti->cdti_trk0 > DiskInfo.last
450 || ti->cdti_trk1 < ti->cdti_trk0)
452 return -EINVAL;
455 if (ti->cdti_trk1 > DiskInfo.last)
456 ti->cdti_trk1 = DiskInfo.last;
458 mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
459 mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
461 #ifdef MCD_DEBUG
462 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
463 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
464 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
465 #endif
467 i = mcdPlay(&mcd_Play);
468 if (i < 0)
470 audioStatus = CDROM_AUDIO_ERROR;
471 return -EIO;
474 audioStatus = CDROM_AUDIO_PLAY;
475 return 0;
477 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
479 if (audioStatus == CDROM_AUDIO_PLAY) {
480 outb(MCMD_STOP, MCDPORT(0));
481 i = getMcdStatus(MCD_STATUS_DELAY);
482 audioStatus = CDROM_AUDIO_NO_STATUS;
485 msf=(struct cdrom_msf *) arg;
487 /* convert to bcd */
489 bin2bcd(&msf->cdmsf_min0);
490 bin2bcd(&msf->cdmsf_sec0);
491 bin2bcd(&msf->cdmsf_frame0);
492 bin2bcd(&msf->cdmsf_min1);
493 bin2bcd(&msf->cdmsf_sec1);
494 bin2bcd(&msf->cdmsf_frame1);
496 mcd_Play.start.min = msf->cdmsf_min0;
497 mcd_Play.start.sec = msf->cdmsf_sec0;
498 mcd_Play.start.frame = msf->cdmsf_frame0;
499 mcd_Play.end.min = msf->cdmsf_min1;
500 mcd_Play.end.sec = msf->cdmsf_sec1;
501 mcd_Play.end.frame = msf->cdmsf_frame1;
503 #ifdef MCD_DEBUG
504 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
505 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
506 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
507 #endif
509 i = mcdPlay(&mcd_Play);
510 if (i < 0)
512 audioStatus = CDROM_AUDIO_ERROR;
513 return -EIO;
516 audioStatus = CDROM_AUDIO_PLAY;
517 return 0;
519 case CDROMREADTOCHDR: /* Read the table of contents header */
520 tocHdr=(struct cdrom_tochdr *) arg;
521 tocHdr->cdth_trk0 = DiskInfo.first;
522 tocHdr->cdth_trk1 = DiskInfo.last;
523 return 0;
525 case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
526 entry=(struct cdrom_tocentry *) arg;
527 if (entry->cdte_track == CDROM_LEADOUT)
528 tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
530 else if (entry->cdte_track > DiskInfo.last
531 || entry->cdte_track < DiskInfo.first)
532 return -EINVAL;
534 else
535 tocPtr = &Toc[entry->cdte_track];
537 entry->cdte_adr = tocPtr -> ctrl_addr;
538 entry->cdte_ctrl = tocPtr -> ctrl_addr >> 4;
540 if (entry->cdte_format == CDROM_LBA)
541 entry->cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
543 else if (entry->cdte_format == CDROM_MSF)
545 entry->cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
546 entry->cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
547 entry->cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
550 else
551 return -EINVAL;
553 return 0;
555 case CDROMSUBCHNL: /* Get subchannel info */
557 subchnl=(struct cdrom_subchnl *) arg;
558 if (GetQChannelInfo(&qInfo) < 0)
559 return -EIO;
561 subchnl->cdsc_audiostatus = audioStatus;
562 subchnl->cdsc_adr = qInfo.ctrl_addr;
563 subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
564 subchnl->cdsc_trk = bcd2bin(qInfo.track);
565 subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
566 subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
567 subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
568 subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
569 subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
570 subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
571 subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
572 return(0);
574 case CDROMVOLCTRL: /* Volume control */
575 volctrl=(struct cdrom_volctrl *) arg;
576 outb(MCMD_SET_VOLUME, MCDPORT(0));
577 outb(volctrl->channel0, MCDPORT(0));
578 outb(255, MCDPORT(0));
579 outb(volctrl->channel1, MCDPORT(0));
580 outb(255, MCDPORT(0));
582 i = getMcdStatus(MCD_STATUS_DELAY);
583 if (i < 0)
584 return -EIO;
587 char a, b, c, d;
589 getValue(&a);
590 getValue(&b);
591 getValue(&c);
592 getValue(&d);
595 return 0;
597 default:
598 return -EINVAL;
603 * Take care of the different block sizes between cdrom and Linux.
604 * When Linux gets variable block sizes this will probably go away.
607 static void
608 mcd_transfer(void)
610 if (CURRENT_VALID) {
611 while (CURRENT -> nr_sectors) {
612 int bn = CURRENT -> sector / 4;
613 int i;
614 for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
616 if (i < MCD_BUF_SIZ) {
617 int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
618 int nr_sectors = 4 - (CURRENT -> sector & 3);
619 if (mcd_buf_out != i) {
620 mcd_buf_out = i;
621 if (mcd_buf_bn[i] != bn) {
622 mcd_buf_out = -1;
623 continue;
626 if (nr_sectors > CURRENT -> nr_sectors)
627 nr_sectors = CURRENT -> nr_sectors;
628 memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512);
629 CURRENT -> nr_sectors -= nr_sectors;
630 CURRENT -> sector += nr_sectors;
631 CURRENT -> buffer += nr_sectors * 512;
632 } else {
633 mcd_buf_out = -1;
634 break;
642 * We only seem to get interrupts after an error.
643 * Just take the interrupt and clear out the status reg.
646 static void
647 mcd_interrupt(int irq, void *dev_id, struct pt_regs * regs)
649 int st;
651 st = inb(MCDPORT(1)) & 0xFF;
652 #ifdef TEST1
653 printk("<int1-%02X>", st);
654 #endif
655 if (!(st & MFL_STATUS))
657 st = inb(MCDPORT(0)) & 0xFF;
658 #ifdef TEST1
659 printk("<int0-%02X>", st);
660 #endif
661 if ((st & 0xFF) != 0xFF)
662 mcd_error = st ? st & 0xFF : -1;
667 static void
668 do_mcd_request(request_queue_t * q)
670 #ifdef TEST2
671 printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
672 #endif
673 mcd_transfer_is_active = 1;
674 while (CURRENT_VALID) {
675 if (CURRENT->bh) {
676 if (!buffer_locked(CURRENT->bh))
677 panic(DEVICE_NAME ": block not locked");
679 mcd_transfer();
680 if (CURRENT -> nr_sectors == 0) {
681 end_request(1);
682 } else {
683 mcd_buf_out = -1; /* Want to read a block not in buffer */
684 if (mcd_state == MCD_S_IDLE) {
685 if (!tocUpToDate) {
686 if (updateToc() < 0) {
687 while (CURRENT_VALID)
688 end_request(0);
689 break;
692 mcd_state = MCD_S_START;
693 McdTries = 5;
694 SET_TIMER(mcd_poll, 1);
696 break;
699 mcd_transfer_is_active = 0;
700 #ifdef TEST2
701 printk(" do_mcd_request ends\n");
702 #endif
707 static void
708 mcd_poll(void)
710 int st;
713 if (mcd_error)
715 if (mcd_error & 0xA5)
717 printk("mcd: I/O error 0x%02x", mcd_error);
718 if (mcd_error & 0x80)
719 printk(" (Door open)");
720 if (mcd_error & 0x20)
721 printk(" (Disk changed)");
722 if (mcd_error & 0x04)
724 printk(" (Read error)"); /* Bitch about the problem. */
726 /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
727 /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
728 /* But I find that rather HANDY!!! */
729 /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
730 /* AJK [06/17/95] */
732 /* Slap the CD down to single speed! */
733 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ)
735 MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
736 mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
737 printk(" Speed now 1x"); /* Pull my finger! */
740 printk("\n");
741 mcd_invalidate_buffers();
742 #ifdef WARN_IF_READ_FAILURE
743 if (McdTries == MCD_RETRY_ATTEMPTS)
744 printk("mcd: read of block %d failed\n", mcd_next_bn);
745 #endif
746 if (!McdTries--)
748 /* Nuts! This cd is ready for recycling! */
749 /* When WAS the last time YOU cleaned it CORRECTLY?! */
750 printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
751 if (mcd_transfer_is_active)
753 McdTries = 0;
754 goto ret;
756 if (CURRENT_VALID)
757 end_request(0);
758 McdTries = MCD_RETRY_ATTEMPTS;
761 mcd_error = 0;
762 mcd_state = MCD_S_STOP;
764 /* Switch back to Double speed if enough GOOD sectors were read! */
766 /* Are we a double speed with a crappy CD?! */
767 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ)
769 /* We ARE a double speed and we ARE bitching! */
770 if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */
771 { /* We need to switch back to double speed now... */
772 MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
773 printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
775 else mcd1xhold--; /* No?! Count down the good reads some more... */
776 /* and try, try again! */
781 immediately:
782 switch (mcd_state) {
786 case MCD_S_IDLE:
787 #ifdef TEST3
788 printk("MCD_S_IDLE\n");
789 #endif
790 return;
794 case MCD_S_START:
795 #ifdef TEST3
796 printk("MCD_S_START\n");
797 #endif
799 outb(MCMD_GET_STATUS, MCDPORT(0));
800 mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
801 McdTimeout = 3000;
802 break;
806 case MCD_S_MODE:
807 #ifdef TEST3
808 printk("MCD_S_MODE\n");
809 #endif
811 if ((st = mcdStatus()) != -1) {
813 if (st & MST_DSK_CHG) {
814 mcdDiskChanged = 1;
815 tocUpToDate = 0;
816 mcd_invalidate_buffers();
819 set_mode_immediately:
821 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
822 mcdDiskChanged = 1;
823 tocUpToDate = 0;
824 if (mcd_transfer_is_active) {
825 mcd_state = MCD_S_START;
826 goto immediately;
828 printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
829 mcd_state = MCD_S_IDLE;
830 while (CURRENT_VALID)
831 end_request(0);
832 return;
835 outb(MCMD_SET_MODE, MCDPORT(0));
836 outb(1, MCDPORT(0));
837 mcd_mode = 1;
838 mcd_state = MCD_S_READ;
839 McdTimeout = 3000;
842 break;
846 case MCD_S_READ:
847 #ifdef TEST3
848 printk("MCD_S_READ\n");
849 #endif
851 if ((st = mcdStatus()) != -1) {
853 if (st & MST_DSK_CHG) {
854 mcdDiskChanged = 1;
855 tocUpToDate = 0;
856 mcd_invalidate_buffers();
859 read_immediately:
861 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
862 mcdDiskChanged = 1;
863 tocUpToDate = 0;
864 if (mcd_transfer_is_active) {
865 mcd_state = MCD_S_START;
866 goto immediately;
868 printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
869 mcd_state = MCD_S_IDLE;
870 while (CURRENT_VALID)
871 end_request(0);
872 return;
875 if (CURRENT_VALID) {
876 struct mcd_Play_msf msf;
877 mcd_next_bn = CURRENT -> sector / 4;
878 hsg2msf(mcd_next_bn, &msf.start);
879 msf.end.min = ~0;
880 msf.end.sec = ~0;
881 msf.end.frame = ~0;
882 sendMcdCmd(MCMD_DATA_READ, &msf);
883 mcd_state = MCD_S_DATA;
884 McdTimeout = READ_TIMEOUT;
885 } else {
886 mcd_state = MCD_S_STOP;
887 goto immediately;
891 break;
894 case MCD_S_DATA:
895 #ifdef TEST3
896 printk("MCD_S_DATA\n");
897 #endif
899 st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
900 data_immediately:
901 #ifdef TEST5
902 printk("Status %02x\n",st);
903 #endif
904 switch (st) {
906 case MFL_DATA:
907 #ifdef WARN_IF_READ_FAILURE
908 if (McdTries == 5)
909 printk("mcd: read of block %d failed\n", mcd_next_bn);
910 #endif
911 if (!McdTries--) {
912 printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
913 if (mcd_transfer_is_active) {
914 McdTries = 0;
915 break;
917 if (CURRENT_VALID)
918 end_request(0);
919 McdTries = 5;
921 mcd_state = MCD_S_START;
922 McdTimeout = READ_TIMEOUT;
923 goto immediately;
925 case MFL_STATUSorDATA:
926 break;
928 default:
929 McdTries = 5;
930 if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
931 mcd_state = MCD_S_STOP;
932 goto immediately;
934 mcd_buf_bn[mcd_buf_in] = -1;
935 READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
936 mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
937 if (mcd_buf_out == -1)
938 mcd_buf_out = mcd_buf_in;
939 mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
940 if (!mcd_transfer_is_active) {
941 while (CURRENT_VALID) {
942 mcd_transfer();
943 if (CURRENT -> nr_sectors == 0)
944 end_request(1);
945 else
946 break;
950 if (CURRENT_VALID
951 && (CURRENT -> sector / 4 < mcd_next_bn ||
952 CURRENT -> sector / 4 > mcd_next_bn + 16)) {
953 mcd_state = MCD_S_STOP;
954 goto immediately;
956 McdTimeout = READ_TIMEOUT;
957 #ifdef DOUBLE_QUICK_ONLY
958 if (MCMD_DATA_READ != MCMD_PLAY_READ)
959 #endif
961 int count= QUICK_LOOP_COUNT;
962 while (count--) {
963 QUICK_LOOP_DELAY;
964 if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
965 # ifdef TEST4
966 /* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
967 printk(" %d ",QUICK_LOOP_COUNT-count);
968 # endif
969 goto data_immediately;
972 # ifdef TEST4
973 /* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
974 printk("ended ");
975 # endif
977 break;
979 break;
983 case MCD_S_STOP:
984 #ifdef TEST3
985 printk("MCD_S_STOP\n");
986 #endif
988 #ifdef WORK_AROUND_MITSUMI_BUG_93
989 if (!mitsumi_bug_93_wait)
990 goto do_not_work_around_mitsumi_bug_93_1;
992 McdTimeout = mitsumi_bug_93_wait;
993 mcd_state = 9+3+1;
994 break;
996 case 9+3+1:
997 if (McdTimeout)
998 break;
1000 do_not_work_around_mitsumi_bug_93_1:
1001 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
1003 outb(MCMD_STOP, MCDPORT(0));
1005 #ifdef WORK_AROUND_MITSUMI_BUG_92
1006 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1007 int i = 4096;
1008 do {
1009 inb(MCDPORT(0));
1010 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1011 outb(MCMD_STOP, MCDPORT(0));
1012 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1013 i = 4096;
1014 do {
1015 inb(MCDPORT(0));
1016 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1017 outb(MCMD_STOP, MCDPORT(0));
1020 #endif /* WORK_AROUND_MITSUMI_BUG_92 */
1022 mcd_state = MCD_S_STOPPING;
1023 McdTimeout = 1000;
1024 break;
1026 case MCD_S_STOPPING:
1027 #ifdef TEST3
1028 printk("MCD_S_STOPPING\n");
1029 #endif
1031 if ((st = mcdStatus()) == -1 && McdTimeout)
1032 break;
1034 if ((st != -1) && (st & MST_DSK_CHG)) {
1035 mcdDiskChanged = 1;
1036 tocUpToDate = 0;
1037 mcd_invalidate_buffers();
1040 #ifdef WORK_AROUND_MITSUMI_BUG_93
1041 if (!mitsumi_bug_93_wait)
1042 goto do_not_work_around_mitsumi_bug_93_2;
1044 McdTimeout = mitsumi_bug_93_wait;
1045 mcd_state = 9+3+2;
1046 break;
1048 case 9+3+2:
1049 if (McdTimeout)
1050 break;
1052 st = -1;
1054 do_not_work_around_mitsumi_bug_93_2:
1055 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
1057 #ifdef TEST3
1058 printk("CURRENT_VALID %d mcd_mode %d\n",
1059 CURRENT_VALID, mcd_mode);
1060 #endif
1062 if (CURRENT_VALID) {
1063 if (st != -1) {
1064 if (mcd_mode == 1)
1065 goto read_immediately;
1066 else
1067 goto set_mode_immediately;
1068 } else {
1069 mcd_state = MCD_S_START;
1070 McdTimeout = 1;
1072 } else {
1073 mcd_state = MCD_S_IDLE;
1074 return;
1076 break;
1078 default:
1079 printk("mcd: invalid state %d\n", mcd_state);
1080 return;
1083 ret:
1084 if (!McdTimeout--) {
1085 printk("mcd: timeout in state %d\n", mcd_state);
1086 mcd_state = MCD_S_STOP;
1089 SET_TIMER(mcd_poll, 1);
1094 static void
1095 mcd_invalidate_buffers(void)
1097 int i;
1098 for (i = 0; i < MCD_BUF_SIZ; ++i)
1099 mcd_buf_bn[i] = -1;
1100 mcd_buf_out = -1;
1105 * Open the device special file. Check that a disk is in.
1107 static int mcd_open(struct cdrom_device_info * cdi, int purpose)
1109 int st, count=0;
1110 if (mcdPresent == 0)
1111 return -ENXIO; /* no hardware */
1113 if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
1114 mcd_invalidate_buffers();
1115 do {
1116 st = statusCmd(); /* check drive status */
1117 if (st == -1)
1118 return -EIO; /* drive doesn't respond */
1119 if ((st & MST_READY) == 0) { /* no disk? wait a sec... */
1120 current->state = TASK_INTERRUPTIBLE;
1121 schedule_timeout(HZ);
1123 } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1125 if (updateToc() < 0)
1126 return -EIO;
1128 ++mcd_open_count;
1129 MOD_INC_USE_COUNT;
1130 return 0;
1135 * On close, we flush all mcd blocks from the buffer cache.
1137 static void mcd_release(struct cdrom_device_info * cdi)
1138 { MOD_DEC_USE_COUNT;
1139 if (!--mcd_open_count) {
1140 mcd_invalidate_buffers();
1146 /* This routine gets called during initialization if things go wrong,
1147 * and is used in mcd_exit as well. */
1148 static void cleanup(int level)
1150 switch (level) {
1151 case 3:
1152 if (unregister_cdrom(&mcd_info)) {
1153 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1154 return;
1156 free_irq(mcd_irq, NULL);
1157 case 2:
1158 release_region(mcd_port,4);
1159 case 1:
1160 if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
1161 printk(KERN_WARNING "Can't unregister major mcd\n");
1162 return;
1164 default:
1171 * Test for presence of drive and initialize it. Called at boot time.
1174 int __init mcd_init(void)
1176 int count;
1177 unsigned char result[3];
1178 char msg[80];
1180 if (mcd_port <= 0 || mcd_irq <= 0) {
1181 printk("skip mcd_init\n");
1182 return -EIO;
1185 if (devfs_register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0)
1187 printk("Unable to get major %d for Mitsumi CD-ROM\n",
1188 MAJOR_NR);
1189 return -EIO;
1191 if (check_region(mcd_port, 4)) {
1192 cleanup(1);
1193 printk("Init failed, I/O port (%X) already in use\n",
1194 mcd_port);
1195 return -EIO;
1198 blksize_size[MAJOR_NR] = mcd_blocksizes;
1199 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1200 read_ahead[MAJOR_NR] = 4;
1202 /* check for card */
1204 outb(0, MCDPORT(1)); /* send reset */
1205 for (count = 0; count < 2000000; count++)
1206 (void) inb(MCDPORT(1)); /* delay a bit */
1208 outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1209 for (count = 0; count < 2000000; count++)
1210 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1211 break;
1213 if (count >= 2000000) {
1214 printk("Init failed. No mcd device at 0x%x irq %d\n",
1215 mcd_port, mcd_irq);
1216 cleanup(1);
1217 return -EIO;
1219 count = inb(MCDPORT(0)); /* pick up the status */
1221 outb(MCMD_GET_VERSION,MCDPORT(0));
1222 for(count=0;count<3;count++)
1223 if(getValue(result+count)) {
1224 printk("mitsumi get version failed at 0x%d\n",
1225 mcd_port);
1226 cleanup(1);
1227 return -EIO;
1230 if (result[0] == result[1] && result[1] == result[2]) {
1231 cleanup(1);
1232 return -EIO;
1235 mcdVersion=result[2];
1237 if (mcdVersion >=4)
1238 outb(4,MCDPORT(2)); /* magic happens */
1240 /* don't get the IRQ until we know for sure the drive is there */
1242 if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL))
1244 printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1245 cleanup(1);
1246 return -EIO;
1249 if (result[1] == 'D')
1251 MCMD_DATA_READ = MCMD_2X_READ;
1252 /* Added flag to drop to 1x speed if too many errors */
1253 mcdDouble = 1;
1254 } else
1255 mcd_info.speed = 1;
1256 sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1257 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double", mcd_port, mcd_irq);
1259 request_region(mcd_port, 4, "mcd");
1261 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1262 outb(0x02,MCDPORT(0));
1263 outb(0x00,MCDPORT(0));
1264 getValue(result);
1266 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1267 outb(0x10,MCDPORT(0));
1268 outb(0x04,MCDPORT(0));
1269 getValue(result);
1271 mcd_invalidate_buffers();
1272 mcdPresent = 1;
1274 mcd_info.dev = MKDEV(MAJOR_NR,0);
1276 if (register_cdrom(&mcd_info) != 0) {
1277 printk("Cannot register Mitsumi CD-ROM!\n");
1278 cleanup(3);
1279 return -EIO;
1281 printk(msg);
1283 return 0;
1287 static void
1288 hsg2msf(long hsg, struct msf *msf)
1290 hsg += 150;
1291 msf -> min = hsg / 4500;
1292 hsg %= 4500;
1293 msf -> sec = hsg / 75;
1294 msf -> frame = hsg % 75;
1296 bin2bcd(&msf -> min); /* convert to BCD */
1297 bin2bcd(&msf -> sec);
1298 bin2bcd(&msf -> frame);
1302 static void
1303 bin2bcd(unsigned char *p)
1305 int u, t;
1307 u = *p % 10;
1308 t = *p / 10;
1309 *p = u | (t << 4);
1312 static int
1313 bcd2bin(unsigned char bcd)
1315 return (bcd >> 4) * 10 + (bcd & 0xF);
1320 * See if a status is ready from the drive and return it
1321 * if it is ready.
1324 static int
1325 mcdStatus(void)
1327 int i;
1328 int st;
1330 st = inb(MCDPORT(1)) & MFL_STATUS;
1331 if (!st)
1333 i = inb(MCDPORT(0)) & 0xFF;
1334 return i;
1336 else
1337 return -1;
1342 * Send a play or read command to the drive
1345 static void
1346 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1348 outb(cmd, MCDPORT(0));
1349 outb(params -> start.min, MCDPORT(0));
1350 outb(params -> start.sec, MCDPORT(0));
1351 outb(params -> start.frame, MCDPORT(0));
1352 outb(params -> end.min, MCDPORT(0));
1353 outb(params -> end.sec, MCDPORT(0));
1354 outb(params -> end.frame, MCDPORT(0));
1359 * Timer interrupt routine to test for status ready from the drive.
1360 * (see the next routine)
1363 static void
1364 mcdStatTimer(void)
1366 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1368 wake_up(&mcd_waitq);
1369 return;
1372 McdTimeout--;
1373 if (McdTimeout <= 0)
1375 wake_up(&mcd_waitq);
1376 return;
1379 SET_TIMER(mcdStatTimer, 1);
1384 * Wait for a status to be returned from the drive. The actual test
1385 * (see routine above) is done by the timer interrupt to avoid
1386 * excessive rescheduling.
1389 static int
1390 getMcdStatus(int timeout)
1392 int st;
1394 McdTimeout = timeout;
1395 SET_TIMER(mcdStatTimer, 1);
1396 sleep_on(&mcd_waitq);
1397 if (McdTimeout <= 0)
1398 return -1;
1400 st = inb(MCDPORT(0)) & 0xFF;
1401 if (st == 0xFF)
1402 return -1;
1404 if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1405 /* XXX might be an error? look at q-channel? */
1406 audioStatus = CDROM_AUDIO_COMPLETED;
1408 if (st & MST_DSK_CHG)
1410 mcdDiskChanged = 1;
1411 tocUpToDate = 0;
1412 audioStatus = CDROM_AUDIO_NO_STATUS;
1415 return st;
1419 /* gives current state of the drive This function is quite unreliable,
1420 and should probably be rewritten by someone, eventually... */
1421 int mcd_drive_status(struct cdrom_device_info * cdi, int slot_nr)
1423 int st;
1425 st = statusCmd(); /* check drive status */
1426 if (st == -1)
1427 return -EIO; /* drive doesn't respond */
1428 if ((st & MST_READY)) return CDS_DISC_OK;
1429 if ((st & MST_DOOR_OPEN)) return CDS_TRAY_OPEN;
1430 if ((st & MST_DSK_CHG)) return CDS_NO_DISC;
1431 if ((st & MST_BUSY)) return CDS_DRIVE_NOT_READY;
1432 return -EIO;
1437 * Read a value from the drive.
1440 static int
1441 getValue(unsigned char *result)
1443 int count;
1444 int s;
1446 for (count = 0; count < 2000; count++)
1447 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1448 break;
1450 if (count >= 2000)
1452 printk("mcd: getValue timeout\n");
1453 return -1;
1456 s = inb(MCDPORT(0)) & 0xFF;
1457 *result = (unsigned char) s;
1458 return 0;
1463 * Read the current Q-channel info. Also used for reading the
1464 * table of contents.
1468 GetQChannelInfo(struct mcd_Toc *qp)
1470 unsigned char notUsed;
1471 int retry;
1473 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1475 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1476 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1477 break;
1480 if (retry >= MCD_RETRY_ATTEMPTS)
1481 return -1;
1483 if (getValue(&qp -> ctrl_addr) < 0) return -1;
1484 if (getValue(&qp -> track) < 0) return -1;
1485 if (getValue(&qp -> pointIndex) < 0) return -1;
1486 if (getValue(&qp -> trackTime.min) < 0) return -1;
1487 if (getValue(&qp -> trackTime.sec) < 0) return -1;
1488 if (getValue(&qp -> trackTime.frame) < 0) return -1;
1489 if (getValue(&notUsed) < 0) return -1;
1490 if (getValue(&qp -> diskTime.min) < 0) return -1;
1491 if (getValue(&qp -> diskTime.sec) < 0) return -1;
1492 if (getValue(&qp -> diskTime.frame) < 0) return -1;
1494 return 0;
1499 * Read the table of contents (TOC) and TOC header if necessary
1502 static int
1503 updateToc()
1505 if (tocUpToDate)
1506 return 0;
1508 if (GetDiskInfo() < 0)
1509 return -EIO;
1511 if (GetToc() < 0)
1512 return -EIO;
1514 tocUpToDate = 1;
1515 return 0;
1520 * Read the table of contents header
1523 static int
1524 GetDiskInfo()
1526 int retry;
1528 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1530 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1531 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1532 break;
1535 if (retry >= MCD_RETRY_ATTEMPTS)
1536 return -1;
1538 if (getValue(&DiskInfo.first) < 0) return -1;
1539 if (getValue(&DiskInfo.last) < 0) return -1;
1541 DiskInfo.first = bcd2bin(DiskInfo.first);
1542 DiskInfo.last = bcd2bin(DiskInfo.last);
1544 #ifdef MCD_DEBUG
1545 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1546 DiskInfo.first,
1547 DiskInfo.last,
1548 DiskInfo.diskLength.min,
1549 DiskInfo.diskLength.sec,
1550 DiskInfo.diskLength.frame,
1551 DiskInfo.firstTrack.min,
1552 DiskInfo.firstTrack.sec,
1553 DiskInfo.firstTrack.frame);
1554 #endif
1556 if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1557 if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1558 if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1559 if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1560 if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1561 if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1563 return 0;
1568 * Read the table of contents (TOC)
1571 static int
1572 GetToc()
1574 int i, px;
1575 int limit;
1576 int retry;
1577 struct mcd_Toc qInfo;
1579 for (i = 0; i < MAX_TRACKS; i++)
1580 Toc[i].pointIndex = 0;
1582 i = DiskInfo.last + 3;
1584 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1586 outb(MCMD_STOP, MCDPORT(0));
1587 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1588 break;
1591 if (retry >= MCD_RETRY_ATTEMPTS)
1592 return -1;
1594 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1596 outb(MCMD_SET_MODE, MCDPORT(0));
1597 outb(0x05, MCDPORT(0)); /* mode: toc */
1598 mcd_mode = 0x05;
1599 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1600 break;
1603 if (retry >= MCD_RETRY_ATTEMPTS)
1604 return -1;
1606 for (limit = 300; limit > 0; limit--)
1608 if (GetQChannelInfo(&qInfo) < 0)
1609 break;
1611 px = bcd2bin(qInfo.pointIndex);
1612 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1613 if (Toc[px].pointIndex == 0)
1615 Toc[px] = qInfo;
1616 i--;
1619 if (i <= 0)
1620 break;
1623 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1625 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1627 outb(MCMD_SET_MODE, MCDPORT(0));
1628 outb(0x01, MCDPORT(0));
1629 mcd_mode = 1;
1630 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1631 break;
1634 #ifdef MCD_DEBUG
1635 for (i = 1; i <= DiskInfo.last; i++)
1636 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1637 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1638 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1639 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1640 for (i = 100; i < 103; i++)
1641 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1642 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1643 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1644 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1645 #endif
1647 return limit > 0 ? 0 : -1;
1651 void __exit mcd_exit(void)
1653 cleanup(3);
1656 #ifdef MODULE
1657 module_init(mcd_init);
1658 #endif
1659 module_exit(mcd_exit);