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