This source file includes following definitions.
- mcd_setup
- check_mcd_media_change
- statusCmd
- mcdPlay
- msf2hsg
- mcd_ioctl
- mcd_transfer
- mcd_interrupt
- do_mcd_request
- mcd_start
- mcd_status
- mcd_read_cmd
- mcd_data
- mcd_open
- mcd_release
- mcd_init
- hsg2msf
- bin2bcd
- bcd2bin
- mcdStatus
- sendMcdCmd
- mcdStatTimer
- getMcdStatus
- getValue
- GetQChannelInfo
- updateToc
- GetDiskInfo
- GetToc
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 #include <linux/errno.h>
37 #include <linux/signal.h>
38 #include <linux/sched.h>
39 #include <linux/timer.h>
40 #include <linux/fs.h>
41 #include <linux/kernel.h>
42 #include <linux/cdrom.h>
43 #include <linux/ioport.h>
44
45
46 #include <asm/system.h>
47 #include <asm/io.h>
48 #include <asm/segment.h>
49
50 #define MAJOR_NR MITSUMI_CDROM_MAJOR
51 #include "blk.h"
52 #include <linux/mcd.h>
53
54 #if 0
55 static int mcd_sizes[] = { 0 };
56 #endif
57
58 static int mcdPresent = 0;
59
60 static char mcd_buf[2048];
61 static int mcd_bn = -1;
62 static short mcd_port = MCD_BASE_ADDR;
63 static int mcd_irq = MCD_INTR_NR;
64
65 static int McdTimeout, McdTries;
66 static struct wait_queue *mcd_waitq = NULL;
67
68 static struct mcd_DiskInfo DiskInfo;
69 static struct mcd_Toc Toc[MAX_TRACKS];
70 static struct mcd_Play_msf mcd_Play;
71
72 static int audioStatus;
73 static char mcdDiskChanged;
74 static char tocUpToDate;
75 static char mcdVersion;
76
77 static void mcd_transfer(void);
78 static void mcd_start(void);
79 static void mcd_status(void);
80 static void mcd_read_cmd(void);
81 static void mcd_data(void);
82 static void do_mcd_request(void);
83 static void hsg2msf(long hsg, struct msf *msf);
84 static void bin2bcd(unsigned char *p);
85 static int bcd2bin(unsigned char bcd);
86 static int mcdStatus(void);
87 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
88 static int getMcdStatus(int timeout);
89 static int GetQChannelInfo(struct mcd_Toc *qp);
90 static int updateToc(void);
91 static int GetDiskInfo(void);
92 static int GetToc(void);
93 static int getValue(unsigned char *result);
94
95
96 void mcd_setup(char *str, int *ints)
97 {
98 if (ints[0] > 0)
99 mcd_port = ints[1];
100 if (ints[0] > 1)
101 mcd_irq = ints[2];
102 }
103
104
105 int
106 check_mcd_media_change(int full_dev, int flag)
107 {
108 int retval, target;
109
110
111 #if 1
112 return 0;
113 #endif
114 target = MINOR(full_dev);
115
116 if (target > 0) {
117 printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
118 return 0;
119 }
120
121 retval = mcdDiskChanged;
122 if (!flag)
123 {
124 mcdDiskChanged = 0;
125 }
126
127 return retval;
128 }
129
130
131
132
133
134
135
136 static int
137 statusCmd(void)
138 {
139 int st, retry;
140
141 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
142 {
143
144 outb(MCMD_GET_STATUS, MCDPORT(0));
145 st = getMcdStatus(MCD_STATUS_DELAY);
146 if (st != -1)
147 break;
148 }
149
150 return st;
151 }
152
153
154
155
156
157
158 static int
159 mcdPlay(struct mcd_Play_msf *arg)
160 {
161 int retry, st;
162
163 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
164 {
165 sendMcdCmd(MCMD_PLAY_READ, arg);
166 st = getMcdStatus(2 * MCD_STATUS_DELAY);
167 if (st != -1)
168 break;
169 }
170
171 return st;
172 }
173
174
175 long
176 msf2hsg(struct msf *mp)
177 {
178 return bcd2bin(mp -> frame)
179 + bcd2bin(mp -> sec) * 75
180 + bcd2bin(mp -> min) * 4500
181 - 150;
182 }
183
184
185 static int
186 mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
187 unsigned long arg)
188 {
189 int i, st;
190 struct mcd_Toc qInfo;
191 struct cdrom_ti ti;
192 struct cdrom_tochdr tocHdr;
193 struct cdrom_msf msf;
194 struct cdrom_tocentry entry;
195 struct mcd_Toc *tocPtr;
196 struct cdrom_subchnl subchnl;
197 #if 0
198 struct cdrom_volctrl volctrl;
199 #endif
200
201 if (!ip)
202 return -EINVAL;
203
204 st = statusCmd();
205 if (st < 0)
206 return -EIO;
207
208 if (!tocUpToDate)
209 {
210 i = updateToc();
211 if (i < 0)
212 return i;
213 }
214
215 switch (cmd)
216 {
217 case CDROMSTART:
218
219
220
221
222
223 return 0;
224
225 case CDROMSTOP:
226 outb(MCMD_STOP, MCDPORT(0));
227 i = getMcdStatus(MCD_STATUS_DELAY);
228
229
230
231 audioStatus = CDROM_AUDIO_NO_STATUS;
232 return 0;
233
234 case CDROMPAUSE:
235 if (audioStatus != CDROM_AUDIO_PLAY)
236 return -EINVAL;
237
238 outb(MCMD_STOP, MCDPORT(0));
239 i = getMcdStatus(MCD_STATUS_DELAY);
240
241 if (GetQChannelInfo(&qInfo) < 0)
242 {
243
244
245 audioStatus = CDROM_AUDIO_NO_STATUS;
246 return 0;
247 }
248
249 mcd_Play.start = qInfo.diskTime;
250
251 audioStatus = CDROM_AUDIO_PAUSED;
252 return 0;
253
254 case CDROMRESUME:
255 if (audioStatus != CDROM_AUDIO_PAUSED)
256 return -EINVAL;
257
258
259
260 i = mcdPlay(&mcd_Play);
261 if (i < 0)
262 {
263 audioStatus = CDROM_AUDIO_ERROR;
264 return -EIO;
265 }
266
267 audioStatus = CDROM_AUDIO_PLAY;
268 return 0;
269
270 case CDROMPLAYTRKIND:
271
272 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
273 if (st)
274 return st;
275
276 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
277
278 if (ti.cdti_trk0 < DiskInfo.first
279 || ti.cdti_trk0 > DiskInfo.last
280 || ti.cdti_trk1 < ti.cdti_trk0)
281 {
282 return -EINVAL;
283 }
284
285 if (ti.cdti_trk1 > DiskInfo.last)
286 ti. cdti_trk1 = DiskInfo.last;
287
288 mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
289 mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
290
291 #ifdef MCD_DEBUG
292 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
293 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
294 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
295 #endif
296
297 i = mcdPlay(&mcd_Play);
298 if (i < 0)
299 {
300 audioStatus = CDROM_AUDIO_ERROR;
301 return -EIO;
302 }
303
304 audioStatus = CDROM_AUDIO_PLAY;
305 return 0;
306
307 case CDROMPLAYMSF:
308
309 if (audioStatus == CDROM_AUDIO_PLAY) {
310 outb(MCMD_STOP, MCDPORT(0));
311 i = getMcdStatus(MCD_STATUS_DELAY);
312 audioStatus = CDROM_AUDIO_NO_STATUS;
313 }
314
315 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
316 if (st)
317 return st;
318
319 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
320
321
322
323 bin2bcd(&msf.cdmsf_min0);
324 bin2bcd(&msf.cdmsf_sec0);
325 bin2bcd(&msf.cdmsf_frame0);
326 bin2bcd(&msf.cdmsf_min1);
327 bin2bcd(&msf.cdmsf_sec1);
328 bin2bcd(&msf.cdmsf_frame1);
329
330 mcd_Play.start.min = msf.cdmsf_min0;
331 mcd_Play.start.sec = msf.cdmsf_sec0;
332 mcd_Play.start.frame = msf.cdmsf_frame0;
333 mcd_Play.end.min = msf.cdmsf_min1;
334 mcd_Play.end.sec = msf.cdmsf_sec1;
335 mcd_Play.end.frame = msf.cdmsf_frame1;
336
337 #ifdef MCD_DEBUG
338 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
339 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
340 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
341 #endif
342
343 i = mcdPlay(&mcd_Play);
344 if (i < 0)
345 {
346 audioStatus = CDROM_AUDIO_ERROR;
347 return -EIO;
348 }
349
350 audioStatus = CDROM_AUDIO_PLAY;
351 return 0;
352
353 case CDROMREADTOCHDR:
354 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
355 if (st)
356 return st;
357
358 tocHdr.cdth_trk0 = DiskInfo.first;
359 tocHdr.cdth_trk1 = DiskInfo.last;
360 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
361 return 0;
362
363 case CDROMREADTOCENTRY:
364
365 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
366 if (st)
367 return st;
368
369 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
370 if (entry.cdte_track == CDROM_LEADOUT)
371
372 tocPtr = &Toc[DiskInfo.last + 1];
373
374 else if (entry.cdte_track > DiskInfo.last
375 || entry.cdte_track < DiskInfo.first)
376 return -EINVAL;
377
378 else
379 tocPtr = &Toc[entry.cdte_track];
380
381 entry.cdte_adr = tocPtr -> ctrl_addr;
382 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
383
384 if (entry.cdte_format == CDROM_LBA)
385 entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
386
387 else if (entry.cdte_format == CDROM_MSF)
388 {
389 entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
390 entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
391 entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
392 }
393
394 else
395 return -EINVAL;
396
397 memcpy_tofs((void *) arg, &entry, sizeof entry);
398 return 0;
399
400 case CDROMSUBCHNL:
401
402 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
403 if (st)
404 return st;
405
406 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
407
408 if (GetQChannelInfo(&qInfo) < 0)
409 return -EIO;
410
411 subchnl.cdsc_audiostatus = audioStatus;
412 subchnl.cdsc_adr = qInfo.ctrl_addr;
413 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
414 subchnl.cdsc_trk = bcd2bin(qInfo.track);
415 subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
416
417 if (subchnl.cdsc_format == CDROM_LBA)
418 {
419 subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
420 subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
421 }
422
423 else if (subchnl.cdsc_format == CDROM_MSF)
424 {
425 subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
426 subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
427 subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
428
429 subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
430 subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
431 subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
432 }
433
434 else
435 return -EINVAL;
436
437 memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
438 return 0;
439
440 case CDROMVOLCTRL:
441
442
443
444
445
446 #if 0
447 st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
448 if (st)
449 return st;
450
451 memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
452 printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF);
453 outb(MCMD_SET_VOLUME, MCDPORT(0));
454 outb(volctrl.channel0, MCDPORT(0));
455 outb(0, MCDPORT(0));
456 outb(volctrl.channel1, MCDPORT(0));
457 outb(1, MCDPORT(0));
458
459 i = getMcdStatus(MCD_STATUS_DELAY);
460 if (i < 0)
461 return -EIO;
462
463 {
464 int a, b, c, d;
465
466 getValue(&a);
467 getValue(&b);
468 getValue(&c);
469 getValue(&d);
470 printk("%02X %02X %02X %02X\n", a, b, c, d);
471 }
472
473 outb(0xF8, MCDPORT(0));
474 i = getMcdStatus(MCD_STATUS_DELAY);
475 printk("F8 -> %02X\n", i & 0xFF);
476 #endif
477 return 0;
478
479 case CDROMEJECT:
480
481 if (audioStatus == CDROM_AUDIO_PLAY) {
482 outb(MCMD_STOP, MCDPORT(0));
483 i = getMcdStatus(MCD_STATUS_DELAY);
484 }
485
486 audioStatus = CDROM_AUDIO_NO_STATUS;
487
488 outb(MCMD_EJECT, MCDPORT(0));
489
490
491
492
493
494 i = getMcdStatus(MCD_STATUS_DELAY);
495 return 0;
496 default:
497 return -EINVAL;
498 }
499 }
500
501
502
503
504
505
506
507 static void
508 mcd_transfer(void)
509 {
510 long offs;
511
512 while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4)
513 {
514 offs = (CURRENT -> sector & 3) * 512;
515 memcpy(CURRENT -> buffer, mcd_buf + offs, 512);
516 CURRENT -> nr_sectors--;
517 CURRENT -> sector++;
518 CURRENT -> buffer += 512;
519 }
520 }
521
522
523
524
525
526
527
528 static void
529 mcd_interrupt(int unused)
530 {
531 int st;
532
533 st = inb(MCDPORT(1)) & 0xFF;
534 if (st != 0xFF)
535 {
536 st = inb(MCDPORT(0)) & 0xFF;
537 #if 0
538 printk("<int-%02X>", st);
539 #endif
540 }
541 }
542
543
544
545
546
547
548 static void
549 do_mcd_request(void)
550 {
551 unsigned int block,dev;
552 unsigned int nsect;
553
554 repeat:
555 if (!(CURRENT) || CURRENT->dev < 0) return;
556 INIT_REQUEST;
557 dev = MINOR(CURRENT->dev);
558 block = CURRENT->sector;
559 nsect = CURRENT->nr_sectors;
560
561 if (CURRENT == NULL || CURRENT -> sector == -1)
562 return;
563
564 if (CURRENT -> cmd != READ)
565 {
566 printk("mcd: bad cmd %d\n", CURRENT -> cmd);
567 end_request(0);
568 goto repeat;
569 }
570
571 mcd_transfer();
572
573
574
575 if (CURRENT -> nr_sectors == 0)
576 {
577 end_request(1);
578 goto repeat;
579 }
580
581 McdTries = MCD_RETRY_ATTEMPTS;
582 mcd_start();
583 }
584
585
586
587
588
589
590 static void
591 mcd_start()
592 {
593 if (McdTries == 0)
594 {
595 printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS);
596 end_request(0);
597 SET_TIMER(do_mcd_request, 1);
598 return;
599 }
600
601 McdTries--;
602 outb(0x40, MCDPORT(0));
603 McdTimeout = MCD_STATUS_DELAY;
604 SET_TIMER(mcd_status, 1);
605 }
606
607
608
609
610
611
612
613 static void
614 mcd_status()
615 {
616 int st;
617
618 McdTimeout--;
619 st = mcdStatus();
620 if (st == -1)
621 {
622 if (McdTimeout == 0)
623 {
624 printk("mcd: status timed out\n");
625 SET_TIMER(mcd_start, 1);
626 return;
627 }
628
629 SET_TIMER(mcd_status, 1);
630 return;
631 }
632
633 if (st & MST_DSK_CHG)
634 {
635 mcdDiskChanged = 1;
636 }
637
638 if ((st & MST_READY) == 0)
639 {
640 printk("mcd: disk removed\n");
641 mcdDiskChanged = 1;
642 end_request(0);
643 do_mcd_request();
644 return;
645 }
646
647 outb(0x50, MCDPORT(0));
648 outb(0x01, MCDPORT(0));
649 McdTimeout = 100;
650 SET_TIMER(mcd_read_cmd, 1);
651 }
652
653
654
655
656
657
658
659 static void
660 mcd_read_cmd()
661 {
662 int st;
663 long block;
664 struct mcd_Play_msf mcdcmd;
665
666 McdTimeout--;
667 st = mcdStatus();
668
669 if (st & MST_DSK_CHG)
670 {
671 mcdDiskChanged = 1;
672 }
673
674 if (st == -1)
675 {
676 if (McdTimeout == 0)
677 {
678 printk("mcd: set mode timed out\n");
679 SET_TIMER(mcd_start, 1);
680 return;
681 }
682
683 SET_TIMER(mcd_read_cmd, 1);
684 return;
685 }
686
687 mcd_bn = -1;
688 block = CURRENT -> sector / 4;
689 hsg2msf(block, &mcdcmd.start);
690
691 mcdcmd.end.min = 0;
692 mcdcmd.end.sec = 0;
693 mcdcmd.end.frame = 1;
694
695 sendMcdCmd(MCMD_PLAY_READ, &mcdcmd);
696 McdTimeout = 200;
697 SET_TIMER(mcd_data, 1);
698 }
699
700
701
702
703
704
705
706 static void
707 mcd_data()
708 {
709 int i;
710
711 McdTimeout--;
712 cli();
713 i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA);
714 if (i == MFL_DATA)
715 {
716 printk("mcd: read failed\n");
717 #ifdef MCD_DEBUG
718 printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);
719 #endif
720 SET_TIMER(mcd_start, 1);
721 sti();
722 return;
723 }
724
725 if (i == (MFL_STATUS | MFL_DATA))
726 {
727 if (McdTimeout == 0)
728 {
729 printk("mcd: data timeout, retrying\n");
730 SET_TIMER(mcd_start, 1);
731 }
732
733 else
734 SET_TIMER(mcd_data, 1);
735
736 sti();
737 return;
738 }
739
740 CLEAR_TIMER;
741 READ_DATA(MCDPORT(0), &mcd_buf[0], 2048);
742 sti();
743
744 mcd_bn = CURRENT -> sector / 4;
745 mcd_transfer();
746 end_request(1);
747 SET_TIMER(do_mcd_request, 1);
748 }
749
750
751
752
753
754
755 int
756 mcd_open(struct inode *ip, struct file *fp)
757 {
758 int st;
759
760 if (mcdPresent == 0)
761 return -ENXIO;
762
763 st = statusCmd();
764 if (st == -1)
765 return -EIO;
766
767 if ((st & MST_READY) == 0)
768 {
769 printk("mcd: no disk in drive\n");
770 return -EIO;
771 }
772
773 if (updateToc() < 0)
774 return -EIO;
775
776 return 0;
777 }
778
779
780
781
782
783
784 static void
785 mcd_release(struct inode * inode, struct file * file)
786 {
787 mcd_bn = -1;
788 sync_dev(inode->i_rdev);
789 invalidate_buffers(inode -> i_rdev);
790 }
791
792
793 static struct file_operations mcd_fops = {
794 NULL,
795 block_read,
796 block_write,
797 NULL,
798 NULL,
799 mcd_ioctl,
800 NULL,
801 mcd_open,
802 mcd_release
803 };
804
805
806
807
808
809
810 static struct sigaction mcd_sigaction = {
811 mcd_interrupt,
812 0,
813 SA_INTERRUPT,
814 NULL
815 };
816
817
818
819
820
821
822 unsigned long
823 mcd_init(unsigned long mem_start, unsigned long mem_end)
824 {
825 int count;
826 unsigned char result[3];
827
828 if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
829 {
830 printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
831 MAJOR_NR);
832 return mem_start;
833 }
834
835 if (check_region(mcd_port, 4)) {
836 printk("mcd: Init failed, I/O port (%X) already in use\n",
837 mcd_port);
838 return mem_start;
839 }
840
841 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
842 read_ahead[MAJOR_NR] = 4;
843
844
845
846 outb(0, MCDPORT(1));
847 for (count = 0; count < 1000000; count++)
848 (void) inb(MCDPORT(1));
849
850 outb(0x40, MCDPORT(0));
851 for (count = 0; count < 1000000; count++)
852 if (!(inb(MCDPORT(1)) & MFL_STATUS))
853 break;
854
855 if (count >= 1000000) {
856 printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
857 mcd_port, mcd_irq);
858 return mem_start;
859 }
860 count = inb(MCDPORT(0));
861
862 outb(MCMD_GET_VERSION,MCDPORT(0));
863 for(count=0;count<3;count++)
864 if(getValue(result+count)) {
865 printk("mcd: mitsumi get version failed at 0x%d\n",
866 mcd_port);
867 return mem_start;
868 }
869
870 if (result[0] == result[1] && result[1] == result[2])
871 return mem_start;
872
873 printk("mcd: Mitsumi version : %02X %c %x\n",
874 result[0],result[1],result[2]);
875
876
877 mcdVersion=result[2];
878
879 if (mcdVersion >=4)
880 outb(4,MCDPORT(2));
881
882
883
884 if (irqaction(mcd_irq, &mcd_sigaction))
885 {
886 printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
887 return mem_start;
888 }
889 snarf_region(mcd_port, 4);
890 mcdPresent = 1;
891 printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
892 mcd_port, mcd_irq);
893 return mem_start;
894 }
895
896
897 static void
898 hsg2msf(long hsg, struct msf *msf)
899 {
900 hsg += 150;
901 msf -> min = hsg / 4500;
902 hsg %= 4500;
903 msf -> sec = hsg / 75;
904 msf -> frame = hsg % 75;
905
906 bin2bcd(&msf -> min);
907 bin2bcd(&msf -> sec);
908 bin2bcd(&msf -> frame);
909 }
910
911
912 static void
913 bin2bcd(unsigned char *p)
914 {
915 int u, t;
916
917 u = *p % 10;
918 t = *p / 10;
919 *p = u | (t << 4);
920 }
921
922 static int
923 bcd2bin(unsigned char bcd)
924 {
925 return (bcd >> 4) * 10 + (bcd & 0xF);
926 }
927
928
929
930
931
932
933
934 static int
935 mcdStatus(void)
936 {
937 int i;
938 int st;
939
940 st = inb(MCDPORT(1)) & MFL_STATUS;
941 if (!st)
942 {
943 i = inb(MCDPORT(0)) & 0xFF;
944 return i;
945 }
946 else
947 return -1;
948 }
949
950
951
952
953
954
955 static void
956 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
957 {
958 outb(cmd, MCDPORT(0));
959 outb(params -> start.min, MCDPORT(0));
960 outb(params -> start.sec, MCDPORT(0));
961 outb(params -> start.frame, MCDPORT(0));
962 outb(params -> end.min, MCDPORT(0));
963 outb(params -> end.sec, MCDPORT(0));
964 outb(params -> end.frame, MCDPORT(0));
965 }
966
967
968
969
970
971
972
973 static void
974 mcdStatTimer(void)
975 {
976 if (!(inb(MCDPORT(1)) & MFL_STATUS))
977 {
978 wake_up(&mcd_waitq);
979 return;
980 }
981
982 McdTimeout--;
983 if (McdTimeout <= 0)
984 {
985 wake_up(&mcd_waitq);
986 return;
987 }
988
989 SET_TIMER(mcdStatTimer, 1);
990 }
991
992
993
994
995
996
997
998
999 static int
1000 getMcdStatus(int timeout)
1001 {
1002 int st;
1003
1004 McdTimeout = timeout;
1005 SET_TIMER(mcdStatTimer, 1);
1006 sleep_on(&mcd_waitq);
1007 if (McdTimeout <= 0)
1008 return -1;
1009
1010 st = inb(MCDPORT(0)) & 0xFF;
1011 if (st == 0xFF)
1012 return -1;
1013
1014 if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1015
1016 audioStatus = CDROM_AUDIO_COMPLETED;
1017
1018 if (st & MST_DSK_CHG)
1019 {
1020 mcdDiskChanged = 1;
1021 tocUpToDate = 0;
1022 audioStatus = CDROM_AUDIO_NO_STATUS;
1023 }
1024
1025 return st;
1026 }
1027
1028
1029
1030
1031
1032
1033
1034 static int
1035 getValue(unsigned char *result)
1036 {
1037 int count;
1038 int s;
1039
1040 for (count = 0; count < 2000; count++)
1041 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1042 break;
1043
1044 if (count >= 2000)
1045 {
1046 printk("mcd: getValue timeout\n");
1047 return -1;
1048 }
1049
1050 s = inb(MCDPORT(0)) & 0xFF;
1051 *result = (unsigned char) s;
1052 return 0;
1053 }
1054
1055
1056
1057
1058
1059
1060
1061 int
1062 GetQChannelInfo(struct mcd_Toc *qp)
1063 {
1064 unsigned char notUsed;
1065 int retry;
1066
1067 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1068 {
1069 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1070 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1071 break;
1072 }
1073
1074 if (retry >= MCD_RETRY_ATTEMPTS)
1075 return -1;
1076
1077 if (getValue(&qp -> ctrl_addr) < 0) return -1;
1078 if (getValue(&qp -> track) < 0) return -1;
1079 if (getValue(&qp -> pointIndex) < 0) return -1;
1080 if (getValue(&qp -> trackTime.min) < 0) return -1;
1081 if (getValue(&qp -> trackTime.sec) < 0) return -1;
1082 if (getValue(&qp -> trackTime.frame) < 0) return -1;
1083 if (getValue(¬Used) < 0) return -1;
1084 if (getValue(&qp -> diskTime.min) < 0) return -1;
1085 if (getValue(&qp -> diskTime.sec) < 0) return -1;
1086 if (getValue(&qp -> diskTime.frame) < 0) return -1;
1087
1088 return 0;
1089 }
1090
1091
1092
1093
1094
1095
1096 static int
1097 updateToc()
1098 {
1099 if (tocUpToDate)
1100 return 0;
1101
1102 if (GetDiskInfo() < 0)
1103 return -EIO;
1104
1105 if (GetToc() < 0)
1106 return -EIO;
1107
1108 tocUpToDate = 1;
1109 return 0;
1110 }
1111
1112
1113
1114
1115
1116
1117 static int
1118 GetDiskInfo()
1119 {
1120 int retry;
1121
1122 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1123 {
1124 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1125 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1126 break;
1127 }
1128
1129 if (retry >= MCD_RETRY_ATTEMPTS)
1130 return -1;
1131
1132 if (getValue(&DiskInfo.first) < 0) return -1;
1133 if (getValue(&DiskInfo.last) < 0) return -1;
1134
1135 DiskInfo.first = bcd2bin(DiskInfo.first);
1136 DiskInfo.last = bcd2bin(DiskInfo.last);
1137
1138 if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1139 if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1140 if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1141 if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1142 if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1143 if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1144
1145 #ifdef MCD_DEBUG
1146 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1147 DiskInfo.first,
1148 DiskInfo.last,
1149 DiskInfo.diskLength.min,
1150 DiskInfo.diskLength.sec,
1151 DiskInfo.diskLength.frame,
1152 DiskInfo.firstTrack.min,
1153 DiskInfo.firstTrack.sec,
1154 DiskInfo.firstTrack.frame);
1155 #endif
1156
1157 return 0;
1158 }
1159
1160
1161
1162
1163
1164
1165 static int
1166 GetToc()
1167 {
1168 int i, px;
1169 int limit;
1170 int retry;
1171 struct mcd_Toc qInfo;
1172
1173 for (i = 0; i < MAX_TRACKS; i++)
1174 Toc[i].pointIndex = 0;
1175
1176 i = DiskInfo.last + 3;
1177
1178 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1179 {
1180 outb(MCMD_STOP, MCDPORT(0));
1181 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1182 break;
1183 }
1184
1185 if (retry >= MCD_RETRY_ATTEMPTS)
1186 return -1;
1187
1188 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1189 {
1190 outb(MCMD_SET_MODE, MCDPORT(0));
1191 outb(0x05, MCDPORT(0));
1192 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1193 break;
1194 }
1195
1196 if (retry >= MCD_RETRY_ATTEMPTS)
1197 return -1;
1198
1199 for (limit = 300; limit > 0; limit--)
1200 {
1201 if (GetQChannelInfo(&qInfo) < 0)
1202 break;
1203
1204 px = bcd2bin(qInfo.pointIndex);
1205 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1206 if (Toc[px].pointIndex == 0)
1207 {
1208 Toc[px] = qInfo;
1209 i--;
1210 }
1211
1212 if (i <= 0)
1213 break;
1214 }
1215
1216 Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1217
1218 for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1219 {
1220 outb(MCMD_SET_MODE, MCDPORT(0));
1221 outb(0x01, MCDPORT(0));
1222 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1223 break;
1224 }
1225
1226 #ifdef MCD_DEBUG
1227 for (i = 1; i <= DiskInfo.last; i++)
1228 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1229 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1230 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1231 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1232 for (i = 100; i < 103; i++)
1233 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n",
1234 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1235 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1236 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1237 #endif
1238
1239 return limit > 0 ? 0 : -1;
1240 }
1241