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