1 /*
2 linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
3
4 Copyright (C) 1992 Martin Harriss
5 Portions Copyright (C) 2001 Red Hat
6
7 martin@bdsi.com (no longer valid - where are you now, Martin?)
8
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.
13
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.
18
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.
22
23 HISTORY
24
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>)
34
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.
41
42
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
47
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
63
64 Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
65
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.
69
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).
72
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>
77
78 September 2001 - Reformatted and cleaned up the code
79 Alan Cox <alan@redhat.com>
80 */
81
82 #include <linux/module.h>
83
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>
98
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/blkdev.h>
105
106 #include "mcd.h"
107
108 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
109 static int mcdDouble;
110
111 /* How many sectors to hold at 1x speed counter */
112 static int mcd1xhold;
113
114 /* Is the drive connected properly and responding?? */
115 static int mcdPresent;
116 static struct request_queue *mcd_queue;
117
118 #define MAJOR_NR MITSUMI_CDROM_MAJOR
119 #define QUEUE (mcd_queue)
120 #define CURRENT elv_next_request(mcd_queue)
121
122 #define QUICK_LOOP_DELAY udelay(45) /* use udelay */
123 #define QUICK_LOOP_COUNT 20
124
125 static int current_valid(void)
126 {
127 return CURRENT &&
128 CURRENT->cmd == READ &&
129 CURRENT->sector != -1;
130 }
131
132 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
133 #define MCD_BUF_SIZ 16
134 static volatile int mcd_transfer_is_active;
135 static char mcd_buf[2048 * MCD_BUF_SIZ]; /* buffer for block size conversion */
136 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
137 static volatile int mcd_buf_in, mcd_buf_out = -1;
138 static volatile int mcd_error;
139 static int mcd_open_count;
140 enum mcd_state_e {
141 MCD_S_IDLE, /* 0 */
142 MCD_S_START, /* 1 */
143 MCD_S_MODE, /* 2 */
144 MCD_S_READ, /* 3 */
145 MCD_S_DATA, /* 4 */
146 MCD_S_STOP, /* 5 */
147 MCD_S_STOPPING /* 6 */
148 };
149 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
150 static int mcd_mode = -1;
151 static int MCMD_DATA_READ = MCMD_PLAY_READ;
152
153 #define READ_TIMEOUT 3000
154
155 int mitsumi_bug_93_wait;
156
157 static short mcd_port = CONFIG_MCD_BASE; /* used as "mcd" by "insmod" */
158 static int mcd_irq = CONFIG_MCD_IRQ; /* must directly follow mcd_port */
159
160 static int McdTimeout, McdTries;
161 static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
162
163 static struct mcd_DiskInfo DiskInfo;
164 static struct mcd_Toc Toc[MAX_TRACKS];
165 static struct mcd_Play_msf mcd_Play;
166
167 static int audioStatus;
168 static char mcdDiskChanged;
169 static char tocUpToDate;
170 static char mcdVersion;
171
172 static void mcd_transfer(void);
173 static void mcd_poll(unsigned long dummy);
174 static void mcd_invalidate_buffers(void);
175 static void hsg2msf(long hsg, struct msf *msf);
176 static void bin2bcd(unsigned char *p);
177 static int bcd2bin(unsigned char bcd);
178 static int mcdStatus(void);
179 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
180 static int getMcdStatus(int timeout);
181 static int GetQChannelInfo(struct mcd_Toc *qp);
182 static int updateToc(void);
183 static int GetDiskInfo(void);
184 static int GetToc(void);
185 static int getValue(unsigned char *result);
186 static int mcd_open(struct cdrom_device_info *cdi, int purpose);
187 static void mcd_release(struct cdrom_device_info *cdi);
188 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
189 static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
190 static DEFINE_SPINLOCK(mcd_spinlock);
191 static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
192 void *arg);
193 static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
194
195 static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
196
197 static struct cdrom_device_ops mcd_dops = {
198 .open = mcd_open,
199 .release = mcd_release,
200 .drive_status = mcd_drive_status,
201 .media_changed = mcd_media_changed,
202 .tray_move = mcd_tray_move,
203 .audio_ioctl = mcd_audio_ioctl,
204 .capability = CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
205 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
206 };
207
208 static struct cdrom_device_info mcd_info = {
209 .ops = &mcd_dops,
210 .speed = 2,
211 .capacity = 1,
212 .name = "mcd",
213 };
214
215 static int mcd_block_open(struct inode *inode, struct file *file)
216 {
217 return cdrom_open(&mcd_info, inode, file);
218 }
219
220 static int mcd_block_release(struct inode *inode, struct file *file)
221 {
222 return cdrom_release(&mcd_info, file);
223 }
224
225 static int mcd_block_ioctl(struct inode *inode, struct file *file,
226 unsigned cmd, unsigned long arg)
227 {
228 return cdrom_ioctl(file, &mcd_info, inode, cmd, arg);
229 }
230
231 static int mcd_block_media_changed(struct gendisk *disk)
232 {
233 return cdrom_media_changed(&mcd_info);
234 }
235
236 static struct block_device_operations mcd_bdops =
237 {
238 .owner = THIS_MODULE,
239 .open = mcd_block_open,
240 .release = mcd_block_release,
241 .ioctl = mcd_block_ioctl,
242 .media_changed = mcd_block_media_changed,
243 };
244
245 static struct gendisk *mcd_gendisk;
246
247 static int __init mcd_setup(char *str)
248 {
249 int ints[9];
250
251 (void) get_options(str, ARRAY_SIZE(ints), ints);
252
253 if (ints[0] > 0)
254 mcd_port = ints[1];
255 if (ints[0] > 1)
256 mcd_irq = ints[2];
257 if (ints[0] > 2)
258 mitsumi_bug_93_wait = ints[3];
259
260 return 1;
261 }
262
263 __setup("mcd=", mcd_setup);
264
265 #ifdef MODULE
266 static int __init param_set_mcd(const char *val, struct kernel_param *kp)
267 {
268 mcd_setup(val);
269 return 0;
270 }
271 module_param_call(mcd, param_set_mcd, NULL, NULL, 0);
272 #endif
273
274 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
275 {
276 return 0;
277 }
278
279
280 /*
281 * Do a 'get status' command and get the result. Only use from the top half
282 * because it calls 'getMcdStatus' which sleeps.
283 */
284
285 static int statusCmd(void)
286 {
287 int st = -1, retry;
288
289 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
290 /* send get-status cmd */
291 outb(MCMD_GET_STATUS, MCDPORT(0));
292
293 st = getMcdStatus(MCD_STATUS_DELAY);
294 if (st != -1)
295 break;
296 }
297
298 return st;
299 }
300
301
302 /*
303 * Send a 'Play' command and get the status. Use only from the top half.
304 */
305
306 static int mcdPlay(struct mcd_Play_msf *arg)
307 {
308 int retry, st = -1;
309
310 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
311 sendMcdCmd(MCMD_PLAY_READ, arg);
312 st = getMcdStatus(2 * MCD_STATUS_DELAY);
313 if (st != -1)
314 break;
315 }
316
317 return st;
318 }
319
320
321 static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
322 {
323 int i;
324 if (position) {
325 /* Eject */
326 /* all drives can at least stop! */
327 if (audioStatus == CDROM_AUDIO_PLAY) {
328 outb(MCMD_STOP, MCDPORT(0));
329 i = getMcdStatus(MCD_STATUS_DELAY);
330 }
331
332 audioStatus = CDROM_AUDIO_NO_STATUS;
333
334 outb(MCMD_EJECT, MCDPORT(0));
335 /*
336 * the status (i) shows failure on all but the FX drives.
337 * But nothing we can do about that in software!
338 * So just read the status and forget it. - Jon.
339 */
340 i = getMcdStatus(MCD_STATUS_DELAY);
341 return 0;
342 } else
343 return -EINVAL;
344 }
345
346 long msf2hsg(struct msf *mp)
347 {
348 return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
349 }
350
351
352 int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
353 void *arg)
354 {
355 int i, st;
356 struct mcd_Toc qInfo;
357 struct cdrom_ti *ti;
358 struct cdrom_tochdr *tocHdr;
359 struct cdrom_msf *msf;
360 struct cdrom_subchnl *subchnl;
361 struct cdrom_tocentry *entry;
362 struct mcd_Toc *tocPtr;
363 struct cdrom_volctrl *volctrl;
364
365 st = statusCmd();
366 if (st < 0)
367 return -EIO;
368
369 if (!tocUpToDate) {
370 i = updateToc();
371 if (i < 0)
372 return i; /* error reading TOC */
373 }
374
375 switch (cmd) {
376 case CDROMSTART: /* Spin up the drive */
377 /* Don't think we can do this. Even if we could,
378 * I think the drive times out and stops after a while
379 * anyway. For now, ignore it.
380 */
381
382 return 0;
383
384 case CDROMSTOP: /* Spin down the drive */
385 outb(MCMD_STOP, MCDPORT(0));
386 i = getMcdStatus(MCD_STATUS_DELAY);
387
388 /* should we do anything if it fails? */
389
390 audioStatus = CDROM_AUDIO_NO_STATUS;
391 return 0;
392
393 case CDROMPAUSE: /* Pause the drive */
394 if (audioStatus != CDROM_AUDIO_PLAY)
395 return -EINVAL;
396
397 outb(MCMD_STOP, MCDPORT(0));
398 i = getMcdStatus(MCD_STATUS_DELAY);
399
400 if (GetQChannelInfo(&qInfo) < 0) {
401 /* didn't get q channel info */
402
403 audioStatus = CDROM_AUDIO_NO_STATUS;
404 return 0;
405 }
406
407 mcd_Play.start = qInfo.diskTime; /* remember restart point */
408
409 audioStatus = CDROM_AUDIO_PAUSED;
410 return 0;
411
412 case CDROMRESUME: /* Play it again, Sam */
413 if (audioStatus != CDROM_AUDIO_PAUSED)
414 return -EINVAL;
415
416 /* restart the drive at the saved position. */
417
418 i = mcdPlay(&mcd_Play);
419 if (i < 0) {
420 audioStatus = CDROM_AUDIO_ERROR;
421 return -EIO;
422 }
423
424 audioStatus = CDROM_AUDIO_PLAY;
425 return 0;
426
427 case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
428
429 ti = (struct cdrom_ti *) arg;
430
431 if (ti->cdti_trk0 < DiskInfo.first
432 || ti->cdti_trk0 > DiskInfo.last
433 || ti->cdti_trk1 < ti->cdti_trk0) {
434 return -EINVAL;
435 }
436
437 if (ti->cdti_trk1 > DiskInfo.last)
438 ti->cdti_trk1 = DiskInfo.last;
439
440 mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
441 mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
442
443 #ifdef MCD_DEBUG
444 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
445 mcd_Play.start.min, mcd_Play.start.sec,
446 mcd_Play.start.frame, mcd_Play.end.min,
447 mcd_Play.end.sec, mcd_Play.end.frame);
448 #endif
449
450 i = mcdPlay(&mcd_Play);
451 if (i < 0) {
452 audioStatus = CDROM_AUDIO_ERROR;
453 return -EIO;
454 }
455
456 audioStatus = CDROM_AUDIO_PLAY;
457 return 0;
458
459 case CDROMPLAYMSF: /* Play starting at the given MSF address. */
460
461 if (audioStatus == CDROM_AUDIO_PLAY) {
462 outb(MCMD_STOP, MCDPORT(0));
463 i = getMcdStatus(MCD_STATUS_DELAY);
464 audioStatus = CDROM_AUDIO_NO_STATUS;
465 }
466
467 msf = (struct cdrom_msf *) arg;
468
469 /* convert to bcd */
470
471 bin2bcd(&msf->cdmsf_min0);
472 bin2bcd(&msf->cdmsf_sec0);
473 bin2bcd(&msf->cdmsf_frame0);
474 bin2bcd(&msf->cdmsf_min1);
475 bin2bcd(&msf->cdmsf_sec1);
476 bin2bcd(&msf->cdmsf_frame1);
477
478 mcd_Play.start.min = msf->cdmsf_min0;
479 mcd_Play.start.sec = msf->cdmsf_sec0;
480 mcd_Play.start.frame = msf->cdmsf_frame0;
481 mcd_Play.end.min = msf->cdmsf_min1;
482 mcd_Play.end.sec = msf->cdmsf_sec1;
483 mcd_Play.end.frame = msf->cdmsf_frame1;
484
485 #ifdef MCD_DEBUG
486 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
487 mcd_Play.start.min, mcd_Play.start.sec,
488 mcd_Play.start.frame, mcd_Play.end.min,
489 mcd_Play.end.sec, mcd_Play.end.frame);
490 #endif
491
492 i = mcdPlay(&mcd_Play);
493 if (i < 0) {
494 audioStatus = CDROM_AUDIO_ERROR;
495 return -EIO;
496 }
497
498 audioStatus = CDROM_AUDIO_PLAY;
499 return 0;
500
501 case CDROMREADTOCHDR: /* Read the table of contents header */
502 tocHdr = (struct cdrom_tochdr *) arg;
503 tocHdr->cdth_trk0 = DiskInfo.first;
504 tocHdr->cdth_trk1 = DiskInfo.last;
505 return 0;
506
507 case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
508 entry = (struct cdrom_tocentry *) arg;
509 if (entry->cdte_track == CDROM_LEADOUT)
510 tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
511
512 else if (entry->cdte_track > DiskInfo.last
513 || entry->cdte_track < DiskInfo.first)
514 return -EINVAL;
515
516 else
517 tocPtr = &Toc[entry->cdte_track];
518
519 entry->cdte_adr = tocPtr->ctrl_addr;
520 entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
521
522 if (entry->cdte_format == CDROM_LBA)
523 entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
524
525 else if (entry->cdte_format == CDROM_MSF) {
526 entry->cdte_addr.msf.minute =
527 bcd2bin(tocPtr->diskTime.min);
528 entry->cdte_addr.msf.second =
529 bcd2bin(tocPtr->diskTime.sec);
530 entry->cdte_addr.msf.frame =
531 bcd2bin(tocPtr->diskTime.frame);
532 }
533
534 else
535 return -EINVAL;
536
537 return 0;
538
539 case CDROMSUBCHNL: /* Get subchannel info */
540
541 subchnl = (struct cdrom_subchnl *) arg;
542 if (GetQChannelInfo(&qInfo) < 0)
543 return -EIO;
544
545 subchnl->cdsc_audiostatus = audioStatus;
546 subchnl->cdsc_adr = qInfo.ctrl_addr;
547 subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
548 subchnl->cdsc_trk = bcd2bin(qInfo.track);
549 subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
550 subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
551 subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
552 subchnl->cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
553 subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
554 subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
555 subchnl->cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
556 return (0);
557
558 case CDROMVOLCTRL: /* Volume control */
559 volctrl = (struct cdrom_volctrl *) arg;
560 outb(MCMD_SET_VOLUME, MCDPORT(0));
561 outb(volctrl->channel0, MCDPORT(0));
562 outb(255, MCDPORT(0));
563 outb(volctrl->channel1, MCDPORT(0));
564 outb(255, MCDPORT(0));
565
566 i = getMcdStatus(MCD_STATUS_DELAY);
567 if (i < 0)
568 return -EIO;
569
570 {
571 char a, b, c, d;
572
573 getValue(&a);
574 getValue(&b);
575 getValue(&c);
576 getValue(&d);
577 }
578
579 return 0;
580
581 default:
582 return -EINVAL;
583 }
584 }
585
586 /*
587 * Take care of the different block sizes between cdrom and Linux.
588 * When Linux gets variable block sizes this will probably go away.
589 */
590
591 static void mcd_transfer(void)
592 {
593 if (!current_valid())
594 return;
595
596 while (CURRENT->nr_sectors) {
597 int bn = CURRENT->sector / 4;
598 int i;
599 for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
600 ;
601 if (i < MCD_BUF_SIZ) {
602 int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
603 int nr_sectors = 4 - (CURRENT->sector & 3);
604 if (mcd_buf_out != i) {
605 mcd_buf_out = i;
606 if (mcd_buf_bn[i] != bn) {
607 mcd_buf_out = -1;
608 continue;
609 }
610 }
611 if (nr_sectors > CURRENT->nr_sectors)
612 nr_sectors = CURRENT->nr_sectors;
613 memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
614 CURRENT->nr_sectors -= nr_sectors;
615 CURRENT->sector += nr_sectors;
616 CURRENT->buffer += nr_sectors * 512;
617 } else {
618 mcd_buf_out = -1;
619 break;
620 }
621 }
622 }
623
624
625 /*
626 * We only seem to get interrupts after an error.
627 * Just take the interrupt and clear out the status reg.
628 */
629
630 static irqreturn_t mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
631 {
632 int st;
633
634 st = inb(MCDPORT(1)) & 0xFF;
635 test1(printk("<int1-%02X>", st));
636 if (!(st & MFL_STATUS)) {
637 st = inb(MCDPORT(0)) & 0xFF;
638 test1(printk("<int0-%02X>", st));
639 if ((st & 0xFF) != 0xFF)
640 mcd_error = st ? st & 0xFF : -1;
641 }
642 return IRQ_HANDLED;
643 }
644
645
646 static void do_mcd_request(request_queue_t * q)
647 {
648 test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
649 CURRENT->nr_sectors));
650
651 mcd_transfer_is_active = 1;
652 while (current_valid()) {
653 mcd_transfer();
654 if (CURRENT->nr_sectors == 0) {
655 end_request(CURRENT, 1);
656 } else {
657 mcd_buf_out = -1; /* Want to read a block not in buffer */
658 if (mcd_state == MCD_S_IDLE) {
659 if (!tocUpToDate) {
660 if (updateToc() < 0) {
661 while (current_valid())
662 end_request(CURRENT, 0);
663 break;
664 }
665 }
666 mcd_state = MCD_S_START;
667 McdTries = 5;
668 mcd_timer.function = mcd_poll;
669 mod_timer(&mcd_timer, jiffies + 1);
670 }
671 break;
672 }
673 }
674 mcd_transfer_is_active = 0;
675 test2(printk(" do_mcd_request ends\n"));
676 }
677
678
679
680 static void mcd_poll(unsigned long dummy)
681 {
682 int st;
683
684
685 if (mcd_error) {
686 if (mcd_error & 0xA5) {
687 printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
688 if (mcd_error & 0x80)
689 printk(" (Door open)");
690 if (mcd_error & 0x20)
691 printk(" (Disk changed)");
692 if (mcd_error & 0x04) {
693 printk(" (Read error)"); /* Bitch about the problem. */
694
695 /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
696 /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
697 /* But I find that rather HANDY!!! */
698 /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
699 /* AJK [06/17/95] */
700
701 /* Slap the CD down to single speed! */
702 if (mcdDouble == 1
703 && McdTries == MCD_RETRY_ATTEMPTS
704 && MCMD_DATA_READ == MCMD_2X_READ) {
705 MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
706 mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Beavis! */
707 printk(" Speed now 1x"); /* Pull my finger! */
708 }
709 }
710 printk("\n");
711 mcd_invalidate_buffers();
712 #ifdef WARN_IF_READ_FAILURE
713 if (McdTries == MCD_RETRY_ATTEMPTS)
714 printk(KERN_ERR "mcd: read of block %d failed\n",
715 mcd_next_bn);
716 #endif
717 if (!McdTries--) {
718 /* Nuts! This cd is ready for recycling! */
719 /* When WAS the last time YOU cleaned it CORRECTLY?! */
720 printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
721 mcd_next_bn);
722 if (mcd_transfer_is_active) {
723 McdTries = 0;
724 goto ret;
725 }
726 if (current_valid())
727 end_request(CURRENT, 0);
728 McdTries = MCD_RETRY_ATTEMPTS;
729 }
730 }
731 mcd_error = 0;
732 mcd_state = MCD_S_STOP;
733 }
734 /* Switch back to Double speed if enough GOOD sectors were read! */
735
736 /* Are we a double speed with a crappy CD?! */
737 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
738 && MCMD_DATA_READ == MCMD_PLAY_READ) {
739 /* We ARE a double speed and we ARE bitching! */
740 if (mcd1xhold == 0) { /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
741 MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
742 printk(KERN_INFO "mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
743 } else
744 mcd1xhold--; /* No?! Count down the good reads some more... */
745 /* and try, try again! */
746 }
747
748 immediately:
749 switch (mcd_state) {
750 case MCD_S_IDLE:
751 test3(printk("MCD_S_IDLE\n"));
752 goto out;
753
754 case MCD_S_START:
755 test3(printk("MCD_S_START\n"));
756 outb(MCMD_GET_STATUS, MCDPORT(0));
757 mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
758 McdTimeout = 3000;
759 break;
760
761 case MCD_S_MODE:
762 test3(printk("MCD_S_MODE\n"));
763 if ((st = mcdStatus()) != -1) {
764 if (st & MST_DSK_CHG) {
765 mcdDiskChanged = 1;
766 tocUpToDate = 0;
767 mcd_invalidate_buffers();
768 }
769
770 set_mode_immediately:
771 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
772 mcdDiskChanged = 1;
773 tocUpToDate = 0;
774 if (mcd_transfer_is_active) {
775 mcd_state = MCD_S_START;
776 goto immediately;
777 }
778 printk(KERN_INFO);
779 printk((st & MST_DOOR_OPEN) ?
780 "mcd: door open\n" :
781 "mcd: disk removed\n");
782 mcd_state = MCD_S_IDLE;
783 while (current_valid())
784 end_request(CURRENT, 0);
785 goto out;
786 }
787 outb(MCMD_SET_MODE, MCDPORT(0));
788 outb(1, MCDPORT(0));
789 mcd_mode = 1;
790 mcd_state = MCD_S_READ;
791 McdTimeout = 3000;
792 }
793 break;
794
795 case MCD_S_READ:
796 test3(printk("MCD_S_READ\n"));
797 if ((st = mcdStatus()) != -1) {
798 if (st & MST_DSK_CHG) {
799 mcdDiskChanged = 1;
800 tocUpToDate = 0;
801 mcd_invalidate_buffers();
802 }
803
804 read_immediately:
805 if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
806 mcdDiskChanged = 1;
807 tocUpToDate = 0;
808 if (mcd_transfer_is_active) {
809 mcd_state = MCD_S_START;
810 goto immediately;
811 }
812 printk(KERN_INFO);
813 printk((st & MST_DOOR_OPEN) ?
814 "mcd: door open\n" :
815 "mcd: disk removed\n");
816 mcd_state = MCD_S_IDLE;
817 while (current_valid())
818 end_request(CURRENT, 0);
819 goto out;
820 }
821
822 if (current_valid()) {
823 struct mcd_Play_msf msf;
824 mcd_next_bn = CURRENT->sector / 4;
825 hsg2msf(mcd_next_bn, &msf.start);
826 msf.end.min = ~0;
827 msf.end.sec = ~0;
828 msf.end.frame = ~0;
829 sendMcdCmd(MCMD_DATA_READ, &msf);
830 mcd_state = MCD_S_DATA;
831 McdTimeout = READ_TIMEOUT;
832 } else {
833 mcd_state = MCD_S_STOP;
834 goto immediately;
835 }
836
837 }
838 break;
839
840 case MCD_S_DATA:
841 test3(printk("MCD_S_DATA\n"));
842 st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
843 data_immediately:
844 test5(printk("Status %02x\n", st))
845 switch (st) {
846 case MFL_DATA:
847 #ifdef WARN_IF_READ_FAILURE
848 if (McdTries == 5)
849 printk(KERN_WARNING "mcd: read of block %d failed\n",
850 mcd_next_bn);
851 #endif
852 if (!McdTries--) {
853 printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
854 if (mcd_transfer_is_active) {
855 McdTries = 0;
856 break;
857 }
858 if (current_valid())
859 end_request(CURRENT, 0);
860 McdTries = 5;
861 }
862 mcd_state = MCD_S_START;
863 McdTimeout = READ_TIMEOUT;
864 goto immediately;
865
866 case MFL_STATUSorDATA:
867 break;
868
869 default:
870 McdTries = 5;
871 if (!current_valid() && mcd_buf_in == mcd_buf_out) {
872 mcd_state = MCD_S_STOP;
873 goto immediately;
874 }
875 mcd_buf_bn[mcd_buf_in] = -1;
876 insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
877 2048);
878 mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
879 if (mcd_buf_out == -1)
880 mcd_buf_out = mcd_buf_in;
881 mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
882 if (!mcd_transfer_is_active) {
883 while (current_valid()) {
884 mcd_transfer();
885 if (CURRENT->nr_sectors == 0)
886 end_request(CURRENT, 1);
887 else
888 break;
889 }
890 }
891
892 if (current_valid()
893 && (CURRENT->sector / 4 < mcd_next_bn ||
894 CURRENT->sector / 4 > mcd_next_bn + 16)) {
895 mcd_state = MCD_S_STOP;
896 goto immediately;
897 }
898 McdTimeout = READ_TIMEOUT;
899 {
900 int count = QUICK_LOOP_COUNT;
901 while (count--) {
902 QUICK_LOOP_DELAY;
903 if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
904 test4(printk(" %d ", QUICK_LOOP_COUNT - count));
905 goto data_immediately;
906 }
907 }
908 test4(printk("ended "));
909 }
910 break;
911 }
912 break;
913
914 case MCD_S_STOP:
915 test3(printk("MCD_S_STOP\n"));
916 if (!mitsumi_bug_93_wait)
917 goto do_not_work_around_mitsumi_bug_93_1;
918
919 McdTimeout = mitsumi_bug_93_wait;
920 mcd_state = 9 + 3 + 1;
921 break;
922
923 case 9 + 3 + 1:
924 if (McdTimeout)
925 break;
926
927 do_not_work_around_mitsumi_bug_93_1:
928 outb(MCMD_STOP, MCDPORT(0));
929 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
930 int i = 4096;
931 do {
932 inb(MCDPORT(0));
933 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
934 outb(MCMD_STOP, MCDPORT(0));
935 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
936 i = 4096;
937 do {
938 inb(MCDPORT(0));
939 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
940 outb(MCMD_STOP, MCDPORT(0));
941 }
942 }
943
944 mcd_state = MCD_S_STOPPING;
945 McdTimeout = 1000;
946 break;
947
948 case MCD_S_STOPPING:
949 test3(printk("MCD_S_STOPPING\n"));
950 if ((st = mcdStatus()) == -1 && McdTimeout)
951 break;
952
953 if ((st != -1) && (st & MST_DSK_CHG)) {
954 mcdDiskChanged = 1;
955 tocUpToDate = 0;
956 mcd_invalidate_buffers();
957 }
958 if (!mitsumi_bug_93_wait)
959 goto do_not_work_around_mitsumi_bug_93_2;
960
961 McdTimeout = mitsumi_bug_93_wait;
962 mcd_state = 9 + 3 + 2;
963 break;
964
965 case 9 + 3 + 2:
966 if (McdTimeout)
967 break;
968 st = -1;
969
970 do_not_work_around_mitsumi_bug_93_2:
971 test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
972 mcd_mode));
973 if (current_valid()) {
974 if (st != -1) {
975 if (mcd_mode == 1)
976 goto read_immediately;
977 else
978 goto set_mode_immediately;
979 } else {
980 mcd_state = MCD_S_START;
981 McdTimeout = 1;
982 }
983 } else {
984 mcd_state = MCD_S_IDLE;
985 goto out;
986 }
987 break;
988 default:
989 printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
990 goto out;
991 }
992 ret:
993 if (!McdTimeout--) {
994 printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
995 mcd_state = MCD_S_STOP;
996 }
997 mcd_timer.function = mcd_poll;
998 mod_timer(&mcd_timer, jiffies + 1);
999 out:
1000 return;
1001 }
1002
1003 static void mcd_invalidate_buffers(void)
1004 {
1005 int i;
1006 for (i = 0; i < MCD_BUF_SIZ; ++i)
1007 mcd_buf_bn[i] = -1;
1008 mcd_buf_out = -1;
1009 }
1010
1011 /*
1012 * Open the device special file. Check that a disk is in.
1013 */
1014 static int mcd_open(struct cdrom_device_info *cdi, int purpose)
1015 {
1016 int st, count = 0;
1017 if (mcdPresent == 0)
1018 return -ENXIO; /* no hardware */
1019
1020 if (mcd_open_count || mcd_state != MCD_S_IDLE)
1021 goto bump_count;
1022
1023 mcd_invalidate_buffers();
1024 do {
1025 st = statusCmd(); /* check drive status */
1026 if (st == -1)
1027 goto err_out; /* drive doesn't respond */
1028 if ((st & MST_READY) == 0) /* no disk? wait a sec... */
1029 msleep(1000);
1030
1031 } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1032
1033 if (updateToc() < 0)
1034 goto err_out;
1035
1036 bump_count:
1037 ++mcd_open_count;
1038 return 0;
1039
1040 err_out:
1041 return -EIO;
1042 }
1043
1044
1045 /*
1046 * On close, we flush all mcd blocks from the buffer cache.
1047 */
1048 static void mcd_release(struct cdrom_device_info *cdi)
1049 {
1050 if (!--mcd_open_count) {
1051 mcd_invalidate_buffers();
1052 }
1053 }
1054
1055 /*
1056 * Test for presence of drive and initialize it. Called at boot time.
1057 */
1058
1059 int __init mcd_init(void)
1060 {
1061 struct gendisk *disk = alloc_disk(1);
1062 int count;
1063 unsigned char result[3];
1064 char msg[80];
1065
1066 if (!disk) {
1067 printk(KERN_INFO "mcd: can't allocated disk.\n");
1068 return -ENOMEM;
1069 }
1070 if (mcd_port <= 0 || mcd_irq <= 0) {
1071 printk(KERN_INFO "mcd: not probing.\n");
1072 put_disk(disk);
1073 return -EIO;
1074 }
1075 if (register_blkdev(MAJOR_NR, "mcd")) {
1076 put_disk(disk);
1077 return -EIO;
1078 }
1079 if (!request_region(mcd_port, 4, "mcd")) {
1080 printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
1081 goto out_region;
1082 }
1083
1084 mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
1085 if (!mcd_queue)
1086 goto out_queue;
1087
1088 /* check for card */
1089
1090 outb(0, MCDPORT(1)); /* send reset */
1091 for (count = 0; count < 2000000; count++)
1092 (void) inb(MCDPORT(1)); /* delay a bit */
1093
1094 outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1095 for (count = 0; count < 2000000; count++)
1096 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1097 break;
1098
1099 if (count >= 2000000) {
1100 printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
1101 mcd_port, mcd_irq);
1102 goto out_probe;
1103 }
1104 count = inb(MCDPORT(0)); /* pick up the status */
1105
1106 outb(MCMD_GET_VERSION, MCDPORT(0));
1107 for (count = 0; count < 3; count++)
1108 if (getValue(result + count)) {
1109 printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
1110 mcd_port);
1111 goto out_probe;
1112 }
1113
1114 if (result[0] == result[1] && result[1] == result[2])
1115 goto out_probe;
1116
1117 mcdVersion = result[2];
1118
1119 if (mcdVersion >= 4)
1120 outb(4, MCDPORT(2)); /* magic happens */
1121
1122 /* don't get the IRQ until we know for sure the drive is there */
1123
1124 if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
1125 printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1126 goto out_probe;
1127 }
1128
1129 if (result[1] == 'D') {
1130 MCMD_DATA_READ = MCMD_2X_READ;
1131 /* Added flag to drop to 1x speed if too many errors */
1132 mcdDouble = 1;
1133 } else
1134 mcd_info.speed = 1;
1135 sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1136 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
1137 mcd_port, mcd_irq);
1138
1139 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1140 outb(0x02, MCDPORT(0));
1141 outb(0x00, MCDPORT(0));
1142 getValue(result);
1143
1144 outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1145 outb(0x10, MCDPORT(0));
1146 outb(0x04, MCDPORT(0));
1147 getValue(result);
1148
1149 mcd_invalidate_buffers();
1150 mcdPresent = 1;
1151
1152 disk->major = MAJOR_NR;
1153 disk->first_minor = 0;
1154 sprintf(disk->disk_name, "mcd");
1155 disk->fops = &mcd_bdops;
1156 disk->flags = GENHD_FL_CD;
1157 mcd_gendisk = disk;
1158
1159 if (register_cdrom(&mcd_info) != 0) {
1160 printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
1161 goto out_cdrom;
1162 }
1163 disk->queue = mcd_queue;
1164 add_disk(disk);
1165 printk(msg);
1166 return 0;
1167
1168 out_cdrom:
1169 free_irq(mcd_irq, NULL);
1170 out_queue:
1171 release_region(mcd_port, 4);
1172 out_probe:
1173 blk_cleanup_queue(mcd_queue);
1174 out_region:
1175 unregister_blkdev(MAJOR_NR, "mcd");
1176 put_disk(disk);
1177 return -EIO;
1178 }
1179
1180
1181 static void hsg2msf(long hsg, struct msf *msf)
1182 {
1183 hsg += 150;
1184 msf->min = hsg / 4500;
1185 hsg %= 4500;
1186 msf->sec = hsg / 75;
1187 msf->frame = hsg % 75;
1188
1189 bin2bcd(&msf->min); /* convert to BCD */
1190 bin2bcd(&msf->sec);
1191 bin2bcd(&msf->frame);
1192 }
1193
1194
1195 static void bin2bcd(unsigned char *p)
1196 {
1197 int u, t;
1198
1199 u = *p % 10;
1200 t = *p / 10;
1201 *p = u | (t << 4);
1202 }
1203
1204 static int bcd2bin(unsigned char bcd)
1205 {
1206 return (bcd >> 4) * 10 + (bcd & 0xF);
1207 }
1208
1209
1210 /*
1211 * See if a status is ready from the drive and return it
1212 * if it is ready.
1213 */
1214
1215 static int mcdStatus(void)
1216 {
1217 int i;
1218 int st;
1219
1220 st = inb(MCDPORT(1)) & MFL_STATUS;
1221 if (!st) {
1222 i = inb(MCDPORT(0)) & 0xFF;
1223 return i;
1224 } else
1225 return -1;
1226 }
1227
1228
1229 /*
1230 * Send a play or read command to the drive
1231 */
1232
1233 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1234 {
1235 outb(cmd, MCDPORT(0));
1236 outb(params->start.min, MCDPORT(0));
1237 outb(params->start.sec, MCDPORT(0));
1238 outb(params->start.frame, MCDPORT(0));
1239 outb(params->end.min, MCDPORT(0));
1240 outb(params->end.sec, MCDPORT(0));
1241 outb(params->end.frame, MCDPORT(0));
1242 }
1243
1244
1245 /*
1246 * Timer interrupt routine to test for status ready from the drive.
1247 * (see the next routine)
1248 */
1249
1250 static void mcdStatTimer(unsigned long dummy)
1251 {
1252 if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
1253 wake_up(&mcd_waitq);
1254 return;
1255 }
1256
1257 McdTimeout--;
1258 if (McdTimeout <= 0) {
1259 wake_up(&mcd_waitq);
1260 return;
1261 }
1262 mcd_timer.function = mcdStatTimer;
1263 mod_timer(&mcd_timer, jiffies + 1);
1264 }
1265
1266
1267 /*
1268 * Wait for a status to be returned from the drive. The actual test
1269 * (see routine above) is done by the timer interrupt to avoid
1270 * excessive rescheduling.
1271 */
1272
1273 static int getMcdStatus(int timeout)
1274 {
1275 int st;
1276
1277 McdTimeout = timeout;
1278 mcd_timer.function = mcdStatTimer;
1279 mod_timer(&mcd_timer, jiffies + 1);
1280 sleep_on(&mcd_waitq);
1281 if (McdTimeout <= 0)
1282 return -1;
1283
1284 st = inb(MCDPORT(0)) & 0xFF;
1285 if (st == 0xFF)
1286 return -1;
1287
1288 if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1289 /* XXX might be an error? look at q-channel? */
1290 audioStatus = CDROM_AUDIO_COMPLETED;
1291
1292 if (st & MST_DSK_CHG) {
1293 mcdDiskChanged = 1;
1294 tocUpToDate = 0;
1295 audioStatus = CDROM_AUDIO_NO_STATUS;
1296 }
1297
1298 return st;
1299 }
1300
1301
1302 /* gives current state of the drive This function is quite unreliable,
1303 and should probably be rewritten by someone, eventually... */
1304
1305 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1306 {
1307 int st;
1308
1309 st = statusCmd(); /* check drive status */
1310 if (st == -1)
1311 return -EIO; /* drive doesn't respond */
1312 if ((st & MST_READY))
1313 return CDS_DISC_OK;
1314 if ((st & MST_DOOR_OPEN))
1315 return CDS_TRAY_OPEN;
1316 if ((st & MST_DSK_CHG))
1317 return CDS_NO_DISC;
1318 if ((st & MST_BUSY))
1319 return CDS_DRIVE_NOT_READY;
1320 return -EIO;
1321 }
1322
1323
1324 /*
1325 * Read a value from the drive.
1326 */
1327
1328 static int getValue(unsigned char *result)
1329 {
1330 int count;
1331 int s;
1332
1333 for (count = 0; count < 2000; count++)
1334 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1335 break;
1336
1337 if (count >= 2000) {
1338 printk("mcd: getValue timeout\n");
1339 return -1;
1340 }
1341
1342 s = inb(MCDPORT(0)) & 0xFF;
1343 *result = (unsigned char) s;
1344 return 0;
1345 }
1346
1347 /*
1348 * Read the current Q-channel info. Also used for reading the
1349 * table of contents.
1350 */
1351
1352 int GetQChannelInfo(struct mcd_Toc *qp)
1353 {
1354 unsigned char notUsed;
1355 int retry;
1356
1357 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1358 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1359 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1360 break;
1361 }
1362
1363 if (retry >= MCD_RETRY_ATTEMPTS)
1364 return -1;
1365
1366 if (getValue(&qp->ctrl_addr) < 0)
1367 return -1;
1368 if (getValue(&qp->track) < 0)
1369 return -1;
1370 if (getValue(&qp->pointIndex) < 0)
1371 return -1;
1372 if (getValue(&qp->trackTime.min) < 0)
1373 return -1;
1374 if (getValue(&qp->trackTime.sec) < 0)
1375 return -1;
1376 if (getValue(&qp->trackTime.frame) < 0)
1377 return -1;
1378 if (getValue(¬Used) < 0)
1379 return -1;
1380 if (getValue(&qp->diskTime.min) < 0)
1381 return -1;
1382 if (getValue(&qp->diskTime.sec) < 0)
1383 return -1;
1384 if (getValue(&qp->diskTime.frame) < 0)
1385 return -1;
1386
1387 return 0;
1388 }
1389
1390 /*
1391 * Read the table of contents (TOC) and TOC header if necessary
1392 */
1393
1394 static int updateToc(void)
1395 {
1396 if (tocUpToDate)
1397 return 0;
1398
1399 if (GetDiskInfo() < 0)
1400 return -EIO;
1401
1402 if (GetToc() < 0)
1403 return -EIO;
1404
1405 tocUpToDate = 1;
1406 return 0;
1407 }
1408
1409 /*
1410 * Read the table of contents header
1411 */
1412
1413 static int GetDiskInfo(void)
1414 {
1415 int retry;
1416
1417 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1418 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1419 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1420 break;
1421 }
1422
1423 if (retry >= MCD_RETRY_ATTEMPTS)
1424 return -1;
1425
1426 if (getValue(&DiskInfo.first) < 0)
1427 return -1;
1428 if (getValue(&DiskInfo.last) < 0)
1429 return -1;
1430
1431 DiskInfo.first = bcd2bin(DiskInfo.first);
1432 DiskInfo.last = bcd2bin(DiskInfo.last);
1433
1434 #ifdef MCD_DEBUG
1435 printk
1436 ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1437 DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
1438 DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
1439 DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
1440 DiskInfo.firstTrack.frame);
1441 #endif
1442
1443 if (getValue(&DiskInfo.diskLength.min) < 0)
1444 return -1;
1445 if (getValue(&DiskInfo.diskLength.sec) < 0)
1446 return -1;
1447 if (getValue(&DiskInfo.diskLength.frame) < 0)
1448 return -1;
1449 if (getValue(&DiskInfo.firstTrack.min) < 0)
1450 return -1;
1451 if (getValue(&DiskInfo.firstTrack.sec) < 0)
1452 return -1;
1453 if (getValue(&DiskInfo.firstTrack.frame) < 0)
1454 return -1;
1455
1456 return 0;
1457 }
1458
1459 /*
1460 * Read the table of contents (TOC)
1461 */
1462
1463 static int GetToc(void)
1464 {
1465 int i, px;
1466 int limit;
1467 int retry;
1468 struct mcd_Toc qInfo;
1469
1470 for (i = 0; i < MAX_TRACKS; i++)
1471 Toc[i].pointIndex = 0;
1472
1473 i = DiskInfo.last + 3;
1474
1475 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1476 outb(MCMD_STOP, MCDPORT(0));
1477 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1478 break;
1479 }
1480
1481 if (retry >= MCD_RETRY_ATTEMPTS)
1482 return -1;
1483
1484 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1485 outb(MCMD_SET_MODE, MCDPORT(0));
1486 outb(0x05, MCDPORT(0)); /* mode: toc */
1487 mcd_mode = 0x05;
1488 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1489 break;
1490 }
1491
1492 if (retry >= MCD_RETRY_ATTEMPTS)
1493 return -1;
1494
1495 for (limit = 300; limit > 0; limit--) {
1496 if (GetQChannelInfo(&qInfo) < 0)
1497 break;
1498
1499 px = bcd2bin(qInfo.pointIndex);
1500 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1501 if (Toc[px].pointIndex == 0) {
1502 Toc[px] = qInfo;
1503 i--;
1504 }
1505
1506 if (i <= 0)
1507 break;
1508 }
1509
1510 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1511
1512 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1513 outb(MCMD_SET_MODE, MCDPORT(0));
1514 outb(0x01, MCDPORT(0));
1515 mcd_mode = 1;
1516 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1517 break;
1518 }
1519
1520 #ifdef MCD_DEBUG
1521 for (i = 1; i <= DiskInfo.last; i++)
1522 printk
1523 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1524 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1525 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1526 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1527 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1528 for (i = 100; i < 103; i++)
1529 printk
1530 ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1531 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1532 Toc[i].trackTime.min, Toc[i].trackTime.sec,
1533 Toc[i].trackTime.frame, Toc[i].diskTime.min,
1534 Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1535 #endif
1536
1537 return limit > 0 ? 0 : -1;
1538 }
1539
1540 void __exit mcd_exit(void)
1541 {
1542 del_gendisk(mcd_gendisk);
1543 put_disk(mcd_gendisk);
1544 if (unregister_cdrom(&mcd_info)) {
1545 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1546 return;
1547 }
1548 free_irq(mcd_irq, NULL);
1549 release_region(mcd_port, 4);
1550 if (unregister_blkdev(MAJOR_NR, "mcd")) {
1551 printk(KERN_WARNING "Can't unregister major mcd\n");
1552 return;
1553 }
1554 blk_cleanup_queue(mcd_queue);
1555 del_timer_sync(&mcd_timer);
1556 }
1557
1558 #ifdef MODULE
1559 module_init(mcd_init);
1560 #endif
1561 module_exit(mcd_exit);
1562
1563 MODULE_AUTHOR("Martin Harriss");
1564 MODULE_LICENSE("GPL");
1565 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);
1566
|
This page was automatically generated by the
LXR engine.
|