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