Hopefully get the Kconfig PCI stuff right, finally.
[linux-2.6/linux-mips.git] / drivers / cdrom / mcd.c
blob5d538e645d1593782e2fc2faa6a6493cee0e2f11
1 /*
2 linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
4 Copyright (C) 1992 Martin Harriss
5 Portions Copyright (C) 2001 Red Hat
7 martin@bdsi.com (no longer valid - where are you now, Martin?)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 HISTORY
25 0.1 First attempt - internal use only
26 0.2 Cleaned up delays and use of timer - alpha release
27 0.3 Audio support added
28 0.3.1 Changes for mitsumi CRMC LU005S march version
29 (stud11@cc4.kuleuven.ac.be)
30 0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
31 (Jon Tombs <jon@robots.ox.ac.uk>)
32 0.3.3 Added more #defines and mcd_setup()
33 (Jon Tombs <jon@gtex02.us.es>)
35 October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
36 Braunschweig, Germany: rework to speed up data read operation.
37 Also enabled definition of irq and address from bootstrap, using the
38 environment.
39 November 93 added code for FX001 S,D (single & double speed).
40 February 94 added code for broken M 5/6 series of 16-bit single speed.
43 0.4
44 Added support for loadable MODULEs, so mcd can now also be loaded by
45 insmod and removed by rmmod during runtime.
46 Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
48 0.5
49 I added code for FX001 D to drop from double speed to single speed
50 when encountering errors... this helps with some "problematic" CD's
51 that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
52 severely scratched, or possibly slightly warped! I have noticed that
53 the Mitsumi 2x/4x drives are just less tolerant and the firmware is
54 not smart enough to drop speed, so let's just kludge it with software!
55 ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
56 Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
57 even WORSE! ;)
58 ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
59 certain "large" CD's that have data on the outside edge in your
60 DOS DRIVERS .... Accuracy counts... speed is secondary ;)
61 17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
62 07 July 1995 Modifications by Andrew J. Kroll
64 Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
66 Michael K. Johnson <johnsonm@redhat.com> added retries on open
67 for slow drives which take a while to recognize that they contain
68 a CD.
70 November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
71 March 1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
73 November 1999 -- Make kernel-parameter implementation work with 2.3.x
74 Removed init_module & cleanup_module in favor of
75 module_init & module_exit.
76 Torben Mathiasen <tmm@image.dk>
78 September 2001 - Reformatted and cleaned up the code
79 Alan Cox <alan@redhat.com>
82 #include <linux/module.h>
84 #include <linux/errno.h>
85 #include <linux/interrupt.h>
86 #include <linux/signal.h>
87 #include <linux/mm.h>
88 #include <linux/timer.h>
89 #include <linux/fs.h>
90 #include <linux/kernel.h>
91 #include <linux/devfs_fs_kernel.h>
92 #include <linux/cdrom.h>
93 #include <linux/ioport.h>
94 #include <linux/string.h>
95 #include <linux/delay.h>
96 #include <linux/init.h>
97 #include <linux/config.h>
99 /* #define REALLY_SLOW_IO */
100 #include <asm/system.h>
101 #include <asm/io.h>
102 #include <asm/current.h>
103 #include <asm/uaccess.h>
104 #include <linux/blk.h>
106 #define mcd_port mcd /* for compatible parameter passing with "insmod" */
107 #include "mcd.h"
109 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
110 static int mcdDouble;
112 /* How many sectors to hold at 1x speed counter */
113 static int mcd1xhold;
115 /* Is the drive connected properly and responding?? */
116 static int mcdPresent;
117 static struct request_queue mcd_queue;
119 #define MAJOR_NR MITSUMI_CDROM_MAJOR
120 #define QUEUE (&mcd_queue)
121 #define CURRENT elv_next_request(&mcd_queue)
123 #define QUICK_LOOP_DELAY udelay(45) /* use udelay */
124 #define QUICK_LOOP_COUNT 20
126 static int current_valid(void)
128 return CURRENT &&
129 CURRENT->cmd == READ &&
130 CURRENT->sector != -1;
133 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
134 #define MCD_BUF_SIZ 16
135 static volatile int mcd_transfer_is_active;
136 static char mcd_buf[2048 * MCD_BUF_SIZ]; /* buffer for block size conversion */
137 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
138 static volatile int mcd_buf_in, mcd_buf_out = -1;
139 static volatile int mcd_error;
140 static int mcd_open_count;
141 enum mcd_state_e {
142 MCD_S_IDLE, /* 0 */
143 MCD_S_START, /* 1 */
144 MCD_S_MODE, /* 2 */
145 MCD_S_READ, /* 3 */
146 MCD_S_DATA, /* 4 */
147 MCD_S_STOP, /* 5 */
148 MCD_S_STOPPING /* 6 */
150 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
151 static int mcd_mode = -1;
152 static int MCMD_DATA_READ = MCMD_PLAY_READ;
154 #define READ_TIMEOUT 3000
156 int mitsumi_bug_93_wait;
158 static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
159 static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
160 MODULE_PARM(mcd, "1-2i");
162 static int McdTimeout, McdTries;
163 static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
165 static struct mcd_DiskInfo DiskInfo;
166 static struct mcd_Toc Toc[MAX_TRACKS];
167 static struct mcd_Play_msf mcd_Play;
169 static int audioStatus;
170 static char mcdDiskChanged;
171 static char tocUpToDate;
172 static char mcdVersion;
174 static void mcd_transfer(void);
175 static void mcd_poll(unsigned long dummy);
176 static void mcd_invalidate_buffers(void);
177 static void hsg2msf(long hsg, struct msf *msf);
178 static void bin2bcd(unsigned char *p);
179 static int bcd2bin(unsigned char bcd);
180 static int mcdStatus(void);
181 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
182 static int getMcdStatus(int timeout);
183 static int GetQChannelInfo(struct mcd_Toc *qp);
184 static int updateToc(void);
185 static int GetDiskInfo(void);
186 static int GetToc(void);
187 static int getValue(unsigned char *result);
188 static int mcd_open(struct cdrom_device_info *cdi, int purpose);
189 static void mcd_release(struct cdrom_device_info *cdi);
190 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
191 static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
192 static spinlock_t mcd_spinlock = SPIN_LOCK_UNLOCKED;
193 static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
194 void *arg);
195 static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
197 static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
199 static struct cdrom_device_ops mcd_dops = {
200 .open = mcd_open,
201 .release = mcd_release,
202 .drive_status = mcd_drive_status,
203 .media_changed = mcd_media_changed,
204 .tray_move = mcd_tray_move,
205 .audio_ioctl = mcd_audio_ioctl,
206 .capability = CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
207 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
210 static struct cdrom_device_info mcd_info = {
211 .ops = &mcd_dops,
212 .speed = 2,
213 .capacity = 1,
214 .name = "mcd",
217 static int mcd_block_open(struct inode *inode, struct file *file)
219 return cdrom_open(&mcd_info, inode, file);
222 static int mcd_block_release(struct inode *inode, struct file *file)
224 return cdrom_release(&mcd_info, file);
227 static int mcd_block_ioctl(struct inode *inode, struct file *file,
228 unsigned cmd, unsigned long arg)
230 return cdrom_ioctl(&mcd_info, inode, cmd, arg);
233 static int mcd_block_media_changed(struct gendisk *disk)
235 return cdrom_media_changed(&mcd_info);
238 static struct block_device_operations mcd_bdops =
240 .owner = THIS_MODULE,
241 .open = mcd_block_open,
242 .release = mcd_block_release,
243 .ioctl = mcd_block_ioctl,
244 .media_changed = mcd_block_media_changed,
247 static struct gendisk *mcd_gendisk;
249 #ifndef MODULE
250 static int __init mcd_setup(char *str)
252 int ints[9];
254 (void) get_options(str, ARRAY_SIZE(ints), ints);
256 if (ints[0] > 0)
257 mcd_port = ints[1];
258 if (ints[0] > 1)
259 mcd_irq = ints[2];
260 if (ints[0] > 2)
261 mitsumi_bug_93_wait = ints[3];
263 return 1;
266 __setup("mcd=", mcd_setup);
268 #endif /* MODULE */
270 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
272 return 0;
277 * Do a 'get status' command and get the result. Only use from the top half
278 * because it calls 'getMcdStatus' which sleeps.
281 static int statusCmd(void)
283 int st = -1, retry;
285 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
286 /* send get-status cmd */
287 outb(MCMD_GET_STATUS, MCDPORT(0));
289 st = getMcdStatus(MCD_STATUS_DELAY);
290 if (st != -1)
291 break;
294 return st;
299 * Send a 'Play' command and get the status. Use only from the top half.
302 static int mcdPlay(struct mcd_Play_msf *arg)
304 int retry, st = -1;
306 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
307 sendMcdCmd(MCMD_PLAY_READ, arg);
308 st = getMcdStatus(2 * MCD_STATUS_DELAY);
309 if (st != -1)
310 break;
313 return st;
317 static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
319 int i;
320 if (position) {
321 /* Eject */
322 /* all drives can at least stop! */
323 if (audioStatus == CDROM_AUDIO_PLAY) {
324 outb(MCMD_STOP, MCDPORT(0));
325 i = getMcdStatus(MCD_STATUS_DELAY);
328 audioStatus = CDROM_AUDIO_NO_STATUS;
330 outb(MCMD_EJECT, MCDPORT(0));
332 * the status (i) shows failure on all but the FX drives.
333 * But nothing we can do about that in software!
334 * So just read the status and forget it. - Jon.
336 i = getMcdStatus(MCD_STATUS_DELAY);
337 return 0;
338 } else
339 return -EINVAL;
342 long msf2hsg(struct msf *mp)
344 return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
348 int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
349 void *arg)
351 int i, st;
352 struct mcd_Toc qInfo;
353 struct cdrom_ti *ti;
354 struct cdrom_tochdr *tocHdr;
355 struct cdrom_msf *msf;
356 struct cdrom_subchnl *subchnl;
357 struct cdrom_tocentry *entry;
358 struct mcd_Toc *tocPtr;
359 struct cdrom_volctrl *volctrl;
361 st = statusCmd();
362 if (st < 0)
363 return -EIO;
365 if (!tocUpToDate) {
366 i = updateToc();
367 if (i < 0)
368 return i; /* error reading TOC */
371 switch (cmd) {
372 case CDROMSTART: /* Spin up the drive */
373 /* Don't think we can do this. Even if we could,
374 * I think the drive times out and stops after a while
375 * anyway. For now, ignore it.
378 return 0;
380 case CDROMSTOP: /* Spin down the drive */
381 outb(MCMD_STOP, MCDPORT(0));
382 i = getMcdStatus(MCD_STATUS_DELAY);
384 /* should we do anything if it fails? */
386 audioStatus = CDROM_AUDIO_NO_STATUS;
387 return 0;
389 case CDROMPAUSE: /* Pause the drive */
390 if (audioStatus != CDROM_AUDIO_PLAY)
391 return -EINVAL;
393 outb(MCMD_STOP, MCDPORT(0));
394 i = getMcdStatus(MCD_STATUS_DELAY);
396 if (GetQChannelInfo(&qInfo) < 0) {
397 /* didn't get q channel info */
399 audioStatus = CDROM_AUDIO_NO_STATUS;
400 return 0;
403 mcd_Play.start = qInfo.diskTime; /* remember restart point */
405 audioStatus = CDROM_AUDIO_PAUSED;
406 return 0;
408 case CDROMRESUME: /* Play it again, Sam */
409 if (audioStatus != CDROM_AUDIO_PAUSED)
410 return -EINVAL;
412 /* restart the drive at the saved position. */
414 i = mcdPlay(&mcd_Play);
415 if (i < 0) {
416 audioStatus = CDROM_AUDIO_ERROR;
417 return -EIO;
420 audioStatus = CDROM_AUDIO_PLAY;
421 return 0;
423 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
425 ti = (struct cdrom_ti *) arg;
427 if (ti->cdti_trk0 < DiskInfo.first
428 || ti->cdti_trk0 > DiskInfo.last
429 || ti->cdti_trk1 < ti->cdti_trk0) {
430 return -EINVAL;
433 if (ti->cdti_trk1 > DiskInfo.last)
434 ti->cdti_trk1 = DiskInfo.last;
436 mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
437 mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
439 #ifdef MCD_DEBUG
440 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
441 mcd_Play.start.min, mcd_Play.start.sec,
442 mcd_Play.start.frame, mcd_Play.end.min,
443 mcd_Play.end.sec, mcd_Play.end.frame);
444 #endif
446 i = mcdPlay(&mcd_Play);
447 if (i < 0) {
448 audioStatus = CDROM_AUDIO_ERROR;
449 return -EIO;
452 audioStatus = CDROM_AUDIO_PLAY;
453 return 0;
455 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
457 if (audioStatus == CDROM_AUDIO_PLAY) {
458 outb(MCMD_STOP, MCDPORT(0));
459 i = getMcdStatus(MCD_STATUS_DELAY);
460 audioStatus = CDROM_AUDIO_NO_STATUS;
463 msf = (struct cdrom_msf *) arg;
465 /* convert to bcd */
467 bin2bcd(&msf->cdmsf_min0);
468 bin2bcd(&msf->cdmsf_sec0);
469 bin2bcd(&msf->cdmsf_frame0);
470 bin2bcd(&msf->cdmsf_min1);
471 bin2bcd(&msf->cdmsf_sec1);
472 bin2bcd(&msf->cdmsf_frame1);
474 mcd_Play.start.min = msf->cdmsf_min0;
475 mcd_Play.start.sec = msf->cdmsf_sec0;
476 mcd_Play.start.frame = msf->cdmsf_frame0;
477 mcd_Play.end.min = msf->cdmsf_min1;
478 mcd_Play.end.sec = msf->cdmsf_sec1;
479 mcd_Play.end.frame = msf->cdmsf_frame1;
481 #ifdef MCD_DEBUG
482 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
483 mcd_Play.start.min, mcd_Play.start.sec,
484 mcd_Play.start.frame, mcd_Play.end.min,
485 mcd_Play.end.sec, mcd_Play.end.frame);
486 #endif
488 i = mcdPlay(&mcd_Play);
489 if (i < 0) {
490 audioStatus = CDROM_AUDIO_ERROR;
491 return -EIO;
494 audioStatus = CDROM_AUDIO_PLAY;
495 return 0;
497 case CDROMREADTOCHDR: /* Read the table of contents header */
498 tocHdr = (struct cdrom_tochdr *) arg;
499 tocHdr->cdth_trk0 = DiskInfo.first;
500 tocHdr->cdth_trk1 = DiskInfo.last;
501 return 0;
503 case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
504 entry = (struct cdrom_tocentry *) arg;
505 if (entry->cdte_track == CDROM_LEADOUT)
506 tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
508 else if (entry->cdte_track > DiskInfo.last
509 || entry->cdte_track < DiskInfo.first)
510 return -EINVAL;
512 else
513 tocPtr = &Toc[entry->cdte_track];
515 entry->cdte_adr = tocPtr->ctrl_addr;
516 entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
518 if (entry->cdte_format == CDROM_LBA)
519 entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
521 else if (entry->cdte_format == CDROM_MSF) {
522 entry->cdte_addr.msf.minute =
523 bcd2bin(tocPtr->diskTime.min);
524 entry->cdte_addr.msf.second =
525 bcd2bin(tocPtr->diskTime.sec);
526 entry->cdte_addr.msf.frame =
527 bcd2bin(tocPtr->diskTime.frame);
530 else
531 return -EINVAL;
533 return 0;
535 case CDROMSUBCHNL: /* Get subchannel info */
537 subchnl = (struct cdrom_subchnl *) arg;
538 if (GetQChannelInfo(&qInfo) < 0)
539 return -EIO;
541 subchnl->cdsc_audiostatus = audioStatus;
542 subchnl->cdsc_adr = qInfo.ctrl_addr;
543 subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
544 subchnl->cdsc_trk = bcd2bin(qInfo.track);
545 subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
546 subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
547 subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
548 subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
549 subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
550 subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
551 subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
552 return (0);
554 case CDROMVOLCTRL: /* Volume control */
555 volctrl = (struct cdrom_volctrl *) arg;
556 outb(MCMD_SET_VOLUME, MCDPORT(0));
557 outb(volctrl->channel0, MCDPORT(0));
558 outb(255, MCDPORT(0));
559 outb(volctrl->channel1, MCDPORT(0));
560 outb(255, MCDPORT(0));
562 i = getMcdStatus(MCD_STATUS_DELAY);
563 if (i < 0)
564 return -EIO;
567 char a, b, c, d;
569 getValue(&a);
570 getValue(&b);
571 getValue(&c);
572 getValue(&d);
575 return 0;
577 default:
578 return -EINVAL;
583 * Take care of the different block sizes between cdrom and Linux.
584 * When Linux gets variable block sizes this will probably go away.
587 static void mcd_transfer(void)
589 if (!current_valid())
590 return;
592 while (CURRENT->nr_sectors) {
593 int bn = CURRENT->sector / 4;
594 int i;
595 for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
597 if (i < MCD_BUF_SIZ) {
598 int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
599 int nr_sectors = 4 - (CURRENT->sector & 3);
600 if (mcd_buf_out != i) {
601 mcd_buf_out = i;
602 if (mcd_buf_bn[i] != bn) {
603 mcd_buf_out = -1;
604 continue;
607 if (nr_sectors > CURRENT->nr_sectors)
608 nr_sectors = CURRENT->nr_sectors;
609 memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
610 CURRENT->nr_sectors -= nr_sectors;
611 CURRENT->sector += nr_sectors;
612 CURRENT->buffer += nr_sectors * 512;
613 } else {
614 mcd_buf_out = -1;
615 break;
622 * We only seem to get interrupts after an error.
623 * Just take the interrupt and clear out the status reg.
626 static irqreturn_t mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
628 int st;
630 st = inb(MCDPORT(1)) & 0xFF;
631 test1(printk("<int1-%02X>", st));
632 if (!(st & MFL_STATUS)) {
633 st = inb(MCDPORT(0)) & 0xFF;
634 test1(printk("<int0-%02X>", st));
635 if ((st & 0xFF) != 0xFF)
636 mcd_error = st ? st & 0xFF : -1;
638 return IRQ_HANDLED;
642 static void do_mcd_request(request_queue_t * q)
644 test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
645 CURRENT->nr_sectors));
647 mcd_transfer_is_active = 1;
648 while (current_valid()) {
649 mcd_transfer();
650 if (CURRENT->nr_sectors == 0) {
651 end_request(CURRENT, 1);
652 } else {
653 mcd_buf_out = -1; /* Want to read a block not in buffer */
654 if (mcd_state == MCD_S_IDLE) {
655 if (!tocUpToDate) {
656 if (updateToc() < 0) {
657 while (current_valid())
658 end_request(CURRENT, 0);
659 break;
662 mcd_state = MCD_S_START;
663 McdTries = 5;
664 mcd_timer.function = mcd_poll;
665 mod_timer(&mcd_timer, jiffies + 1);
667 break;
670 mcd_transfer_is_active = 0;
671 test2(printk(" do_mcd_request ends\n"));
676 static void mcd_poll(unsigned long dummy)
678 int st;
681 if (mcd_error) {
682 if (mcd_error & 0xA5) {
683 printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
684 if (mcd_error & 0x80)
685 printk(" (Door open)");
686 if (mcd_error & 0x20)
687 printk(" (Disk changed)");
688 if (mcd_error & 0x04) {
689 printk(" (Read error)"); /* Bitch about the problem. */
691 /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
692 /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
693 /* But I find that rather HANDY!!! */
694 /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
695 /* AJK [06/17/95] */
697 /* Slap the CD down to single speed! */
698 if (mcdDouble == 1
699 && McdTries == MCD_RETRY_ATTEMPTS
700 && MCMD_DATA_READ == MCMD_2X_READ) {
701 MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
702 mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
703 printk(" Speed now 1x"); /* Pull my finger! */
706 printk("\n");
707 mcd_invalidate_buffers();
708 #ifdef WARN_IF_READ_FAILURE
709 if (McdTries == MCD_RETRY_ATTEMPTS)
710 printk(KERN_ERR "mcd: read of block %d failed\n",
711 mcd_next_bn);
712 #endif
713 if (!McdTries--) {
714 /* Nuts! This cd is ready for recycling! */
715 /* When WAS the last time YOU cleaned it CORRECTLY?! */
716 printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
717 mcd_next_bn);
718 if (mcd_transfer_is_active) {
719 McdTries = 0;
720 goto ret;
722 if (current_valid())
723 end_request(CURRENT, 0);
724 McdTries = MCD_RETRY_ATTEMPTS;
727 mcd_error = 0;
728 mcd_state = MCD_S_STOP;
730 /* Switch back to Double speed if enough GOOD sectors were read! */
732 /* Are we a double speed with a crappy CD?! */
733 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
734 && MCMD_DATA_READ == MCMD_PLAY_READ) {
735 /* We ARE a double speed and we ARE bitching! */
736 if (mcd1xhold == 0) { /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
737 MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
738 printk(KERN_INFO "mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
739 } else
740 mcd1xhold--; /* No?! Count down the good reads some more... */
741 /* and try, try again! */
744 immediately:
745 switch (mcd_state) {
746 case MCD_S_IDLE:
747 test3(printk("MCD_S_IDLE\n"));
748 goto out;
750 case MCD_S_START:
751 test3(printk("MCD_S_START\n"));
752 outb(MCMD_GET_STATUS, MCDPORT(0));
753 mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
754 McdTimeout = 3000;
755 break;
757 case MCD_S_MODE:
758 test3(printk("MCD_S_MODE\n"));
759 if ((st = mcdStatus()) != -1) {
760 if (st & MST_DSK_CHG) {
761 mcdDiskChanged = 1;
762 tocUpToDate = 0;
763 mcd_invalidate_buffers();
766 set_mode_immediately:
767 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
768 mcdDiskChanged = 1;
769 tocUpToDate = 0;
770 if (mcd_transfer_is_active) {
771 mcd_state = MCD_S_START;
772 goto immediately;
774 printk(KERN_INFO);
775 printk((st & MST_DOOR_OPEN) ?
776 "mcd: door open\n" :
777 "mcd: disk removed\n");
778 mcd_state = MCD_S_IDLE;
779 while (current_valid())
780 end_request(CURRENT, 0);
781 goto out;
783 outb(MCMD_SET_MODE, MCDPORT(0));
784 outb(1, MCDPORT(0));
785 mcd_mode = 1;
786 mcd_state = MCD_S_READ;
787 McdTimeout = 3000;
789 break;
791 case MCD_S_READ:
792 test3(printk("MCD_S_READ\n"));
793 if ((st = mcdStatus()) != -1) {
794 if (st & MST_DSK_CHG) {
795 mcdDiskChanged = 1;
796 tocUpToDate = 0;
797 mcd_invalidate_buffers();
800 read_immediately:
801 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
802 mcdDiskChanged = 1;
803 tocUpToDate = 0;
804 if (mcd_transfer_is_active) {
805 mcd_state = MCD_S_START;
806 goto immediately;
808 printk(KERN_INFO);
809 printk((st & MST_DOOR_OPEN) ?
810 "mcd: door open\n" :
811 "mcd: disk removed\n");
812 mcd_state = MCD_S_IDLE;
813 while (current_valid())
814 end_request(CURRENT, 0);
815 goto out;
818 if (current_valid()) {
819 struct mcd_Play_msf msf;
820 mcd_next_bn = CURRENT->sector / 4;
821 hsg2msf(mcd_next_bn, &msf.start);
822 msf.end.min = ~0;
823 msf.end.sec = ~0;
824 msf.end.frame = ~0;
825 sendMcdCmd(MCMD_DATA_READ, &msf);
826 mcd_state = MCD_S_DATA;
827 McdTimeout = READ_TIMEOUT;
828 } else {
829 mcd_state = MCD_S_STOP;
830 goto immediately;
834 break;
836 case MCD_S_DATA:
837 test3(printk("MCD_S_DATA\n"));
838 st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
839 data_immediately:
840 test5(printk("Status %02x\n", st))
841 switch (st) {
842 case MFL_DATA:
843 #ifdef WARN_IF_READ_FAILURE
844 if (McdTries == 5)
845 printk(KERN_WARNING "mcd: read of block %d failed\n",
846 mcd_next_bn);
847 #endif
848 if (!McdTries--) {
849 printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
850 if (mcd_transfer_is_active) {
851 McdTries = 0;
852 break;
854 if (current_valid())
855 end_request(CURRENT, 0);
856 McdTries = 5;
858 mcd_state = MCD_S_START;
859 McdTimeout = READ_TIMEOUT;
860 goto immediately;
862 case MFL_STATUSorDATA:
863 break;
865 default:
866 McdTries = 5;
867 if (!current_valid() && mcd_buf_in == mcd_buf_out) {
868 mcd_state = MCD_S_STOP;
869 goto immediately;
871 mcd_buf_bn[mcd_buf_in] = -1;
872 insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
873 2048);
874 mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
875 if (mcd_buf_out == -1)
876 mcd_buf_out = mcd_buf_in;
877 mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
878 if (!mcd_transfer_is_active) {
879 while (current_valid()) {
880 mcd_transfer();
881 if (CURRENT->nr_sectors == 0)
882 end_request(CURRENT, 1);
883 else
884 break;
888 if (current_valid()
889 && (CURRENT->sector / 4 < mcd_next_bn ||
890 CURRENT->sector / 4 > mcd_next_bn + 16)) {
891 mcd_state = MCD_S_STOP;
892 goto immediately;
894 McdTimeout = READ_TIMEOUT;
896 int count = QUICK_LOOP_COUNT;
897 while (count--) {
898 QUICK_LOOP_DELAY;
899 if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
900 test4(printk(" %d ", QUICK_LOOP_COUNT - count));
901 goto data_immediately;
904 test4(printk("ended "));
906 break;
908 break;
910 case MCD_S_STOP:
911 test3(printk("MCD_S_STOP\n"));
912 if (!mitsumi_bug_93_wait)
913 goto do_not_work_around_mitsumi_bug_93_1;
915 McdTimeout = mitsumi_bug_93_wait;
916 mcd_state = 9 + 3 + 1;
917 break;
919 case 9 + 3 + 1:
920 if (McdTimeout)
921 break;
923 do_not_work_around_mitsumi_bug_93_1:
924 outb(MCMD_STOP, MCDPORT(0));
925 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
926 int i = 4096;
927 do {
928 inb(MCDPORT(0));
929 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
930 outb(MCMD_STOP, MCDPORT(0));
931 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
932 i = 4096;
933 do {
934 inb(MCDPORT(0));
935 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
936 outb(MCMD_STOP, MCDPORT(0));
940 mcd_state = MCD_S_STOPPING;
941 McdTimeout = 1000;
942 break;
944 case MCD_S_STOPPING:
945 test3(printk("MCD_S_STOPPING\n"));
946 if ((st = mcdStatus()) == -1 && McdTimeout)
947 break;
949 if ((st != -1) && (st & MST_DSK_CHG)) {
950 mcdDiskChanged = 1;
951 tocUpToDate = 0;
952 mcd_invalidate_buffers();
954 if (!mitsumi_bug_93_wait)
955 goto do_not_work_around_mitsumi_bug_93_2;
957 McdTimeout = mitsumi_bug_93_wait;
958 mcd_state = 9 + 3 + 2;
959 break;
961 case 9 + 3 + 2:
962 if (McdTimeout)
963 break;
964 st = -1;
966 do_not_work_around_mitsumi_bug_93_2:
967 test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
968 mcd_mode));
969 if (current_valid()) {
970 if (st != -1) {
971 if (mcd_mode == 1)
972 goto read_immediately;
973 else
974 goto set_mode_immediately;
975 } else {
976 mcd_state = MCD_S_START;
977 McdTimeout = 1;
979 } else {
980 mcd_state = MCD_S_IDLE;
981 goto out;
983 break;
984 default:
985 printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
986 goto out;
988 ret:
989 if (!McdTimeout--) {
990 printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
991 mcd_state = MCD_S_STOP;
993 mcd_timer.function = mcd_poll;
994 mod_timer(&mcd_timer, jiffies + 1);
995 out:
996 return;
999 static void mcd_invalidate_buffers(void)
1001 int i;
1002 for (i = 0; i < MCD_BUF_SIZ; ++i)
1003 mcd_buf_bn[i] = -1;
1004 mcd_buf_out = -1;
1008 * Open the device special file. Check that a disk is in.
1010 static int mcd_open(struct cdrom_device_info *cdi, int purpose)
1012 int st, count = 0;
1013 if (mcdPresent == 0)
1014 return -ENXIO; /* no hardware */
1016 if (mcd_open_count || mcd_state != MCD_S_IDLE)
1017 goto bump_count;
1019 mcd_invalidate_buffers();
1020 do {
1021 st = statusCmd(); /* check drive status */
1022 if (st == -1)
1023 goto err_out; /* drive doesn't respond */
1024 if ((st & MST_READY) == 0) { /* no disk? wait a sec... */
1025 current->state = TASK_INTERRUPTIBLE;
1026 schedule_timeout(HZ);
1028 } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1030 if (updateToc() < 0)
1031 goto err_out;
1033 bump_count:
1034 ++mcd_open_count;
1035 return 0;
1037 err_out:
1038 return -EIO;
1043 * On close, we flush all mcd blocks from the buffer cache.
1045 static void mcd_release(struct cdrom_device_info *cdi)
1047 if (!--mcd_open_count) {
1048 mcd_invalidate_buffers();
1053 * Test for presence of drive and initialize it. Called at boot time.
1056 int __init mcd_init(void)
1058 struct gendisk *disk = alloc_disk(1);
1059 int count;
1060 unsigned char result[3];
1061 char msg[80];
1063 if (!disk) {
1064 printk(KERN_INFO "mcd: can't allocated disk.\n");
1065 return -ENOMEM;
1067 if (mcd_port <= 0 || mcd_irq <= 0) {
1068 printk(KERN_INFO "mcd: not probing.\n");
1069 put_disk(disk);
1070 return -EIO;
1072 if (register_blkdev(MAJOR_NR, "mcd")) {
1073 put_disk(disk);
1074 return -EIO;
1076 if (!request_region(mcd_port, 4, "mcd")) {
1077 printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
1078 goto out_region;
1081 blk_init_queue(&mcd_queue, do_mcd_request, &mcd_spinlock);
1083 /* check for card */
1085 outb(0, MCDPORT(1)); /* send reset */
1086 for (count = 0; count < 2000000; count++)
1087 (void) inb(MCDPORT(1)); /* delay a bit */
1089 outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1090 for (count = 0; count < 2000000; count++)
1091 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1092 break;
1094 if (count >= 2000000) {
1095 printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
1096 mcd_port, mcd_irq);
1097 goto out_probe;
1099 count = inb(MCDPORT(0)); /* pick up the status */
1101 outb(MCMD_GET_VERSION, MCDPORT(0));
1102 for (count = 0; count < 3; count++)
1103 if (getValue(result + count)) {
1104 printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
1105 mcd_port);
1106 goto out_probe;
1109 if (result[0] == result[1] && result[1] == result[2])
1110 goto out_probe;
1112 mcdVersion = result[2];
1114 if (mcdVersion >= 4)
1115 outb(4, MCDPORT(2)); /* magic happens */
1117 /* don't get the IRQ until we know for sure the drive is there */
1119 if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
1120 printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1121 goto out_probe;
1124 if (result[1] == 'D') {
1125 MCMD_DATA_READ = MCMD_2X_READ;
1126 /* Added flag to drop to 1x speed if too many errors */
1127 mcdDouble = 1;
1128 } else
1129 mcd_info.speed = 1;
1130 sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1131 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
1132 mcd_port, mcd_irq);
1134 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1135 outb(0x02, MCDPORT(0));
1136 outb(0x00, MCDPORT(0));
1137 getValue(result);
1139 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1140 outb(0x10, MCDPORT(0));
1141 outb(0x04, MCDPORT(0));
1142 getValue(result);
1144 mcd_invalidate_buffers();
1145 mcdPresent = 1;
1147 disk->major = MAJOR_NR;
1148 disk->first_minor = 0;
1149 sprintf(disk->disk_name, "mcd");
1150 disk->fops = &mcd_bdops;
1151 disk->flags = GENHD_FL_CD;
1152 mcd_gendisk = disk;
1154 if (register_cdrom(&mcd_info) != 0) {
1155 printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
1156 goto out_cdrom;
1158 disk->queue = &mcd_queue;
1159 add_disk(disk);
1160 printk(msg);
1161 return 0;
1163 out_cdrom:
1164 free_irq(mcd_irq, NULL);
1165 out_probe:
1166 release_region(mcd_port, 4);
1167 out_region:
1168 unregister_blkdev(MAJOR_NR, "mcd");
1169 blk_cleanup_queue(&mcd_queue);
1170 put_disk(disk);
1171 return -EIO;
1175 static void hsg2msf(long hsg, struct msf *msf)
1177 hsg += 150;
1178 msf->min = hsg / 4500;
1179 hsg %= 4500;
1180 msf->sec = hsg / 75;
1181 msf->frame = hsg % 75;
1183 bin2bcd(&msf->min); /* convert to BCD */
1184 bin2bcd(&msf->sec);
1185 bin2bcd(&msf->frame);
1189 static void bin2bcd(unsigned char *p)
1191 int u, t;
1193 u = *p % 10;
1194 t = *p / 10;
1195 *p = u | (t << 4);
1198 static int bcd2bin(unsigned char bcd)
1200 return (bcd >> 4) * 10 + (bcd & 0xF);
1205 * See if a status is ready from the drive and return it
1206 * if it is ready.
1209 static int mcdStatus(void)
1211 int i;
1212 int st;
1214 st = inb(MCDPORT(1)) & MFL_STATUS;
1215 if (!st) {
1216 i = inb(MCDPORT(0)) & 0xFF;
1217 return i;
1218 } else
1219 return -1;
1224 * Send a play or read command to the drive
1227 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1229 outb(cmd, MCDPORT(0));
1230 outb(params->start.min, MCDPORT(0));
1231 outb(params->start.sec, MCDPORT(0));
1232 outb(params->start.frame, MCDPORT(0));
1233 outb(params->end.min, MCDPORT(0));
1234 outb(params->end.sec, MCDPORT(0));
1235 outb(params->end.frame, MCDPORT(0));
1240 * Timer interrupt routine to test for status ready from the drive.
1241 * (see the next routine)
1244 static void mcdStatTimer(unsigned long dummy)
1246 if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
1247 wake_up(&mcd_waitq);
1248 return;
1251 McdTimeout--;
1252 if (McdTimeout <= 0) {
1253 wake_up(&mcd_waitq);
1254 return;
1256 mcd_timer.function = mcdStatTimer;
1257 mod_timer(&mcd_timer, jiffies + 1);
1262 * Wait for a status to be returned from the drive. The actual test
1263 * (see routine above) is done by the timer interrupt to avoid
1264 * excessive rescheduling.
1267 static int getMcdStatus(int timeout)
1269 int st;
1271 McdTimeout = timeout;
1272 mcd_timer.function = mcdStatTimer;
1273 mod_timer(&mcd_timer, jiffies + 1);
1274 sleep_on(&mcd_waitq);
1275 if (McdTimeout <= 0)
1276 return -1;
1278 st = inb(MCDPORT(0)) & 0xFF;
1279 if (st == 0xFF)
1280 return -1;
1282 if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1283 /* XXX might be an error? look at q-channel? */
1284 audioStatus = CDROM_AUDIO_COMPLETED;
1286 if (st & MST_DSK_CHG) {
1287 mcdDiskChanged = 1;
1288 tocUpToDate = 0;
1289 audioStatus = CDROM_AUDIO_NO_STATUS;
1292 return st;
1296 /* gives current state of the drive This function is quite unreliable,
1297 and should probably be rewritten by someone, eventually... */
1299 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1301 int st;
1303 st = statusCmd(); /* check drive status */
1304 if (st == -1)
1305 return -EIO; /* drive doesn't respond */
1306 if ((st & MST_READY))
1307 return CDS_DISC_OK;
1308 if ((st & MST_DOOR_OPEN))
1309 return CDS_TRAY_OPEN;
1310 if ((st & MST_DSK_CHG))
1311 return CDS_NO_DISC;
1312 if ((st & MST_BUSY))
1313 return CDS_DRIVE_NOT_READY;
1314 return -EIO;
1319 * Read a value from the drive.
1322 static int getValue(unsigned char *result)
1324 int count;
1325 int s;
1327 for (count = 0; count < 2000; count++)
1328 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1329 break;
1331 if (count >= 2000) {
1332 printk("mcd: getValue timeout\n");
1333 return -1;
1336 s = inb(MCDPORT(0)) & 0xFF;
1337 *result = (unsigned char) s;
1338 return 0;
1342 * Read the current Q-channel info. Also used for reading the
1343 * table of contents.
1346 int GetQChannelInfo(struct mcd_Toc *qp)
1348 unsigned char notUsed;
1349 int retry;
1351 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1352 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1353 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1354 break;
1357 if (retry >= MCD_RETRY_ATTEMPTS)
1358 return -1;
1360 if (getValue(&qp->ctrl_addr) < 0)
1361 return -1;
1362 if (getValue(&qp->track) < 0)
1363 return -1;
1364 if (getValue(&qp->pointIndex) < 0)
1365 return -1;
1366 if (getValue(&qp->trackTime.min) < 0)
1367 return -1;
1368 if (getValue(&qp->trackTime.sec) < 0)
1369 return -1;
1370 if (getValue(&qp->trackTime.frame) < 0)
1371 return -1;
1372 if (getValue(&notUsed) < 0)
1373 return -1;
1374 if (getValue(&qp->diskTime.min) < 0)
1375 return -1;
1376 if (getValue(&qp->diskTime.sec) < 0)
1377 return -1;
1378 if (getValue(&qp->diskTime.frame) < 0)
1379 return -1;
1381 return 0;
1385 * Read the table of contents (TOC) and TOC header if necessary
1388 static int updateToc(void)
1390 if (tocUpToDate)
1391 return 0;
1393 if (GetDiskInfo() < 0)
1394 return -EIO;
1396 if (GetToc() < 0)
1397 return -EIO;
1399 tocUpToDate = 1;
1400 return 0;
1404 * Read the table of contents header
1407 static int GetDiskInfo(void)
1409 int retry;
1411 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1412 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1413 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1414 break;
1417 if (retry >= MCD_RETRY_ATTEMPTS)
1418 return -1;
1420 if (getValue(&DiskInfo.first) < 0)
1421 return -1;
1422 if (getValue(&DiskInfo.last) < 0)
1423 return -1;
1425 DiskInfo.first = bcd2bin(DiskInfo.first);
1426 DiskInfo.last = bcd2bin(DiskInfo.last);
1428 #ifdef MCD_DEBUG
1429 printk
1430 ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1431 DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
1432 DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
1433 DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
1434 DiskInfo.firstTrack.frame);
1435 #endif
1437 if (getValue(&DiskInfo.diskLength.min) < 0)
1438 return -1;
1439 if (getValue(&DiskInfo.diskLength.sec) < 0)
1440 return -1;
1441 if (getValue(&DiskInfo.diskLength.frame) < 0)
1442 return -1;
1443 if (getValue(&DiskInfo.firstTrack.min) < 0)
1444 return -1;
1445 if (getValue(&DiskInfo.firstTrack.sec) < 0)
1446 return -1;
1447 if (getValue(&DiskInfo.firstTrack.frame) < 0)
1448 return -1;
1450 return 0;
1454 * Read the table of contents (TOC)
1457 static int GetToc(void)
1459 int i, px;
1460 int limit;
1461 int retry;
1462 struct mcd_Toc qInfo;
1464 for (i = 0; i < MAX_TRACKS; i++)
1465 Toc[i].pointIndex = 0;
1467 i = DiskInfo.last + 3;
1469 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1470 outb(MCMD_STOP, MCDPORT(0));
1471 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1472 break;
1475 if (retry >= MCD_RETRY_ATTEMPTS)
1476 return -1;
1478 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1479 outb(MCMD_SET_MODE, MCDPORT(0));
1480 outb(0x05, MCDPORT(0)); /* mode: toc */
1481 mcd_mode = 0x05;
1482 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1483 break;
1486 if (retry >= MCD_RETRY_ATTEMPTS)
1487 return -1;
1489 for (limit = 300; limit > 0; limit--) {
1490 if (GetQChannelInfo(&qInfo) < 0)
1491 break;
1493 px = bcd2bin(qInfo.pointIndex);
1494 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1495 if (Toc[px].pointIndex == 0) {
1496 Toc[px] = qInfo;
1497 i--;
1500 if (i <= 0)
1501 break;
1504 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1506 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1507 outb(MCMD_SET_MODE, MCDPORT(0));
1508 outb(0x01, MCDPORT(0));
1509 mcd_mode = 1;
1510 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1511 break;
1514 #ifdef MCD_DEBUG
1515 for (i = 1; i <= DiskInfo.last; i++)
1516 printk
1517 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1518 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1519 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1520 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1521 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1522 for (i = 100; i < 103; i++)
1523 printk
1524 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1525 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1526 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1527 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1528 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1529 #endif
1531 return limit > 0 ? 0 : -1;
1534 void __exit mcd_exit(void)
1536 del_gendisk(mcd_gendisk);
1537 put_disk(mcd_gendisk);
1538 if (unregister_cdrom(&mcd_info)) {
1539 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1540 return;
1542 free_irq(mcd_irq, NULL);
1543 release_region(mcd_port, 4);
1544 if (unregister_blkdev(MAJOR_NR, "mcd")) {
1545 printk(KERN_WARNING "Can't unregister major mcd\n");
1546 return;
1548 blk_cleanup_queue(&mcd_queue);
1549 del_timer_sync(&mcd_timer);
1552 #ifdef MODULE
1553 module_init(mcd_init);
1554 #endif
1555 module_exit(mcd_exit);
1557 MODULE_AUTHOR("Martin Harriss");
1558 MODULE_LICENSE("GPL");