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