1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
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
108#include "mcd.h"
109
110static int mcd_blocksizes[1];
111
112
113
114static int mcdDouble;
115
116
117static int mcd1xhold;
118
119
120static int mcdPresent;
121
122#define QUICK_LOOP_DELAY udelay(45)
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
131static volatile int mcd_transfer_is_active;
132static char mcd_buf[2048 * MCD_BUF_SIZ];
133static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
134static volatile int mcd_buf_in, mcd_buf_out = -1;
135static volatile int mcd_error;
136static int mcd_open_count;
137enum mcd_state_e {
138 MCD_S_IDLE,
139 MCD_S_START,
140 MCD_S_MODE,
141 MCD_S_READ,
142 MCD_S_DATA,
143 MCD_S_STOP,
144 MCD_S_STOPPING
145};
146static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
147static int mcd_mode = -1;
148static int MCMD_DATA_READ = MCMD_PLAY_READ;
149
150#define READ_TIMEOUT 3000
151
152int mitsumi_bug_93_wait;
153
154static short mcd_port = CONFIG_MCD_BASE;
155static int mcd_irq = CONFIG_MCD_IRQ;
156MODULE_PARM(mcd, "1-2i");
157
158static int McdTimeout, McdTries;
159static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
160
161static struct mcd_DiskInfo DiskInfo;
162static struct mcd_Toc Toc[MAX_TRACKS];
163static struct mcd_Play_msf mcd_Play;
164
165static int audioStatus;
166static char mcdDiskChanged;
167static char tocUpToDate;
168static char mcdVersion;
169
170static void mcd_transfer(void);
171static void mcd_poll(unsigned long dummy);
172static void mcd_invalidate_buffers(void);
173static void hsg2msf(long hsg, struct msf *msf);
174static void bin2bcd(unsigned char *p);
175static int bcd2bin(unsigned char bcd);
176static int mcdStatus(void);
177static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
178static int getMcdStatus(int timeout);
179static int GetQChannelInfo(struct mcd_Toc *qp);
180static int updateToc(void);
181static int GetDiskInfo(void);
182static int GetToc(void);
183static int getValue(unsigned char *result);
184static int mcd_open(struct cdrom_device_info *cdi, int purpose);
185static void mcd_release(struct cdrom_device_info *cdi);
186static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
187static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
188int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
189 void *arg);
190int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
191
192struct 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
201static struct timer_list mcd_timer;
202
203static 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
214static struct cdrom_device_info mcd_info = {
215 ops:&mcd_dops,
216 speed:2,
217 capacity:1,
218 name:"mcd",
219};
220
221#ifndef MODULE
222static 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
241
242static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
243{
244 return 0;
245}
246
247
248
249
250
251
252
253static int statusCmd(void)
254{
255 int st = -1, retry;
256
257 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
258
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
272
273
274static 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
289static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
290{
291 int i;
292 if (position) {
293
294
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
305
306
307
308 i = getMcdStatus(MCD_STATUS_DELAY);
309 return 0;
310 } else
311 return -EINVAL;
312}
313
314long msf2hsg(struct msf *mp)
315{
316 return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
317}
318
319
320int 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;
341 }
342
343 switch (cmd) {
344 case CDROMSTART:
345
346
347
348
349
350 return 0;
351
352 case CDROMSTOP:
353 outb(MCMD_STOP, MCDPORT(0));
354 i = getMcdStatus(MCD_STATUS_DELAY);
355
356
357
358 audioStatus = CDROM_AUDIO_NO_STATUS;
359 return 0;
360
361 case CDROMPAUSE:
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
370
371 audioStatus = CDROM_AUDIO_NO_STATUS;
372 return 0;
373 }
374
375 mcd_Play.start = qInfo.diskTime;
376
377 audioStatus = CDROM_AUDIO_PAUSED;
378 return 0;
379
380 case CDROMRESUME:
381 if (audioStatus != CDROM_AUDIO_PAUSED)
382 return -EINVAL;
383
384
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:
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:
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
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:
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:
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:
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:
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
556
557
558
559static 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
595
596
597
598static 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
613static 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;
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
651static 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)");
665
666
667
668
669
670
671
672
673 if (mcdDouble == 1
674 && McdTries == MCD_RETRY_ATTEMPTS
675 && MCMD_DATA_READ == MCMD_2X_READ) {
676 MCMD_DATA_READ = MCMD_PLAY_READ;
677 mcd1xhold = SINGLE_HOLD_SECTORS;
678 printk(" Speed now 1x");
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
690
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
706
707
708 if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
709 && MCMD_DATA_READ == MCMD_PLAY_READ) {
710
711 if (mcd1xhold == 0) {
712 MCMD_DATA_READ = MCMD_2X_READ;
713 printk(KERN_INFO "mcd: Switching back to 2X speed!\n");
714 } else
715 mcd1xhold--;
716
717 }
718
719immediately:
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
741set_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
775read_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);
814data_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
898do_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
941do_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 }
962ret:
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);
969out:
970 return;
971}
972
973static 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
983
984static int mcd_open(struct cdrom_device_info *cdi, int purpose)
985{
986 int st, count = 0;
987 if (mcdPresent == 0)
988 return -ENXIO;
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();
996 if (st == -1)
997 goto err_out;
998 if ((st & MST_READY) == 0) {
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
1007bump_count:
1008 ++mcd_open_count;
1009 return 0;
1010
1011err_out:
1012 return -EIO;
1013}
1014
1015
1016
1017
1018
1019static void mcd_release(struct cdrom_device_info *cdi)
1020{
1021 if (!--mcd_open_count) {
1022 mcd_invalidate_buffers();
1023 }
1024}
1025
1026
1027
1028
1029
1030static 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
1055
1056
1057int __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
1083
1084 outb(0, MCDPORT(1));
1085 for (count = 0; count < 2000000; count++)
1086 (void) inb(MCDPORT(1));
1087
1088 outb(0x40, MCDPORT(0));
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));
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));
1119
1120
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
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
1167static 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);
1176 bin2bcd(&msf->sec);
1177 bin2bcd(&msf->frame);
1178}
1179
1180
1181static 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
1190static int bcd2bin(unsigned char bcd)
1191{
1192 return (bcd >> 4) * 10 + (bcd & 0xF);
1193}
1194
1195
1196
1197
1198
1199
1200
1201static 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
1217
1218
1219static 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
1233
1234
1235
1236static 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
1255
1256
1257
1258
1259static 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
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
1289
1290
1291int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1292{
1293 int st;
1294
1295 st = statusCmd();
1296 if (st == -1)
1297 return -EIO;
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
1312
1313
1314static 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
1335
1336
1337
1338int 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
1378
1379
1380static 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
1397
1398
1399static 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
1447
1448
1449static 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));
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
1526void __exit mcd_exit(void)
1527{
1528 cleanup(3);
1529 del_timer_sync(&mcd_timer);
1530}
1531
1532#ifdef MODULE
1533module_init(mcd_init);
1534#endif
1535module_exit(mcd_exit);
1536
1537MODULE_AUTHOR("Martin Harriss");
1538MODULE_LICENSE("GPL");
1539