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