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