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