Revert last change. Bug noticed by Linus.
[linux-2.6/linux-mips.git] / drivers / cdrom / mcd.c
blob0f59831b7b3bd9fcbc0499d5de832ba84ea34169
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(unsigned long dummy);
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 timer_list mcd_timer;
208 static struct cdrom_device_ops mcd_dops = {
209 mcd_open, /* open */
210 mcd_release, /* release */
211 mcd_drive_status, /* drive status */
212 //NULL, /* drive status */
213 mcd_media_changed, /* media changed */
214 mcd_tray_move, /* tray move */
215 NULL, /* lock door */
216 NULL, /* select speed */
217 NULL, /* select disc */
218 NULL, /* get last session */
219 NULL, /* get universal product code */
220 NULL, /* hard reset */
221 mcd_audio_ioctl, /* audio ioctl */
222 NULL, /* device-specific ioctl */
223 CDC_OPEN_TRAY | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO
224 | CDC_DRIVE_STATUS, /* capability */
225 0, /* number of minor devices */
228 static struct cdrom_device_info mcd_info = {
229 &mcd_dops, /* device operations */
230 NULL, /* link */
231 NULL, /* handle */
232 0, /* dev */
233 0, /* mask */
234 2, /* maximum speed */
235 1, /* number of discs */
236 0, /* options, not owned */
237 0, /* mc_flags, not owned */
238 0, /* use count, not owned */
239 "mcd", /* name of the device type */
242 #ifndef MODULE
243 static int __init mcd_setup(char *str)
245 int ints[9];
247 (void)get_options(str, ARRAY_SIZE(ints), ints);
249 if (ints[0] > 0)
250 mcd_port = ints[1];
251 if (ints[0] > 1)
252 mcd_irq = ints[2];
253 #ifdef WORK_AROUND_MITSUMI_BUG_93
254 if (ints[0] > 2)
255 mitsumi_bug_93_wait = ints[3];
256 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
258 return 1;
261 __setup("mcd=", mcd_setup);
263 #endif /* MODULE */
265 static int mcd_media_changed(struct cdrom_device_info * cdi, int disc_nr)
267 int retval;
270 #if 1 /* the below is not reliable */
271 return 0;
272 #endif
274 if (cdi->dev) {
275 printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
276 return 0;
279 retval = mcdDiskChanged;
280 mcdDiskChanged = 0;
282 return retval;
287 * Do a 'get status' command and get the result. Only use from the top half
288 * because it calls 'getMcdStatus' which sleeps.
291 static int
292 statusCmd(void)
294 int st, retry;
296 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
298 outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */
300 st = getMcdStatus(MCD_STATUS_DELAY);
301 if (st != -1)
302 break;
305 return st;
310 * Send a 'Play' command and get the status. Use only from the top half.
313 static int
314 mcdPlay(struct mcd_Play_msf *arg)
316 int retry, st;
318 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
320 sendMcdCmd(MCMD_PLAY_READ, arg);
321 st = getMcdStatus(2 * MCD_STATUS_DELAY);
322 if (st != -1)
323 break;
326 return st;
330 static int
331 mcd_tray_move(struct cdrom_device_info * cdi, int position)
333 int i;
334 if (position) {
335 /* Eject */
336 /* all drives can at least stop! */
337 if (audioStatus == CDROM_AUDIO_PLAY) {
338 outb(MCMD_STOP, MCDPORT(0));
339 i = getMcdStatus(MCD_STATUS_DELAY);
342 audioStatus = CDROM_AUDIO_NO_STATUS;
344 outb(MCMD_EJECT, MCDPORT(0));
346 * the status (i) shows failure on all but the FX drives.
347 * But nothing we can do about that in software!
348 * So just read the status and forget it. - Jon.
350 i = getMcdStatus(MCD_STATUS_DELAY);
351 return 0;
353 else
354 return -EINVAL;
357 long
358 msf2hsg(struct msf *mp)
360 return bcd2bin(mp -> frame)
361 + bcd2bin(mp -> sec) * 75
362 + bcd2bin(mp -> min) * 4500
363 - 150;
367 int mcd_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,
368 void * arg)
370 int i, st;
371 struct mcd_Toc qInfo;
372 struct cdrom_ti *ti;
373 struct cdrom_tochdr *tocHdr;
374 struct cdrom_msf *msf;
375 struct cdrom_subchnl *subchnl;
376 struct cdrom_tocentry *entry;
377 struct mcd_Toc *tocPtr;
378 struct cdrom_volctrl *volctrl;
380 st = statusCmd();
381 if (st < 0)
382 return -EIO;
384 if (!tocUpToDate)
386 i = updateToc();
387 if (i < 0)
388 return i; /* error reading TOC */
391 switch (cmd)
393 case CDROMSTART: /* Spin up the drive */
394 /* Don't think we can do this. Even if we could,
395 * I think the drive times out and stops after a while
396 * anyway. For now, ignore it.
399 return 0;
401 case CDROMSTOP: /* Spin down the drive */
402 outb(MCMD_STOP, MCDPORT(0));
403 i = getMcdStatus(MCD_STATUS_DELAY);
405 /* should we do anything if it fails? */
407 audioStatus = CDROM_AUDIO_NO_STATUS;
408 return 0;
410 case CDROMPAUSE: /* Pause the drive */
411 if (audioStatus != CDROM_AUDIO_PLAY)
412 return -EINVAL;
414 outb(MCMD_STOP, MCDPORT(0));
415 i = getMcdStatus(MCD_STATUS_DELAY);
417 if (GetQChannelInfo(&qInfo) < 0)
419 /* didn't get q channel info */
421 audioStatus = CDROM_AUDIO_NO_STATUS;
422 return 0;
425 mcd_Play.start = qInfo.diskTime; /* remember restart point */
427 audioStatus = CDROM_AUDIO_PAUSED;
428 return 0;
430 case CDROMRESUME: /* Play it again, Sam */
431 if (audioStatus != CDROM_AUDIO_PAUSED)
432 return -EINVAL;
434 /* restart the drive at the saved position. */
436 i = mcdPlay(&mcd_Play);
437 if (i < 0)
439 audioStatus = CDROM_AUDIO_ERROR;
440 return -EIO;
443 audioStatus = CDROM_AUDIO_PLAY;
444 return 0;
446 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
448 ti=(struct cdrom_ti *) arg;
450 if (ti->cdti_trk0 < DiskInfo.first
451 || ti->cdti_trk0 > DiskInfo.last
452 || ti->cdti_trk1 < ti->cdti_trk0)
454 return -EINVAL;
457 if (ti->cdti_trk1 > DiskInfo.last)
458 ti->cdti_trk1 = DiskInfo.last;
460 mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
461 mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
463 #ifdef MCD_DEBUG
464 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
465 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
466 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
467 #endif
469 i = mcdPlay(&mcd_Play);
470 if (i < 0)
472 audioStatus = CDROM_AUDIO_ERROR;
473 return -EIO;
476 audioStatus = CDROM_AUDIO_PLAY;
477 return 0;
479 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
481 if (audioStatus == CDROM_AUDIO_PLAY) {
482 outb(MCMD_STOP, MCDPORT(0));
483 i = getMcdStatus(MCD_STATUS_DELAY);
484 audioStatus = CDROM_AUDIO_NO_STATUS;
487 msf=(struct cdrom_msf *) arg;
489 /* convert to bcd */
491 bin2bcd(&msf->cdmsf_min0);
492 bin2bcd(&msf->cdmsf_sec0);
493 bin2bcd(&msf->cdmsf_frame0);
494 bin2bcd(&msf->cdmsf_min1);
495 bin2bcd(&msf->cdmsf_sec1);
496 bin2bcd(&msf->cdmsf_frame1);
498 mcd_Play.start.min = msf->cdmsf_min0;
499 mcd_Play.start.sec = msf->cdmsf_sec0;
500 mcd_Play.start.frame = msf->cdmsf_frame0;
501 mcd_Play.end.min = msf->cdmsf_min1;
502 mcd_Play.end.sec = msf->cdmsf_sec1;
503 mcd_Play.end.frame = msf->cdmsf_frame1;
505 #ifdef MCD_DEBUG
506 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
507 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
508 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
509 #endif
511 i = mcdPlay(&mcd_Play);
512 if (i < 0)
514 audioStatus = CDROM_AUDIO_ERROR;
515 return -EIO;
518 audioStatus = CDROM_AUDIO_PLAY;
519 return 0;
521 case CDROMREADTOCHDR: /* Read the table of contents header */
522 tocHdr=(struct cdrom_tochdr *) arg;
523 tocHdr->cdth_trk0 = DiskInfo.first;
524 tocHdr->cdth_trk1 = DiskInfo.last;
525 return 0;
527 case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
528 entry=(struct cdrom_tocentry *) arg;
529 if (entry->cdte_track == CDROM_LEADOUT)
530 tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
532 else if (entry->cdte_track > DiskInfo.last
533 || entry->cdte_track < DiskInfo.first)
534 return -EINVAL;
536 else
537 tocPtr = &Toc[entry->cdte_track];
539 entry->cdte_adr = tocPtr -> ctrl_addr;
540 entry->cdte_ctrl = tocPtr -> ctrl_addr >> 4;
542 if (entry->cdte_format == CDROM_LBA)
543 entry->cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
545 else if (entry->cdte_format == CDROM_MSF)
547 entry->cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
548 entry->cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
549 entry->cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
552 else
553 return -EINVAL;
555 return 0;
557 case CDROMSUBCHNL: /* Get subchannel info */
559 subchnl=(struct cdrom_subchnl *) arg;
560 if (GetQChannelInfo(&qInfo) < 0)
561 return -EIO;
563 subchnl->cdsc_audiostatus = audioStatus;
564 subchnl->cdsc_adr = qInfo.ctrl_addr;
565 subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
566 subchnl->cdsc_trk = bcd2bin(qInfo.track);
567 subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
568 subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
569 subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
570 subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
571 subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
572 subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
573 subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
574 return(0);
576 case CDROMVOLCTRL: /* Volume control */
577 volctrl=(struct cdrom_volctrl *) arg;
578 outb(MCMD_SET_VOLUME, MCDPORT(0));
579 outb(volctrl->channel0, MCDPORT(0));
580 outb(255, MCDPORT(0));
581 outb(volctrl->channel1, MCDPORT(0));
582 outb(255, MCDPORT(0));
584 i = getMcdStatus(MCD_STATUS_DELAY);
585 if (i < 0)
586 return -EIO;
589 char a, b, c, d;
591 getValue(&a);
592 getValue(&b);
593 getValue(&c);
594 getValue(&d);
597 return 0;
599 default:
600 return -EINVAL;
605 * Take care of the different block sizes between cdrom and Linux.
606 * When Linux gets variable block sizes this will probably go away.
609 static void
610 mcd_transfer(void)
612 if (CURRENT_VALID) {
613 while (CURRENT -> nr_sectors) {
614 int bn = CURRENT -> sector / 4;
615 int i;
616 for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
618 if (i < MCD_BUF_SIZ) {
619 int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
620 int nr_sectors = 4 - (CURRENT -> sector & 3);
621 if (mcd_buf_out != i) {
622 mcd_buf_out = i;
623 if (mcd_buf_bn[i] != bn) {
624 mcd_buf_out = -1;
625 continue;
628 if (nr_sectors > CURRENT -> nr_sectors)
629 nr_sectors = CURRENT -> nr_sectors;
630 memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512);
631 CURRENT -> nr_sectors -= nr_sectors;
632 CURRENT -> sector += nr_sectors;
633 CURRENT -> buffer += nr_sectors * 512;
634 } else {
635 mcd_buf_out = -1;
636 break;
644 * We only seem to get interrupts after an error.
645 * Just take the interrupt and clear out the status reg.
648 static void
649 mcd_interrupt(int irq, void *dev_id, struct pt_regs * regs)
651 int st;
653 st = inb(MCDPORT(1)) & 0xFF;
654 #ifdef TEST1
655 printk("<int1-%02X>", st);
656 #endif
657 if (!(st & MFL_STATUS))
659 st = inb(MCDPORT(0)) & 0xFF;
660 #ifdef TEST1
661 printk("<int0-%02X>", st);
662 #endif
663 if ((st & 0xFF) != 0xFF)
664 mcd_error = st ? st & 0xFF : -1;
669 static void
670 do_mcd_request(request_queue_t * q)
672 #ifdef TEST2
673 printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
674 #endif
675 mcd_transfer_is_active = 1;
676 while (CURRENT_VALID) {
677 if (CURRENT->bh) {
678 if (!buffer_locked(CURRENT->bh))
679 panic(DEVICE_NAME ": block not locked");
681 mcd_transfer();
682 if (CURRENT -> nr_sectors == 0) {
683 end_request(1);
684 } else {
685 mcd_buf_out = -1; /* Want to read a block not in buffer */
686 if (mcd_state == MCD_S_IDLE) {
687 if (!tocUpToDate) {
688 if (updateToc() < 0) {
689 while (CURRENT_VALID)
690 end_request(0);
691 break;
694 mcd_state = MCD_S_START;
695 McdTries = 5;
696 SET_TIMER(mcd_poll, 1);
698 break;
701 mcd_transfer_is_active = 0;
702 #ifdef TEST2
703 printk(" do_mcd_request ends\n");
704 #endif
709 static void
710 mcd_poll(unsigned long dummy)
712 int st;
715 if (mcd_error)
717 if (mcd_error & 0xA5)
719 printk("mcd: I/O error 0x%02x", mcd_error);
720 if (mcd_error & 0x80)
721 printk(" (Door open)");
722 if (mcd_error & 0x20)
723 printk(" (Disk changed)");
724 if (mcd_error & 0x04)
726 printk(" (Read error)"); /* Bitch about the problem. */
728 /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
729 /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
730 /* But I find that rather HANDY!!! */
731 /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
732 /* AJK [06/17/95] */
734 /* Slap the CD down to single speed! */
735 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ)
737 MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
738 mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
739 printk(" Speed now 1x"); /* Pull my finger! */
742 printk("\n");
743 mcd_invalidate_buffers();
744 #ifdef WARN_IF_READ_FAILURE
745 if (McdTries == MCD_RETRY_ATTEMPTS)
746 printk("mcd: read of block %d failed\n", mcd_next_bn);
747 #endif
748 if (!McdTries--)
750 /* Nuts! This cd is ready for recycling! */
751 /* When WAS the last time YOU cleaned it CORRECTLY?! */
752 printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
753 if (mcd_transfer_is_active)
755 McdTries = 0;
756 goto ret;
758 if (CURRENT_VALID)
759 end_request(0);
760 McdTries = MCD_RETRY_ATTEMPTS;
763 mcd_error = 0;
764 mcd_state = MCD_S_STOP;
766 /* Switch back to Double speed if enough GOOD sectors were read! */
768 /* Are we a double speed with a crappy CD?! */
769 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ)
771 /* We ARE a double speed and we ARE bitching! */
772 if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */
773 { /* We need to switch back to double speed now... */
774 MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
775 printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
777 else mcd1xhold--; /* No?! Count down the good reads some more... */
778 /* and try, try again! */
783 immediately:
784 switch (mcd_state) {
788 case MCD_S_IDLE:
789 #ifdef TEST3
790 printk("MCD_S_IDLE\n");
791 #endif
792 goto out;
796 case MCD_S_START:
797 #ifdef TEST3
798 printk("MCD_S_START\n");
799 #endif
801 outb(MCMD_GET_STATUS, MCDPORT(0));
802 mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
803 McdTimeout = 3000;
804 break;
808 case MCD_S_MODE:
809 #ifdef TEST3
810 printk("MCD_S_MODE\n");
811 #endif
813 if ((st = mcdStatus()) != -1) {
815 if (st & MST_DSK_CHG) {
816 mcdDiskChanged = 1;
817 tocUpToDate = 0;
818 mcd_invalidate_buffers();
821 set_mode_immediately:
823 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
824 mcdDiskChanged = 1;
825 tocUpToDate = 0;
826 if (mcd_transfer_is_active) {
827 mcd_state = MCD_S_START;
828 goto immediately;
830 printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
831 mcd_state = MCD_S_IDLE;
832 while (CURRENT_VALID)
833 end_request(0);
834 goto out;
837 outb(MCMD_SET_MODE, MCDPORT(0));
838 outb(1, MCDPORT(0));
839 mcd_mode = 1;
840 mcd_state = MCD_S_READ;
841 McdTimeout = 3000;
844 break;
848 case MCD_S_READ:
849 #ifdef TEST3
850 printk("MCD_S_READ\n");
851 #endif
853 if ((st = mcdStatus()) != -1) {
855 if (st & MST_DSK_CHG) {
856 mcdDiskChanged = 1;
857 tocUpToDate = 0;
858 mcd_invalidate_buffers();
861 read_immediately:
863 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
864 mcdDiskChanged = 1;
865 tocUpToDate = 0;
866 if (mcd_transfer_is_active) {
867 mcd_state = MCD_S_START;
868 goto immediately;
870 printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
871 mcd_state = MCD_S_IDLE;
872 while (CURRENT_VALID)
873 end_request(0);
874 goto out;
877 if (CURRENT_VALID) {
878 struct mcd_Play_msf msf;
879 mcd_next_bn = CURRENT -> sector / 4;
880 hsg2msf(mcd_next_bn, &msf.start);
881 msf.end.min = ~0;
882 msf.end.sec = ~0;
883 msf.end.frame = ~0;
884 sendMcdCmd(MCMD_DATA_READ, &msf);
885 mcd_state = MCD_S_DATA;
886 McdTimeout = READ_TIMEOUT;
887 } else {
888 mcd_state = MCD_S_STOP;
889 goto immediately;
893 break;
896 case MCD_S_DATA:
897 #ifdef TEST3
898 printk("MCD_S_DATA\n");
899 #endif
901 st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
902 data_immediately:
903 #ifdef TEST5
904 printk("Status %02x\n",st);
905 #endif
906 switch (st) {
908 case MFL_DATA:
909 #ifdef WARN_IF_READ_FAILURE
910 if (McdTries == 5)
911 printk("mcd: read of block %d failed\n", mcd_next_bn);
912 #endif
913 if (!McdTries--) {
914 printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
915 if (mcd_transfer_is_active) {
916 McdTries = 0;
917 break;
919 if (CURRENT_VALID)
920 end_request(0);
921 McdTries = 5;
923 mcd_state = MCD_S_START;
924 McdTimeout = READ_TIMEOUT;
925 goto immediately;
927 case MFL_STATUSorDATA:
928 break;
930 default:
931 McdTries = 5;
932 if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
933 mcd_state = MCD_S_STOP;
934 goto immediately;
936 mcd_buf_bn[mcd_buf_in] = -1;
937 READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
938 mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
939 if (mcd_buf_out == -1)
940 mcd_buf_out = mcd_buf_in;
941 mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
942 if (!mcd_transfer_is_active) {
943 while (CURRENT_VALID) {
944 mcd_transfer();
945 if (CURRENT -> nr_sectors == 0)
946 end_request(1);
947 else
948 break;
952 if (CURRENT_VALID
953 && (CURRENT -> sector / 4 < mcd_next_bn ||
954 CURRENT -> sector / 4 > mcd_next_bn + 16)) {
955 mcd_state = MCD_S_STOP;
956 goto immediately;
958 McdTimeout = READ_TIMEOUT;
959 #ifdef DOUBLE_QUICK_ONLY
960 if (MCMD_DATA_READ != MCMD_PLAY_READ)
961 #endif
963 int count= QUICK_LOOP_COUNT;
964 while (count--) {
965 QUICK_LOOP_DELAY;
966 if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
967 # ifdef TEST4
968 /* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
969 printk(" %d ",QUICK_LOOP_COUNT-count);
970 # endif
971 goto data_immediately;
974 # ifdef TEST4
975 /* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
976 printk("ended ");
977 # endif
979 break;
981 break;
985 case MCD_S_STOP:
986 #ifdef TEST3
987 printk("MCD_S_STOP\n");
988 #endif
990 #ifdef WORK_AROUND_MITSUMI_BUG_93
991 if (!mitsumi_bug_93_wait)
992 goto do_not_work_around_mitsumi_bug_93_1;
994 McdTimeout = mitsumi_bug_93_wait;
995 mcd_state = 9+3+1;
996 break;
998 case 9+3+1:
999 if (McdTimeout)
1000 break;
1002 do_not_work_around_mitsumi_bug_93_1:
1003 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
1005 outb(MCMD_STOP, MCDPORT(0));
1007 #ifdef WORK_AROUND_MITSUMI_BUG_92
1008 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1009 int i = 4096;
1010 do {
1011 inb(MCDPORT(0));
1012 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1013 outb(MCMD_STOP, MCDPORT(0));
1014 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1015 i = 4096;
1016 do {
1017 inb(MCDPORT(0));
1018 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1019 outb(MCMD_STOP, MCDPORT(0));
1022 #endif /* WORK_AROUND_MITSUMI_BUG_92 */
1024 mcd_state = MCD_S_STOPPING;
1025 McdTimeout = 1000;
1026 break;
1028 case MCD_S_STOPPING:
1029 #ifdef TEST3
1030 printk("MCD_S_STOPPING\n");
1031 #endif
1033 if ((st = mcdStatus()) == -1 && McdTimeout)
1034 break;
1036 if ((st != -1) && (st & MST_DSK_CHG)) {
1037 mcdDiskChanged = 1;
1038 tocUpToDate = 0;
1039 mcd_invalidate_buffers();
1042 #ifdef WORK_AROUND_MITSUMI_BUG_93
1043 if (!mitsumi_bug_93_wait)
1044 goto do_not_work_around_mitsumi_bug_93_2;
1046 McdTimeout = mitsumi_bug_93_wait;
1047 mcd_state = 9+3+2;
1048 break;
1050 case 9+3+2:
1051 if (McdTimeout)
1052 break;
1054 st = -1;
1056 do_not_work_around_mitsumi_bug_93_2:
1057 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
1059 #ifdef TEST3
1060 printk("CURRENT_VALID %d mcd_mode %d\n",
1061 CURRENT_VALID, mcd_mode);
1062 #endif
1064 if (CURRENT_VALID) {
1065 if (st != -1) {
1066 if (mcd_mode == 1)
1067 goto read_immediately;
1068 else
1069 goto set_mode_immediately;
1070 } else {
1071 mcd_state = MCD_S_START;
1072 McdTimeout = 1;
1074 } else {
1075 mcd_state = MCD_S_IDLE;
1076 goto out;
1078 break;
1080 default:
1081 printk("mcd: invalid state %d\n", mcd_state);
1082 goto out;
1085 ret:
1086 if (!McdTimeout--) {
1087 printk("mcd: timeout in state %d\n", mcd_state);
1088 mcd_state = MCD_S_STOP;
1091 SET_TIMER(mcd_poll, 1);
1092 out:
1093 return;
1098 static void
1099 mcd_invalidate_buffers(void)
1101 int i;
1102 for (i = 0; i < MCD_BUF_SIZ; ++i)
1103 mcd_buf_bn[i] = -1;
1104 mcd_buf_out = -1;
1109 * Open the device special file. Check that a disk is in.
1111 static int mcd_open(struct cdrom_device_info * cdi, int purpose)
1113 int st, count=0;
1114 if (mcdPresent == 0)
1115 return -ENXIO; /* no hardware */
1117 MOD_INC_USE_COUNT;
1119 if (mcd_open_count || mcd_state != MCD_S_IDLE)
1120 goto bump_count;
1122 mcd_invalidate_buffers();
1123 do {
1124 st = statusCmd(); /* check drive status */
1125 if (st == -1)
1126 goto err_out; /* drive doesn't respond */
1127 if ((st & MST_READY) == 0) { /* no disk? wait a sec... */
1128 current->state = TASK_INTERRUPTIBLE;
1129 schedule_timeout(HZ);
1131 } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1133 if (updateToc() < 0)
1134 goto err_out;
1136 bump_count:
1137 ++mcd_open_count;
1138 return 0;
1140 err_out:
1141 MOD_DEC_USE_COUNT;
1142 return -EIO;
1147 * On close, we flush all mcd blocks from the buffer cache.
1149 static void mcd_release(struct cdrom_device_info * cdi)
1150 { MOD_DEC_USE_COUNT;
1151 if (!--mcd_open_count) {
1152 mcd_invalidate_buffers();
1158 /* This routine gets called during initialization if things go wrong,
1159 * and is used in mcd_exit as well. */
1160 static void cleanup(int level)
1162 switch (level) {
1163 case 3:
1164 if (unregister_cdrom(&mcd_info)) {
1165 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1166 return;
1168 free_irq(mcd_irq, NULL);
1169 case 2:
1170 release_region(mcd_port,4);
1171 case 1:
1172 if (devfs_unregister_blkdev(MAJOR_NR, "mcd")) {
1173 printk(KERN_WARNING "Can't unregister major mcd\n");
1174 return;
1176 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1177 default:
1184 * Test for presence of drive and initialize it. Called at boot time.
1187 int __init mcd_init(void)
1189 int count;
1190 unsigned char result[3];
1191 char msg[80];
1193 if (mcd_port <= 0 || mcd_irq <= 0) {
1194 printk("skip mcd_init\n");
1195 return -EIO;
1198 if (devfs_register_blkdev(MAJOR_NR, "mcd", &cdrom_fops) != 0)
1200 printk("Unable to get major %d for Mitsumi CD-ROM\n",
1201 MAJOR_NR);
1202 return -EIO;
1204 if (check_region(mcd_port, 4)) {
1205 cleanup(1);
1206 printk("Init failed, I/O port (%X) already in use\n",
1207 mcd_port);
1208 return -EIO;
1211 blksize_size[MAJOR_NR] = mcd_blocksizes;
1212 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1213 read_ahead[MAJOR_NR] = 4;
1215 /* check for card */
1217 outb(0, MCDPORT(1)); /* send reset */
1218 for (count = 0; count < 2000000; count++)
1219 (void) inb(MCDPORT(1)); /* delay a bit */
1221 outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1222 for (count = 0; count < 2000000; count++)
1223 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1224 break;
1226 if (count >= 2000000) {
1227 printk("Init failed. No mcd device at 0x%x irq %d\n",
1228 mcd_port, mcd_irq);
1229 cleanup(1);
1230 return -EIO;
1232 count = inb(MCDPORT(0)); /* pick up the status */
1234 outb(MCMD_GET_VERSION,MCDPORT(0));
1235 for(count=0;count<3;count++)
1236 if(getValue(result+count)) {
1237 printk("mitsumi get version failed at 0x%d\n",
1238 mcd_port);
1239 cleanup(1);
1240 return -EIO;
1243 if (result[0] == result[1] && result[1] == result[2]) {
1244 cleanup(1);
1245 return -EIO;
1248 mcdVersion=result[2];
1250 if (mcdVersion >=4)
1251 outb(4,MCDPORT(2)); /* magic happens */
1253 /* don't get the IRQ until we know for sure the drive is there */
1255 if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL))
1257 printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1258 cleanup(1);
1259 return -EIO;
1262 if (result[1] == 'D')
1264 MCMD_DATA_READ = MCMD_2X_READ;
1265 /* Added flag to drop to 1x speed if too many errors */
1266 mcdDouble = 1;
1267 } else
1268 mcd_info.speed = 1;
1269 sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1270 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double", mcd_port, mcd_irq);
1272 request_region(mcd_port, 4, "mcd");
1274 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1275 outb(0x02,MCDPORT(0));
1276 outb(0x00,MCDPORT(0));
1277 getValue(result);
1279 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1280 outb(0x10,MCDPORT(0));
1281 outb(0x04,MCDPORT(0));
1282 getValue(result);
1284 mcd_invalidate_buffers();
1285 mcdPresent = 1;
1287 mcd_info.dev = MKDEV(MAJOR_NR,0);
1289 if (register_cdrom(&mcd_info) != 0) {
1290 printk("Cannot register Mitsumi CD-ROM!\n");
1291 cleanup(3);
1292 return -EIO;
1294 printk(msg);
1296 return 0;
1300 static void
1301 hsg2msf(long hsg, struct msf *msf)
1303 hsg += 150;
1304 msf -> min = hsg / 4500;
1305 hsg %= 4500;
1306 msf -> sec = hsg / 75;
1307 msf -> frame = hsg % 75;
1309 bin2bcd(&msf -> min); /* convert to BCD */
1310 bin2bcd(&msf -> sec);
1311 bin2bcd(&msf -> frame);
1315 static void
1316 bin2bcd(unsigned char *p)
1318 int u, t;
1320 u = *p % 10;
1321 t = *p / 10;
1322 *p = u | (t << 4);
1325 static int
1326 bcd2bin(unsigned char bcd)
1328 return (bcd >> 4) * 10 + (bcd & 0xF);
1333 * See if a status is ready from the drive and return it
1334 * if it is ready.
1337 static int
1338 mcdStatus(void)
1340 int i;
1341 int st;
1343 st = inb(MCDPORT(1)) & MFL_STATUS;
1344 if (!st)
1346 i = inb(MCDPORT(0)) & 0xFF;
1347 return i;
1349 else
1350 return -1;
1355 * Send a play or read command to the drive
1358 static void
1359 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1361 outb(cmd, MCDPORT(0));
1362 outb(params -> start.min, MCDPORT(0));
1363 outb(params -> start.sec, MCDPORT(0));
1364 outb(params -> start.frame, MCDPORT(0));
1365 outb(params -> end.min, MCDPORT(0));
1366 outb(params -> end.sec, MCDPORT(0));
1367 outb(params -> end.frame, MCDPORT(0));
1372 * Timer interrupt routine to test for status ready from the drive.
1373 * (see the next routine)
1376 static void
1377 mcdStatTimer(unsigned long dummy)
1379 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1381 wake_up(&mcd_waitq);
1382 return;
1385 McdTimeout--;
1386 if (McdTimeout <= 0)
1388 wake_up(&mcd_waitq);
1389 return;
1392 SET_TIMER(mcdStatTimer, 1);
1397 * Wait for a status to be returned from the drive. The actual test
1398 * (see routine above) is done by the timer interrupt to avoid
1399 * excessive rescheduling.
1402 static int
1403 getMcdStatus(int timeout)
1405 int st;
1407 McdTimeout = timeout;
1408 SET_TIMER(mcdStatTimer, 1);
1409 sleep_on(&mcd_waitq);
1410 if (McdTimeout <= 0)
1411 return -1;
1413 st = inb(MCDPORT(0)) & 0xFF;
1414 if (st == 0xFF)
1415 return -1;
1417 if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1418 /* XXX might be an error? look at q-channel? */
1419 audioStatus = CDROM_AUDIO_COMPLETED;
1421 if (st & MST_DSK_CHG)
1423 mcdDiskChanged = 1;
1424 tocUpToDate = 0;
1425 audioStatus = CDROM_AUDIO_NO_STATUS;
1428 return st;
1432 /* gives current state of the drive This function is quite unreliable,
1433 and should probably be rewritten by someone, eventually... */
1434 int mcd_drive_status(struct cdrom_device_info * cdi, int slot_nr)
1436 int st;
1438 st = statusCmd(); /* check drive status */
1439 if (st == -1)
1440 return -EIO; /* drive doesn't respond */
1441 if ((st & MST_READY)) return CDS_DISC_OK;
1442 if ((st & MST_DOOR_OPEN)) return CDS_TRAY_OPEN;
1443 if ((st & MST_DSK_CHG)) return CDS_NO_DISC;
1444 if ((st & MST_BUSY)) return CDS_DRIVE_NOT_READY;
1445 return -EIO;
1450 * Read a value from the drive.
1453 static int
1454 getValue(unsigned char *result)
1456 int count;
1457 int s;
1459 for (count = 0; count < 2000; count++)
1460 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1461 break;
1463 if (count >= 2000)
1465 printk("mcd: getValue timeout\n");
1466 return -1;
1469 s = inb(MCDPORT(0)) & 0xFF;
1470 *result = (unsigned char) s;
1471 return 0;
1476 * Read the current Q-channel info. Also used for reading the
1477 * table of contents.
1481 GetQChannelInfo(struct mcd_Toc *qp)
1483 unsigned char notUsed;
1484 int retry;
1486 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1488 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1489 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1490 break;
1493 if (retry >= MCD_RETRY_ATTEMPTS)
1494 return -1;
1496 if (getValue(&qp -> ctrl_addr) < 0) return -1;
1497 if (getValue(&qp -> track) < 0) return -1;
1498 if (getValue(&qp -> pointIndex) < 0) return -1;
1499 if (getValue(&qp -> trackTime.min) < 0) return -1;
1500 if (getValue(&qp -> trackTime.sec) < 0) return -1;
1501 if (getValue(&qp -> trackTime.frame) < 0) return -1;
1502 if (getValue(&notUsed) < 0) return -1;
1503 if (getValue(&qp -> diskTime.min) < 0) return -1;
1504 if (getValue(&qp -> diskTime.sec) < 0) return -1;
1505 if (getValue(&qp -> diskTime.frame) < 0) return -1;
1507 return 0;
1512 * Read the table of contents (TOC) and TOC header if necessary
1515 static int
1516 updateToc()
1518 if (tocUpToDate)
1519 return 0;
1521 if (GetDiskInfo() < 0)
1522 return -EIO;
1524 if (GetToc() < 0)
1525 return -EIO;
1527 tocUpToDate = 1;
1528 return 0;
1533 * Read the table of contents header
1536 static int
1537 GetDiskInfo()
1539 int retry;
1541 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1543 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1544 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1545 break;
1548 if (retry >= MCD_RETRY_ATTEMPTS)
1549 return -1;
1551 if (getValue(&DiskInfo.first) < 0) return -1;
1552 if (getValue(&DiskInfo.last) < 0) return -1;
1554 DiskInfo.first = bcd2bin(DiskInfo.first);
1555 DiskInfo.last = bcd2bin(DiskInfo.last);
1557 #ifdef MCD_DEBUG
1558 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1559 DiskInfo.first,
1560 DiskInfo.last,
1561 DiskInfo.diskLength.min,
1562 DiskInfo.diskLength.sec,
1563 DiskInfo.diskLength.frame,
1564 DiskInfo.firstTrack.min,
1565 DiskInfo.firstTrack.sec,
1566 DiskInfo.firstTrack.frame);
1567 #endif
1569 if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1570 if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1571 if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1572 if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1573 if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1574 if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1576 return 0;
1581 * Read the table of contents (TOC)
1584 static int
1585 GetToc()
1587 int i, px;
1588 int limit;
1589 int retry;
1590 struct mcd_Toc qInfo;
1592 for (i = 0; i < MAX_TRACKS; i++)
1593 Toc[i].pointIndex = 0;
1595 i = DiskInfo.last + 3;
1597 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1599 outb(MCMD_STOP, MCDPORT(0));
1600 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1601 break;
1604 if (retry >= MCD_RETRY_ATTEMPTS)
1605 return -1;
1607 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1609 outb(MCMD_SET_MODE, MCDPORT(0));
1610 outb(0x05, MCDPORT(0)); /* mode: toc */
1611 mcd_mode = 0x05;
1612 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1613 break;
1616 if (retry >= MCD_RETRY_ATTEMPTS)
1617 return -1;
1619 for (limit = 300; limit > 0; limit--)
1621 if (GetQChannelInfo(&qInfo) < 0)
1622 break;
1624 px = bcd2bin(qInfo.pointIndex);
1625 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1626 if (Toc[px].pointIndex == 0)
1628 Toc[px] = qInfo;
1629 i--;
1632 if (i <= 0)
1633 break;
1636 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1638 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1640 outb(MCMD_SET_MODE, MCDPORT(0));
1641 outb(0x01, MCDPORT(0));
1642 mcd_mode = 1;
1643 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1644 break;
1647 #ifdef MCD_DEBUG
1648 for (i = 1; i <= DiskInfo.last; i++)
1649 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1650 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1651 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1652 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1653 for (i = 100; i < 103; i++)
1654 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1655 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1656 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1657 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1658 #endif
1660 return limit > 0 ? 0 : -1;
1664 void __exit mcd_exit(void)
1666 cleanup(3);
1667 del_timer_sync(&mcd_timer);
1670 #ifdef MODULE
1671 module_init(mcd_init);
1672 #endif
1673 module_exit(mcd_exit);