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