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#if RCS
55static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57#endif
58
59#include <linux/version.h>
60#include <linux/module.h>
61
62#include <linux/errno.h>
63#include <linux/sched.h>
64#include <linux/fs.h>
65#include <linux/kernel.h>
66#include <linux/cdrom.h>
67#include <linux/ioport.h>
68#include <linux/mm.h>
69#include <linux/slab.h>
70#include <linux/init.h>
71#include <asm/io.h>
72#include <asm/uaccess.h>
73
74#include <linux/major.h>
75#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76#include <linux/blk.h>
77#include <linux/devfs_fs_kernel.h>
78
79
80#define mcdx_drive_map mcdx
81#include "mcdx.h"
82
83#if BITS_PER_LONG != 32
84# error FIXME: this driver only works on 32-bit platforms
85#endif
86
87#ifndef HZ
88#error HZ not defined
89#endif
90
91#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
92
93#if !MCDX_QUIET
94#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
95#else
96#define xinfo(fmt, args...) { ; }
97#endif
98
99#if MCDX_DEBUG
100#define xtrace(lvl, fmt, args...) \
101 { if (lvl > 0) \
102 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
103#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
104#else
105#define xtrace(lvl, fmt, args...) { ; }
106#define xdebug(fmt, args...) { ; }
107#endif
108
109
110
111
112
113
114
115
116const int REQUEST_SIZE = 800;
117const int DIRECT_SIZE = 400;
118
119enum drivemodes { TOC, DATA, RAW, COOKED };
120enum datamodes { MODE0, MODE1, MODE2 };
121enum resetmodes { SOFT, HARD };
122
123const int SINGLE = 0x01;
124const int DOUBLE = 0x02;
125const int DOOR = 0x04;
126const int MULTI = 0x08;
127
128const unsigned char READ1X = 0xc0;
129const unsigned char READ2X = 0xc1;
130
131
132
133struct s_subqcode {
134 unsigned char control;
135 unsigned char tno;
136 unsigned char index;
137 struct cdrom_msf0 tt;
138 struct cdrom_msf0 dt;
139};
140
141struct s_diskinfo {
142 unsigned int n_first;
143 unsigned int n_last;
144 struct cdrom_msf0 msf_leadout;
145 struct cdrom_msf0 msf_first;
146};
147
148struct s_multi {
149 unsigned char multi;
150 struct cdrom_msf0 msf_last;
151};
152
153struct s_version {
154 unsigned char code;
155 unsigned char ver;
156};
157
158
159
160struct s_drive_stuff {
161
162 wait_queue_head_t busyq;
163 wait_queue_head_t lockq;
164 wait_queue_head_t sleepq;
165
166
167 volatile int introk;
168 volatile int busy;
169 volatile int lock;
170
171
172 struct s_diskinfo di;
173 struct s_multi multi;
174 struct s_subqcode *toc;
175 struct s_subqcode start;
176 struct s_subqcode stop;
177 int xa;
178 int audio;
179 int audiostatus;
180
181
182 volatile int valid;
183 volatile int pending;
184 volatile int low_border;
185 volatile int high_border;
186#ifdef AK2
187 volatile int int_err;
188#endif
189
190
191 void *wreg_data;
192 void *wreg_reset;
193 void *wreg_hcon;
194 void *wreg_chn;
195 void *rreg_data;
196 void *rreg_status;
197
198 int irq;
199 int minor;
200 int present;
201 unsigned char readcmd;
202 unsigned char playcmd;
203 unsigned int xxx;
204 unsigned int yyy;
205 int users;
206 int lastsector;
207 int status;
208 int readerrs;
209};
210
211
212
213
214
215
216
217
218
219int mcdx_init(void);
220void do_mcdx_request(request_queue_t * q);
221
222struct block_device_operations mcdx_bdops =
223{
224 owner: THIS_MODULE,
225 open: cdrom_open,
226 release: cdrom_release,
227 ioctl: cdrom_ioctl,
228 check_media_change: cdrom_media_changed,
229};
230
231
232
233
234
235
236
237static void mcdx_intr(int, void *, struct pt_regs *);
238
239
240static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
241static void mcdx_close(struct cdrom_device_info *cdi);
242static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
243static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
244static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
245static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
246 unsigned int cmd, void *arg);
247
248
249static void log2msf(unsigned int, struct cdrom_msf0 *);
250static unsigned int msf2log(const struct cdrom_msf0 *);
251static unsigned int uint2bcd(unsigned int);
252static unsigned int bcd2uint(unsigned char);
253static char *port(int *);
254static int irq(int *);
255static void mcdx_delay(struct s_drive_stuff *, long jifs);
256static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
257 int nr_sectors);
258static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
259 int nr_sectors);
260
261static int mcdx_config(struct s_drive_stuff *, int);
262static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
263 int);
264static int mcdx_stop(struct s_drive_stuff *, int);
265static int mcdx_hold(struct s_drive_stuff *, int);
266static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
267static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
268static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
269static int mcdx_requestsubqcode(struct s_drive_stuff *,
270 struct s_subqcode *, int);
271static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
272 struct s_multi *, int);
273static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
274 int);
275static int mcdx_getstatus(struct s_drive_stuff *, int);
276static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
277static int mcdx_talk(struct s_drive_stuff *,
278 const unsigned char *cmd, size_t,
279 void *buffer, size_t size, unsigned int timeout, int);
280static int mcdx_readtoc(struct s_drive_stuff *);
281static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
282static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
283static int mcdx_setattentuator(struct s_drive_stuff *,
284 struct cdrom_volctrl *, int);
285
286
287
288static int mcdx_blocksizes[MCDX_NDRIVES];
289static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
290static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
291static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
292 0, 0, 0, 0, 0, 0, 0, 0
293};
294MODULE_PARM(mcdx, "1-4i");
295
296static struct cdrom_device_ops mcdx_dops = {
297 open:mcdx_open,
298 release:mcdx_close,
299 media_changed:mcdx_media_changed,
300 tray_move:mcdx_tray_move,
301 lock_door:mcdx_lockdoor,
302 audio_ioctl:mcdx_audio_ioctl,
303 capability:CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
304 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
305};
306
307static struct cdrom_device_info mcdx_info = {
308 ops:&mcdx_dops,
309 speed:2,
310 capacity:1,
311 name:"mcdx",
312};
313
314
315
316
317
318static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
319 unsigned int cmd, void *arg)
320{
321 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
322
323 if (!stuffp->present)
324 return -ENXIO;
325
326 if (stuffp->xxx) {
327 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
328 stuffp->lastsector = -1;
329 } else {
330 stuffp->lastsector = (CD_FRAMESIZE / 512)
331 * msf2log(&stuffp->di.msf_leadout) - 1;
332 }
333
334 if (stuffp->toc) {
335 kfree(stuffp->toc);
336 stuffp->toc = NULL;
337 if (-1 == mcdx_readtoc(stuffp))
338 return -1;
339 }
340
341 stuffp->xxx = 0;
342 }
343
344 switch (cmd) {
345 case CDROMSTART:{
346 xtrace(IOCTL, "ioctl() START\n");
347
348
349
350 return 0;
351 }
352
353 case CDROMSTOP:{
354 xtrace(IOCTL, "ioctl() STOP\n");
355 stuffp->audiostatus = CDROM_AUDIO_INVALID;
356 if (-1 == mcdx_stop(stuffp, 1))
357 return -EIO;
358 return 0;
359 }
360
361 case CDROMPLAYTRKIND:{
362 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
363
364 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
365 if ((ti->cdti_trk0 < stuffp->di.n_first)
366 || (ti->cdti_trk0 > stuffp->di.n_last)
367 || (ti->cdti_trk1 < stuffp->di.n_first))
368 return -EINVAL;
369 if (ti->cdti_trk1 > stuffp->di.n_last)
370 ti->cdti_trk1 = stuffp->di.n_last;
371 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
372 ti->cdti_trk0, ti->cdti_trk1);
373 return mcdx_playtrk(stuffp, ti);
374 }
375
376 case CDROMPLAYMSF:{
377 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
378
379 xtrace(IOCTL, "ioctl() PLAYMSF\n");
380
381 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
382 && (-1 == mcdx_hold(stuffp, 1)))
383 return -EIO;
384
385 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
386 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
387 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
388
389 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
390 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
391 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
392
393 stuffp->stop.dt.minute = msf->cdmsf_min1;
394 stuffp->stop.dt.second = msf->cdmsf_sec1;
395 stuffp->stop.dt.frame = msf->cdmsf_frame1;
396
397 return mcdx_playmsf(stuffp, msf);
398 }
399
400 case CDROMRESUME:{
401 xtrace(IOCTL, "ioctl() RESUME\n");
402 return mcdx_playtrk(stuffp, NULL);
403 }
404
405 case CDROMREADTOCENTRY:{
406 struct cdrom_tocentry *entry =
407 (struct cdrom_tocentry *) arg;
408 struct s_subqcode *tp = NULL;
409 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
410
411 if (-1 == mcdx_readtoc(stuffp))
412 return -1;
413 if (entry->cdte_track == CDROM_LEADOUT)
414 tp = &stuffp->toc[stuffp->di.n_last -
415 stuffp->di.n_first + 1];
416 else if (entry->cdte_track > stuffp->di.n_last
417 || entry->cdte_track < stuffp->di.n_first)
418 return -EINVAL;
419 else
420 tp = &stuffp->toc[entry->cdte_track -
421 stuffp->di.n_first];
422
423 if (NULL == tp)
424 return -EIO;
425 entry->cdte_adr = tp->control;
426 entry->cdte_ctrl = tp->control >> 4;
427
428
429 entry->cdte_addr.msf.minute =
430 bcd2uint(tp->dt.minute);
431 entry->cdte_addr.msf.second =
432 bcd2uint(tp->dt.second);
433 entry->cdte_addr.msf.frame =
434 bcd2uint(tp->dt.frame);
435 return 0;
436 }
437
438 case CDROMSUBCHNL:{
439 struct cdrom_subchnl *sub =
440 (struct cdrom_subchnl *) arg;
441 struct s_subqcode q;
442
443 xtrace(IOCTL, "ioctl() SUBCHNL\n");
444
445 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
446 return -EIO;
447
448 xtrace(SUBCHNL, "audiostatus: %x\n",
449 stuffp->audiostatus);
450 sub->cdsc_audiostatus = stuffp->audiostatus;
451 sub->cdsc_adr = q.control;
452 sub->cdsc_ctrl = q.control >> 4;
453 sub->cdsc_trk = bcd2uint(q.tno);
454 sub->cdsc_ind = bcd2uint(q.index);
455
456 xtrace(SUBCHNL, "trk %d, ind %d\n",
457 sub->cdsc_trk, sub->cdsc_ind);
458
459
460 sub->cdsc_absaddr.msf.minute =
461 bcd2uint(q.dt.minute);
462 sub->cdsc_absaddr.msf.second =
463 bcd2uint(q.dt.second);
464 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
465 sub->cdsc_reladdr.msf.minute =
466 bcd2uint(q.tt.minute);
467 sub->cdsc_reladdr.msf.second =
468 bcd2uint(q.tt.second);
469 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
470 xtrace(SUBCHNL,
471 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
472 sub->cdsc_absaddr.msf.minute,
473 sub->cdsc_absaddr.msf.second,
474 sub->cdsc_absaddr.msf.frame,
475 sub->cdsc_reladdr.msf.minute,
476 sub->cdsc_reladdr.msf.second,
477 sub->cdsc_reladdr.msf.frame);
478
479 return 0;
480 }
481
482 case CDROMREADTOCHDR:{
483 struct cdrom_tochdr *toc =
484 (struct cdrom_tochdr *) arg;
485
486 xtrace(IOCTL, "ioctl() READTOCHDR\n");
487 toc->cdth_trk0 = stuffp->di.n_first;
488 toc->cdth_trk1 = stuffp->di.n_last;
489 xtrace(TOCHDR,
490 "ioctl() track0 = %d, track1 = %d\n",
491 stuffp->di.n_first, stuffp->di.n_last);
492 return 0;
493 }
494
495 case CDROMPAUSE:{
496 xtrace(IOCTL, "ioctl() PAUSE\n");
497 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
498 return -EINVAL;
499 if (-1 == mcdx_stop(stuffp, 1))
500 return -EIO;
501 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
502 if (-1 ==
503 mcdx_requestsubqcode(stuffp, &stuffp->start,
504 1))
505 return -EIO;
506 return 0;
507 }
508
509 case CDROMMULTISESSION:{
510 struct cdrom_multisession *ms =
511 (struct cdrom_multisession *) arg;
512 xtrace(IOCTL, "ioctl() MULTISESSION\n");
513
514
515 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
516 ms->xa_flag = !!stuffp->multi.multi;
517 xtrace(MS,
518 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
519 ms->xa_flag, ms->addr.lba,
520 stuffp->multi.msf_last.minute,
521 stuffp->multi.msf_last.second,
522 stuffp->multi.msf_last.frame);
523
524 return 0;
525 }
526
527 case CDROMEJECT:{
528 xtrace(IOCTL, "ioctl() EJECT\n");
529 if (stuffp->users > 1)
530 return -EBUSY;
531 return (mcdx_tray_move(cdi, 1));
532 }
533
534 case CDROMCLOSETRAY:{
535 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
536 return (mcdx_tray_move(cdi, 0));
537 }
538
539 case CDROMVOLCTRL:{
540 struct cdrom_volctrl *volctrl =
541 (struct cdrom_volctrl *) arg;
542 xtrace(IOCTL, "ioctl() VOLCTRL\n");
543
544#if 0
545
546
547 volctrl.channel2 = volctrl.channel1;
548 volctrl.channel1 = volctrl.channel3 = 0x00;
549#endif
550 return mcdx_setattentuator(stuffp, volctrl, 2);
551 }
552
553 default:
554 return -EINVAL;
555 }
556}
557
558void do_mcdx_request(request_queue_t * q)
559{
560 int dev;
561 struct s_drive_stuff *stuffp;
562
563 again:
564
565 if (QUEUE_EMPTY) {
566 xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
567 return;
568 }
569
570 if (CURRENT->rq_status == RQ_INACTIVE) {
571 xtrace(REQUEST,
572 "end_request(0): rq_status == RQ_INACTIVE\n");
573 return;
574 }
575
576 INIT_REQUEST;
577
578 dev = MINOR(CURRENT->rq_dev);
579 stuffp = mcdx_stuffp[dev];
580
581 if ((dev < 0)
582 || (dev >= MCDX_NDRIVES)
583 || !stuffp || (!stuffp->present)) {
584 xwarn("do_request(): bad device: %s\n",
585 kdevname(CURRENT->rq_dev));
586 xtrace(REQUEST, "end_request(0): bad device\n");
587 end_request(0);
588 return;
589 }
590
591 if (stuffp->audio) {
592 xwarn("do_request() attempt to read from audio cd\n");
593 xtrace(REQUEST, "end_request(0): read from audio\n");
594 end_request(0);
595 return;
596 }
597
598 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
599 CURRENT->sector, CURRENT->nr_sectors);
600
601 switch (CURRENT->cmd) {
602 case WRITE:
603 xwarn("do_request(): attempt to write to cd!!\n");
604 xtrace(REQUEST, "end_request(0): write\n");
605 end_request(0);
606 return;
607
608 case READ:
609 stuffp->status = 0;
610 while (CURRENT->nr_sectors) {
611 int i;
612
613 i = mcdx_transfer(stuffp,
614 CURRENT->buffer,
615 CURRENT->sector,
616 CURRENT->nr_sectors);
617
618 if (i == -1) {
619 end_request(0);
620 goto again;
621 }
622 CURRENT->sector += i;
623 CURRENT->nr_sectors -= i;
624 CURRENT->buffer += (i * 512);
625 }
626 end_request(1);
627 goto again;
628
629 xtrace(REQUEST, "end_request(1)\n");
630 end_request(1);
631 break;
632
633 default:
634 panic(MCDX "do_request: unknown command.\n");
635 break;
636 }
637
638 goto again;
639}
640
641static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
642{
643 struct s_drive_stuff *stuffp;
644 xtrace(OPENCLOSE, "open()\n");
645 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
646 if (!stuffp->present)
647 return -ENXIO;
648
649
650
651
652
653
654 if (-1 == mcdx_getstatus(stuffp, 1))
655 return -EIO;
656
657 if (stuffp->xxx) {
658
659 xtrace(OPENCLOSE, "open() media changed\n");
660 stuffp->audiostatus = CDROM_AUDIO_INVALID;
661 stuffp->readcmd = 0;
662 xtrace(OPENCLOSE, "open() Request multisession info\n");
663 if (-1 ==
664 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
665 xinfo("No multidiskinfo\n");
666 } else {
667
668 if (!stuffp->multi.multi)
669 stuffp->multi.msf_last.second = 2;
670
671 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
672 stuffp->multi.multi,
673 stuffp->multi.msf_last.minute,
674 stuffp->multi.msf_last.second,
675 stuffp->multi.msf_last.frame);
676
677 {;
678 }
679
680 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
681
682 stuffp->lastsector = -1;
683
684 } else {
685
686 stuffp->lastsector = (CD_FRAMESIZE / 512)
687 * msf2log(&stuffp->di.msf_leadout) - 1;
688
689 xtrace(OPENCLOSE,
690 "open() start %d (%02x:%02x.%02x) %d\n",
691 stuffp->di.n_first,
692 stuffp->di.msf_first.minute,
693 stuffp->di.msf_first.second,
694 stuffp->di.msf_first.frame,
695 msf2log(&stuffp->di.msf_first));
696 xtrace(OPENCLOSE,
697 "open() last %d (%02x:%02x.%02x) %d\n",
698 stuffp->di.n_last,
699 stuffp->di.msf_leadout.minute,
700 stuffp->di.msf_leadout.second,
701 stuffp->di.msf_leadout.frame,
702 msf2log(&stuffp->di.msf_leadout));
703 }
704
705 if (stuffp->toc) {
706 xtrace(MALLOC, "open() free old toc @ %p\n",
707 stuffp->toc);
708 kfree(stuffp->toc);
709
710 stuffp->toc = NULL;
711 }
712
713 xtrace(OPENCLOSE, "open() init irq generation\n");
714 if (-1 == mcdx_config(stuffp, 1))
715 return -EIO;
716#if FALLBACK
717
718 xwarn("AAA %x AAA\n", stuffp->readcmd);
719 if (stuffp->readerrs)
720 stuffp->readcmd = READ1X;
721 else
722 stuffp->readcmd =
723 stuffp->present | SINGLE ? READ1X : READ2X;
724 xwarn("XXX %x XXX\n", stuffp->readcmd);
725#else
726 stuffp->readcmd =
727 stuffp->present | SINGLE ? READ1X : READ2X;
728#endif
729
730
731 if (stuffp->lastsector >= 0) {
732 char buf[512];
733 int ans;
734 int tries;
735
736 stuffp->xa = 0;
737 stuffp->audio = 0;
738
739 for (tries = 6; tries; tries--) {
740
741 stuffp->introk = 1;
742
743 xtrace(OPENCLOSE, "open() try as %s\n",
744 stuffp->xa ? "XA" : "normal");
745
746 if (-1 == (ans = mcdx_setdatamode(stuffp,
747 stuffp->
748 xa ?
749 MODE2 :
750 MODE1,
751 1))) {
752
753 stuffp->xa = 0;
754 break;
755 }
756
757 if ((stuffp->audio = e_audio(ans)))
758 break;
759
760 while (0 ==
761 (ans =
762 mcdx_transfer(stuffp, buf, 0, 1)));
763
764 if (ans == 1)
765 break;
766 stuffp->xa = !stuffp->xa;
767 }
768 }
769
770 if (-1 == mcdx_setdrivemode(stuffp,
771 stuffp->xa ? RAW : COOKED,
772 1))
773 return -EIO;
774 if (stuffp->audio) {
775 xinfo("open() audio disk found\n");
776 } else if (stuffp->lastsector >= 0) {
777 xinfo("open() %s%s disk found\n",
778 stuffp->xa ? "XA / " : "",
779 stuffp->multi.
780 multi ? "Multi Session" : "Single Session");
781 }
782 }
783 stuffp->xxx = 0;
784 stuffp->users++;
785 return 0;
786}
787
788static void mcdx_close(struct cdrom_device_info *cdi)
789{
790 struct s_drive_stuff *stuffp;
791
792 xtrace(OPENCLOSE, "close()\n");
793
794 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
795
796 --stuffp->users;
797}
798
799static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
800
801
802{
803 struct s_drive_stuff *stuffp;
804
805 xinfo("mcdx_media_changed called for device %s\n",
806 kdevname(cdi->dev));
807
808 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
809 mcdx_getstatus(stuffp, 1);
810
811 if (stuffp->yyy == 0)
812 return 0;
813
814 stuffp->yyy = 0;
815 return 1;
816}
817
818#ifndef MODULE
819static int __init mcdx_setup(char *str)
820{
821 int pi[4];
822 (void) get_options(str, ARRAY_SIZE(pi), pi);
823
824 if (pi[0] > 0)
825 mcdx_drive_map[0][0] = pi[1];
826 if (pi[0] > 1)
827 mcdx_drive_map[0][1] = pi[2];
828 return 1;
829}
830
831__setup("mcdx=", mcdx_setup);
832
833#endif
834
835
836
837static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
838
839
840
841
842
843
844
845{
846 if (jifs < 0)
847 return;
848
849 xtrace(SLEEP, "*** delay: sleepq\n");
850 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
851 xtrace(SLEEP, "delay awoken\n");
852 if (signal_pending(current)) {
853 xtrace(SLEEP, "got signal\n");
854 }
855}
856
857static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
858{
859 struct s_drive_stuff *stuffp;
860 unsigned char b;
861
862 stuffp = mcdx_irq_map[irq];
863
864 if (stuffp == NULL) {
865 xwarn("mcdx: no device for intr %d\n", irq);
866 return;
867 }
868#ifdef AK2
869 if (!stuffp->busy && stuffp->pending)
870 stuffp->int_err = 1;
871
872#endif
873
874 b = inb((unsigned int) stuffp->rreg_status);
875 stuffp->introk = ~b & MCDX_RBIT_DTEN;
876
877
878
879
880
881
882
883
884 if (!stuffp->introk) {
885 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
886 if (~b & MCDX_RBIT_STEN) {
887 xinfo("intr() irq %d status 0x%02x\n",
888 irq, inb((unsigned int) stuffp->rreg_data));
889 } else {
890 xinfo("intr() irq %d ambiguous hw status\n", irq);
891 }
892 } else {
893 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
894 }
895
896 stuffp->busy = 0;
897 wake_up_interruptible(&stuffp->busyq);
898}
899
900
901static int mcdx_talk(struct s_drive_stuff *stuffp,
902 const unsigned char *cmd, size_t cmdlen,
903 void *buffer, size_t size, unsigned int timeout, int tries)
904
905
906
907
908
909
910{
911 int st;
912 char c;
913 int discard;
914
915
916 if ((discard = (buffer == NULL)))
917 buffer = &c;
918
919 while (stuffp->lock) {
920 xtrace(SLEEP, "*** talk: lockq\n");
921 interruptible_sleep_on(&stuffp->lockq);
922 xtrace(SLEEP, "talk: awoken\n");
923 }
924
925 stuffp->lock = 1;
926
927
928
929 stuffp->valid = 0;
930
931#if MCDX_DEBUG & TALK
932 {
933 unsigned char i;
934 xtrace(TALK,
935 "talk() %d / %d tries, res.size %d, command 0x%02x",
936 tries, timeout, size, (unsigned char) cmd[0]);
937 for (i = 1; i < cmdlen; i++)
938 xtrace(TALK, " 0x%02x", cmd[i]);
939 xtrace(TALK, "\n");
940 }
941#endif
942
943
944
945 for (st = -1; st == -1 && tries; tries--) {
946
947 char *bp = (char *) buffer;
948 size_t sz = size;
949
950 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
951 xtrace(TALK, "talk() command sent\n");
952
953
954 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
955 xinfo("talk() %02x timed out (status), %d tr%s left\n",
956 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
957 continue;
958 }
959 st = *bp;
960 sz--;
961 if (!discard)
962 bp++;
963
964 xtrace(TALK, "talk() got status 0x%02x\n", st);
965
966
967 if (e_cmderr(st)) {
968 xwarn("command error cmd = %02x %s \n",
969 cmd[0], cmdlen > 1 ? "..." : "");
970 st = -1;
971 continue;
972 }
973
974
975 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
976 stuffp->audiostatus =
977 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
978 CDROM_AUDIO_NO_STATUS;
979 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
980 && e_audiobusy(st) == 0)
981 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
982
983
984 if (e_changed(st)) {
985 xinfo("talk() media changed\n");
986 stuffp->xxx = stuffp->yyy = 1;
987 }
988
989
990 while (sz--) {
991 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
992 xinfo("talk() %02x timed out (data), %d tr%s left\n",
993 cmd[0], tries - 1,
994 tries == 2 ? "y" : "ies");
995 st = -1;
996 break;
997 }
998 if (!discard)
999 bp++;
1000 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
1001 }
1002 }
1003
1004#if !MCDX_QUIET
1005 if (!tries && st == -1)
1006 xinfo("talk() giving up\n");
1007#endif
1008
1009 stuffp->lock = 0;
1010 wake_up_interruptible(&stuffp->lockq);
1011
1012 xtrace(TALK, "talk() done with 0x%02x\n", st);
1013 return st;
1014}
1015
1016
1017
1018EXPORT_NO_SYMBOLS;
1019
1020int __mcdx_init(void)
1021{
1022 int i;
1023 int drives = 0;
1024
1025 mcdx_init();
1026 for (i = 0; i < MCDX_NDRIVES; i++) {
1027 if (mcdx_stuffp[i]) {
1028 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1029 i, mcdx_stuffp[i]);
1030 drives++;
1031 }
1032 }
1033
1034 if (!drives)
1035 return -EIO;
1036
1037 return 0;
1038}
1039
1040void __exit mcdx_exit(void)
1041{
1042 int i;
1043
1044 xinfo("cleanup_module called\n");
1045
1046 for (i = 0; i < MCDX_NDRIVES; i++) {
1047 struct s_drive_stuff *stuffp;
1048 if (unregister_cdrom(&mcdx_info)) {
1049 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1050 return;
1051 }
1052 stuffp = mcdx_stuffp[i];
1053 if (!stuffp)
1054 continue;
1055 release_region((unsigned long) stuffp->wreg_data,
1056 MCDX_IO_SIZE);
1057 free_irq(stuffp->irq, NULL);
1058 if (stuffp->toc) {
1059 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1060 stuffp->toc);
1061 kfree(stuffp->toc);
1062 }
1063 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1064 stuffp);
1065 mcdx_stuffp[i] = NULL;
1066 kfree(stuffp);
1067 }
1068
1069 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1070 xwarn("cleanup() unregister_blkdev() failed\n");
1071 }
1072 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1073#if !MCDX_QUIET
1074 else
1075 xinfo("cleanup() succeeded\n");
1076#endif
1077}
1078
1079#ifdef MODULE
1080module_init(__mcdx_init);
1081#endif
1082module_exit(mcdx_exit);
1083
1084
1085
1086
1087int __init mcdx_init_drive(int drive)
1088{
1089 struct s_version version;
1090 struct s_drive_stuff *stuffp;
1091 int size = sizeof(*stuffp);
1092 char msg[80];
1093
1094 mcdx_blocksizes[drive] = 0;
1095
1096 xtrace(INIT, "init() try drive %d\n", drive);
1097
1098 xtrace(INIT, "kmalloc space for stuffpt's\n");
1099 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1100 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1101 xwarn("init() malloc failed\n");
1102 return 1;
1103 }
1104
1105 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1106 sizeof(*stuffp), stuffp);
1107
1108
1109 memset(stuffp, 0, sizeof(*stuffp));
1110
1111 stuffp->present = 0;
1112 stuffp->toc = NULL;
1113
1114
1115 stuffp->irq = irq(mcdx_drive_map[drive]);
1116 stuffp->wreg_data = stuffp->rreg_data =
1117 port(mcdx_drive_map[drive]);
1118 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1119 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1120 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1121
1122 init_waitqueue_head(&stuffp->busyq);
1123 init_waitqueue_head(&stuffp->lockq);
1124 init_waitqueue_head(&stuffp->sleepq);
1125
1126
1127 if (check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1128 xwarn("0x%3p,%d: Init failed. "
1129 "I/O ports (0x%3p..0x%3p) already in use.\n",
1130 stuffp->wreg_data, stuffp->irq,
1131 stuffp->wreg_data,
1132 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1133 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1134 kfree(stuffp);
1135 xtrace(INIT, "init() continue at next drive\n");
1136 return 0;
1137 }
1138
1139 xtrace(INIT, "init() i/o port is available at 0x%3p\n",
1140 stuffp->wreg_data);
1141 xtrace(INIT, "init() hardware reset\n");
1142 mcdx_reset(stuffp, HARD, 1);
1143
1144 xtrace(INIT, "init() get version\n");
1145 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1146
1147 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1148 MCDX, stuffp->wreg_data, stuffp->irq);
1149 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1150 kfree(stuffp);
1151 xtrace(INIT, "init() continue at next drive\n");
1152 return 0;
1153 }
1154
1155 switch (version.code) {
1156 case 'D':
1157 stuffp->readcmd = READ2X;
1158 stuffp->present = DOUBLE | DOOR | MULTI;
1159 break;
1160 case 'F':
1161 stuffp->readcmd = READ1X;
1162 stuffp->present = SINGLE | DOOR | MULTI;
1163 break;
1164 case 'M':
1165 stuffp->readcmd = READ1X;
1166 stuffp->present = SINGLE;
1167 break;
1168 default:
1169 stuffp->present = 0;
1170 break;
1171 }
1172
1173 stuffp->playcmd = READ1X;
1174
1175 if (!stuffp->present) {
1176 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1177 MCDX, stuffp->wreg_data, stuffp->irq);
1178 kfree(stuffp);
1179 return 0;
1180 }
1181
1182 xtrace(INIT, "init() register blkdev\n");
1183 if (devfs_register_blkdev(MAJOR_NR, "mcdx", &mcdx_bdops) != 0) {
1184 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1185 MCDX, stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1186 kfree(stuffp);
1187 return 1;
1188 }
1189
1190 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1191 read_ahead[MAJOR_NR] = READ_AHEAD;
1192 blksize_size[MAJOR_NR] = mcdx_blocksizes;
1193
1194 xtrace(INIT, "init() subscribe irq and i/o\n");
1195 mcdx_irq_map[stuffp->irq] = stuffp;
1196 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", NULL)) {
1197 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1198 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1199 stuffp->irq = 0;
1200 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1201 kfree(stuffp);
1202 return 0;
1203 }
1204 request_region((unsigned int) stuffp->wreg_data,
1205 MCDX_IO_SIZE, "mcdx");
1206
1207 xtrace(INIT, "init() get garbage\n");
1208 {
1209 int i;
1210 mcdx_delay(stuffp, HZ / 2);
1211 for (i = 100; i; i--)
1212 (void) inb((unsigned int) stuffp->rreg_status);
1213 }
1214
1215
1216#if WE_KNOW_WHY
1217
1218 outb(0x50, (unsigned int) stuffp->wreg_chn);
1219#endif
1220
1221 xtrace(INIT, "init() set non dma but irq mode\n");
1222 mcdx_config(stuffp, 1);
1223
1224 stuffp->minor = drive;
1225
1226 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1227 " (Firmware version %c %x)\n",
1228 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1229 mcdx_stuffp[drive] = stuffp;
1230 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1231 mcdx_info.dev = MKDEV(MAJOR_NR, 0);
1232 if (register_cdrom(&mcdx_info) != 0) {
1233 printk("Cannot register Mitsumi CD-ROM!\n");
1234 release_region((unsigned long) stuffp->wreg_data,
1235 MCDX_IO_SIZE);
1236 free_irq(stuffp->irq, NULL);
1237 kfree(stuffp);
1238 if (devfs_unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1239 xwarn("cleanup() unregister_blkdev() failed\n");
1240 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1241 return 2;
1242 }
1243 devfs_plain_cdrom(&mcdx_info, &mcdx_bdops);
1244 printk(msg);
1245 return 0;
1246}
1247
1248int __init mcdx_init(void)
1249{
1250 int drive;
1251#ifdef MODULE
1252 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1253#else
1254 xwarn("Version 2.14(hs) \n");
1255#endif
1256
1257 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1258
1259
1260 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1261 mcdx_stuffp[drive] = NULL;
1262
1263
1264 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1265 switch (mcdx_init_drive(drive)) {
1266 case 2:
1267 return -EIO;
1268 case 1:
1269 break;
1270 }
1271 }
1272 return 0;
1273}
1274
1275static int mcdx_transfer(struct s_drive_stuff *stuffp,
1276 char *p, int sector, int nr_sectors)
1277
1278
1279
1280
1281
1282{
1283 int ans;
1284
1285 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1286 return ans;
1287#if FALLBACK
1288 if (-1 == ans)
1289 stuffp->readerrs++;
1290 else
1291 return ans;
1292
1293 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1294 xwarn("XXX Already reading 1x -- no chance\n");
1295 return -1;
1296 }
1297
1298 xwarn("XXX Fallback to 1x\n");
1299
1300 stuffp->readcmd = READ1X;
1301 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1302#endif
1303
1304}
1305
1306
1307static int mcdx_xfer(struct s_drive_stuff *stuffp,
1308 char *p, int sector, int nr_sectors)
1309
1310
1311
1312{
1313 int border;
1314 int done = 0;
1315 long timeout;
1316
1317 if (stuffp->audio) {
1318 xwarn("Attempt to read from audio CD.\n");
1319 return -1;
1320 }
1321
1322 if (!stuffp->readcmd) {
1323 xinfo("Can't transfer from missing disk.\n");
1324 return -1;
1325 }
1326
1327 while (stuffp->lock) {
1328 interruptible_sleep_on(&stuffp->lockq);
1329 }
1330
1331 if (stuffp->valid && (sector >= stuffp->pending)
1332 && (sector < stuffp->low_border)) {
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 border = stuffp->high_border < (border =
1343 sector + nr_sectors)
1344 ? stuffp->high_border : border;
1345
1346 stuffp->lock = current->pid;
1347
1348 do {
1349
1350 while (stuffp->busy) {
1351
1352 timeout =
1353 interruptible_sleep_on_timeout
1354 (&stuffp->busyq, 5 * HZ);
1355
1356 if (!stuffp->introk) {
1357 xtrace(XFER,
1358 "error via interrupt\n");
1359 } else if (!timeout) {
1360 xtrace(XFER, "timeout\n");
1361 } else if (signal_pending(current)) {
1362 xtrace(XFER, "signal\n");
1363 } else
1364 continue;
1365
1366 stuffp->lock = 0;
1367 stuffp->busy = 0;
1368 stuffp->valid = 0;
1369
1370 wake_up_interruptible(&stuffp->lockq);
1371 xtrace(XFER, "transfer() done (-1)\n");
1372 return -1;
1373 }
1374
1375
1376
1377 stuffp->busy = (3 == (stuffp->pending & 3));
1378
1379
1380
1381 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1382 const int HEAD =
1383 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1384 CD_FRAMESIZE;
1385 insb((unsigned int) stuffp->rreg_data, p,
1386 HEAD);
1387 }
1388
1389
1390 insb((unsigned int) stuffp->rreg_data, p, 512);
1391
1392
1393
1394 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1395 char dummy[CD_XA_TAIL];
1396 insb((unsigned int) stuffp->rreg_data,
1397 &dummy[0], CD_XA_TAIL);
1398 }
1399
1400 if (stuffp->pending == sector) {
1401 p += 512;
1402 done++;
1403 sector++;
1404 }
1405 } while (++(stuffp->pending) < border);
1406
1407 stuffp->lock = 0;
1408 wake_up_interruptible(&stuffp->lockq);
1409
1410 } else {
1411
1412
1413
1414
1415
1416 static unsigned char cmd[] = {
1417 0,
1418 0, 0, 0,
1419 0, 0, 0
1420 };
1421
1422 cmd[0] = stuffp->readcmd;
1423
1424
1425 stuffp->valid = 1;
1426 stuffp->pending = sector & ~3;
1427
1428
1429 if (stuffp->pending > stuffp->lastsector) {
1430 xwarn
1431 ("transfer() sector %d from nirvana requested.\n",
1432 stuffp->pending);
1433 stuffp->status = MCDX_ST_EOM;
1434 stuffp->valid = 0;
1435 xtrace(XFER, "transfer() done (-1)\n");
1436 return -1;
1437 }
1438
1439 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1440 > stuffp->lastsector + 1) {
1441 xtrace(XFER, "cut low_border\n");
1442 stuffp->low_border = stuffp->lastsector + 1;
1443 }
1444 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1445 > stuffp->lastsector + 1) {
1446 xtrace(XFER, "cut high_border\n");
1447 stuffp->high_border = stuffp->lastsector + 1;
1448 }
1449
1450 {
1451 struct cdrom_msf0 pending;
1452 log2msf(stuffp->pending / 4, &pending);
1453 cmd[1] = pending.minute;
1454 cmd[2] = pending.second;
1455 cmd[3] = pending.frame;
1456 }
1457
1458 cmd[6] =
1459 (unsigned
1460 char) ((stuffp->high_border - stuffp->pending) / 4);
1461 xtrace(XFER, "[%2d]\n", cmd[6]);
1462
1463 stuffp->busy = 1;
1464
1465 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1466
1467 }
1468#ifdef AK2
1469 if (stuffp->int_err) {
1470 stuffp->valid = 0;
1471 stuffp->int_err = 0;
1472 return -1;
1473 }
1474#endif
1475
1476 stuffp->low_border = (stuffp->low_border +=
1477 done) <
1478 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1479
1480 return done;
1481}
1482
1483
1484
1485
1486static char *port(int *ip)
1487{
1488 return (char *) ip[0];
1489}
1490static int irq(int *ip)
1491{
1492 return ip[1];
1493}
1494
1495
1496
1497static unsigned int bcd2uint(unsigned char c)
1498{
1499 return (c >> 4) * 10 + (c & 0x0f);
1500}
1501
1502static unsigned int uint2bcd(unsigned int ival)
1503{
1504 return ((ival / 10) << 4) | (ival % 10);
1505}
1506
1507static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1508{
1509 l += CD_MSF_OFFSET;
1510 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1511 pmsf->second = uint2bcd(l / 75);
1512 pmsf->frame = uint2bcd(l % 75);
1513}
1514
1515static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1516{
1517 return bcd2uint(pmsf->frame)
1518 + bcd2uint(pmsf->second) * 75
1519 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1520}
1521
1522int mcdx_readtoc(struct s_drive_stuff *stuffp)
1523
1524
1525{
1526
1527 if (stuffp->toc) {
1528 xtrace(READTOC, "ioctl() toc already read\n");
1529 return 0;
1530 }
1531
1532 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1533 stuffp->di.n_last - stuffp->di.n_first + 1);
1534
1535 if (-1 == mcdx_hold(stuffp, 1))
1536 return -1;
1537
1538 xtrace(READTOC, "ioctl() tocmode\n");
1539 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1540 return -EIO;
1541
1542
1543 {
1544 int size;
1545 size =
1546 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1547 stuffp->di.n_first + 2);
1548
1549 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1550 stuffp->toc = kmalloc(size, GFP_KERNEL);
1551 if (!stuffp->toc) {
1552 xwarn("Cannot malloc %d bytes for toc\n", size);
1553 mcdx_setdrivemode(stuffp, DATA, 1);
1554 return -EIO;
1555 }
1556 }
1557
1558
1559 {
1560 int trk;
1561 int retries;
1562
1563 for (trk = 0;
1564 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1565 trk++)
1566 stuffp->toc[trk].index = 0;
1567
1568 for (retries = 300; retries; retries--) {
1569 struct s_subqcode q;
1570 unsigned int idx;
1571
1572 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1573 mcdx_setdrivemode(stuffp, DATA, 1);
1574 return -EIO;
1575 }
1576
1577 idx = bcd2uint(q.index);
1578
1579 if ((idx > 0)
1580 && (idx <= stuffp->di.n_last)
1581 && (q.tno == 0)
1582 && (stuffp->toc[idx - stuffp->di.n_first].
1583 index == 0)) {
1584 stuffp->toc[idx - stuffp->di.n_first] = q;
1585 xtrace(READTOC,
1586 "ioctl() toc idx %d (trk %d)\n",
1587 idx, trk);
1588 trk--;
1589 }
1590 if (trk == 0)
1591 break;
1592 }
1593 memset(&stuffp->
1594 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1595 sizeof(stuffp->toc[0]));
1596 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1597 1].dt = stuffp->di.msf_leadout;
1598 }
1599
1600
1601 xtrace(READTOC, "ioctl() undo toc mode\n");
1602 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1603 return -EIO;
1604
1605#if MCDX_DEBUG && READTOC
1606 {
1607 int trk;
1608 for (trk = 0;
1609 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1610 trk++)
1611 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1612 " %02x:%02x.%02x %02x:%02x.%02x\n",
1613 trk + stuffp->di.n_first,
1614 stuffp->toc[trk].control,
1615 stuffp->toc[trk].tno,
1616 stuffp->toc[trk].index,
1617 stuffp->toc[trk].tt.minute,
1618 stuffp->toc[trk].tt.second,
1619 stuffp->toc[trk].tt.frame,
1620 stuffp->toc[trk].dt.minute,
1621 stuffp->toc[trk].dt.second,
1622 stuffp->toc[trk].dt.frame);
1623 }
1624#endif
1625
1626 return 0;
1627}
1628
1629static int
1630mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1631{
1632 unsigned char cmd[7] = {
1633 0, 0, 0, 0, 0, 0, 0
1634 };
1635
1636 if (!stuffp->readcmd) {
1637 xinfo("Can't play from missing disk.\n");
1638 return -1;
1639 }
1640
1641 cmd[0] = stuffp->playcmd;
1642
1643 cmd[1] = msf->cdmsf_min0;
1644 cmd[2] = msf->cdmsf_sec0;
1645 cmd[3] = msf->cdmsf_frame0;
1646 cmd[4] = msf->cdmsf_min1;
1647 cmd[5] = msf->cdmsf_sec1;
1648 cmd[6] = msf->cdmsf_frame1;
1649
1650 xtrace(PLAYMSF, "ioctl(): play %x "
1651 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1652 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1653
1654 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1655
1656 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1657 xwarn("playmsf() timeout\n");
1658 return -1;
1659 }
1660
1661 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1662 return 0;
1663}
1664
1665static int
1666mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1667{
1668 struct s_subqcode *p;
1669 struct cdrom_msf msf;
1670
1671 if (-1 == mcdx_readtoc(stuffp))
1672 return -1;
1673
1674 if (ti)
1675 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1676 else
1677 p = &stuffp->start;
1678
1679 msf.cdmsf_min0 = p->dt.minute;
1680 msf.cdmsf_sec0 = p->dt.second;
1681 msf.cdmsf_frame0 = p->dt.frame;
1682
1683 if (ti) {
1684 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1685 stuffp->stop = *p;
1686 } else
1687 p = &stuffp->stop;
1688
1689 msf.cdmsf_min1 = p->dt.minute;
1690 msf.cdmsf_sec1 = p->dt.second;
1691 msf.cdmsf_frame1 = p->dt.frame;
1692
1693 return mcdx_playmsf(stuffp, &msf);
1694}
1695
1696
1697
1698
1699static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1700{
1701 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1702
1703 if (!stuffp->present)
1704 return -ENXIO;
1705 if (!(stuffp->present & DOOR))
1706 return -ENOSYS;
1707
1708 if (position)
1709 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1710 else
1711 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1712 return 1;
1713}
1714
1715static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1716{
1717 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1718}
1719
1720static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1721{
1722 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1723}
1724
1725static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1726 struct s_subqcode *sub, int tries)
1727{
1728 char buf[11];
1729 int ans;
1730
1731 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1732 2 * HZ, tries)))
1733 return -1;
1734 sub->control = buf[1];
1735 sub->tno = buf[2];
1736 sub->index = buf[3];
1737 sub->tt.minute = buf[4];
1738 sub->tt.second = buf[5];
1739 sub->tt.frame = buf[6];
1740 sub->dt.minute = buf[8];
1741 sub->dt.second = buf[9];
1742 sub->dt.frame = buf[10];
1743
1744 return ans;
1745}
1746
1747static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1748 struct s_multi *multi, int tries)
1749{
1750 char buf[5];
1751 int ans;
1752
1753 if (stuffp->present & MULTI) {
1754 ans =
1755 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1756 tries);
1757 multi->multi = buf[1];
1758 multi->msf_last.minute = buf[2];
1759 multi->msf_last.second = buf[3];
1760 multi->msf_last.frame = buf[4];
1761 return ans;
1762 } else {
1763 multi->multi = 0;
1764 return 0;
1765 }
1766}
1767
1768static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1769 int tries)
1770{
1771 char buf[9];
1772 int ans;
1773 ans =
1774 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1775 if (ans == -1) {
1776 info->n_first = 0;
1777 info->n_last = 0;
1778 } else {
1779 info->n_first = bcd2uint(buf[1]);
1780 info->n_last = bcd2uint(buf[2]);
1781 info->msf_leadout.minute = buf[3];
1782 info->msf_leadout.second = buf[4];
1783 info->msf_leadout.frame = buf[5];
1784 info->msf_first.minute = buf[6];
1785 info->msf_first.second = buf[7];
1786 info->msf_first.frame = buf[8];
1787 }
1788 return ans;
1789}
1790
1791static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1792 int tries)
1793{
1794 char cmd[2];
1795 int ans;
1796
1797 xtrace(HW, "setdrivemode() %d\n", mode);
1798
1799 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1800 return -1;
1801
1802 switch (mode) {
1803 case TOC:
1804 cmd[1] |= 0x04;
1805 break;
1806 case DATA:
1807 cmd[1] &= ~0x04;
1808 break;
1809 case RAW:
1810 cmd[1] |= 0x40;
1811 break;
1812 case COOKED:
1813 cmd[1] &= ~0x40;
1814 break;
1815 default:
1816 break;
1817 }
1818 cmd[0] = 0x50;
1819 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1820}
1821
1822static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1823 int tries)
1824{
1825 unsigned char cmd[2] = { 0xa0 };
1826 xtrace(HW, "setdatamode() %d\n", mode);
1827 switch (mode) {
1828 case MODE0:
1829 cmd[1] = 0x00;
1830 break;
1831 case MODE1:
1832 cmd[1] = 0x01;
1833 break;
1834 case MODE2:
1835 cmd[1] = 0x02;
1836 break;
1837 default:
1838 return -EINVAL;
1839 }
1840 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1841}
1842
1843static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1844{
1845 char cmd[4];
1846
1847 xtrace(HW, "config()\n");
1848
1849 cmd[0] = 0x90;
1850
1851 cmd[1] = 0x10;
1852 cmd[2] = 0x05;
1853
1854 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1855 return -1;
1856
1857 cmd[1] = 0x02;
1858 cmd[2] = 0x00;
1859
1860 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1861}
1862
1863static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1864 int tries)
1865{
1866 char buf[3];
1867 int ans;
1868
1869 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1870 1, buf, sizeof(buf), 2 * HZ, tries)))
1871 return ans;
1872
1873 ver->code = buf[1];
1874 ver->ver = buf[2];
1875
1876 return ans;
1877}
1878
1879static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1880{
1881 if (mode == HARD) {
1882 outb(0, (unsigned int) stuffp->wreg_chn);
1883 outb(0, (unsigned int) stuffp->wreg_reset);
1884 return 0;
1885 } else
1886 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1887}
1888
1889static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1890{
1891 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1892 char cmd[2] = { 0xfe };
1893
1894 if (!(stuffp->present & DOOR))
1895 return -ENOSYS;
1896 if (stuffp->present & DOOR) {
1897 cmd[1] = lock ? 0x01 : 0x00;
1898 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1899 } else
1900 return 0;
1901}
1902
1903static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1904{
1905 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1906}
1907
1908static int
1909mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1910{
1911 unsigned long timeout = to + jiffies;
1912 char c;
1913
1914 if (!buf)
1915 buf = &c;
1916
1917 while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1918 if (time_after(jiffies, timeout))
1919 return -1;
1920 mcdx_delay(stuffp, delay);
1921 }
1922
1923 *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1924
1925 return 0;
1926}
1927
1928static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1929 struct cdrom_volctrl *vol, int tries)
1930{
1931 char cmd[5];
1932 cmd[0] = 0xae;
1933 cmd[1] = vol->channel0;
1934 cmd[2] = 0;
1935 cmd[3] = vol->channel1;
1936 cmd[4] = 0;
1937
1938 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1939}
1940
1941MODULE_LICENSE("GPL");
1942