1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#include <linux/module.h>
71#include <linux/mm.h>
72#include <linux/ioport.h>
73#include <linux/init.h>
74#include <linux/devfs_fs_kernel.h>
75
76#include <asm/io.h>
77
78#define MAJOR_NR OPTICS_CDROM_MAJOR
79#include <linux/blk.h>
80
81#include <linux/cdrom.h>
82#include "optcd.h"
83
84#include <asm/uaccess.h>
85
86
87
88
89
90
91#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
92 DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
93#define DEBUG(x) debug x
94static void debug(int debug_this, const char* fmt, ...)
95{
96 char s[1024];
97 va_list args;
98
99 if (!debug_this)
100 return;
101
102 va_start(args, fmt);
103 vsprintf(s, fmt, args);
104 printk(KERN_DEBUG "optcd: %s\n", s);
105 va_end(args);
106}
107#else
108#define DEBUG(x)
109#endif
110
111static int blksize = 2048;
112static int hsecsize = 2048;
113
114
115
116
117
118
119#define optcd_port optcd
120static short optcd_port = OPTCD_PORTBASE;
121MODULE_PARM(optcd_port, "h");
122
123#define DATA_PORT optcd_port
124#define STATUS_PORT optcd_port+1
125
126
127#define COMIN_PORT optcd_port
128#define RESET_PORT optcd_port+1
129#define HCON_PORT optcd_port+2
130
131
132
133#define ST_DRVERR 0x80
134#define ST_DOOR_OPEN 0x40
135#define ST_MIXEDMODE_DISK 0x20
136#define ST_MODE_BITS 0x1c
137#define ST_M_STOP 0x00
138#define ST_M_READ 0x04
139#define ST_M_AUDIO 0x04
140#define ST_M_PAUSE 0x08
141#define ST_M_INITIAL 0x0c
142#define ST_M_ERROR 0x10
143#define ST_M_OTHERS 0x14
144#define ST_MODE2TRACK 0x02
145#define ST_DSK_CHG 0x01
146#define ST_L_LOCK 0x01
147#define ST_CMD_OK 0x00
148#define ST_OP_OK 0x01
149#define ST_PA_OK 0x02
150#define ST_OP_ERROR 0x05
151#define ST_PA_ERROR 0x06
152
153
154
155
156#define ERR_ILLCMD 0x11
157#define ERR_ILLPARM 0x12
158#define ERR_SLEDGE 0x13
159#define ERR_FOCUS 0x14
160#define ERR_MOTOR 0x15
161#define ERR_RADIAL 0x16
162#define ERR_PLL 0x17
163#define ERR_SUB_TIM 0x18
164#define ERR_SUB_NF 0x19
165#define ERR_TRAY 0x1a
166#define ERR_TOC 0x1b
167#define ERR_JUMP 0x1c
168
169#define ERR_MODE 0x21
170#define ERR_FORM 0x22
171#define ERR_HEADADDR 0x23
172#define ERR_CRC 0x24
173#define ERR_ECC 0x25
174#define ERR_CRC_UNC 0x26
175#define ERR_ILLBSYNC 0x27
176#define ERR_VDST 0x28
177
178#define ERR_READ_TIM 0x31
179#define ERR_DEC_STP 0x32
180#define ERR_DEC_TIM 0x33
181
182#define ERR_KEY 0x41
183#define ERR_READ_FINISH 0x42
184
185#define ERR_NOBSYNC 0x01
186#define ERR_SHORTB 0x02
187#define ERR_LONGB 0x03
188#define ERR_SHORTDSP 0x04
189#define ERR_LONGDSP 0x05
190
191
192
193#define FL_EJECT 0x20
194#define FL_WAIT 0x10
195#define FL_EOP 0x08
196#define FL_STEN 0x04
197#define FL_DTEN 0x02
198#define FL_DRQ 0x01
199#define FL_RESET 0xde
200#define FL_STDT (FL_STEN|FL_DTEN)
201
202
203
204#define HCON_DTS 0x08
205#define HCON_SDRQB 0x04
206#define HCON_LOHI 0x02
207#define HCON_DMA16 0x01
208
209
210
211
212#define COMDRVST 0x20
213#define COMERRST 0x21
214#define COMIOCTLISTAT 0x22
215#define COMINITSINGLE 0x28
216#define COMINITDOUBLE 0x29
217#define COMUNLOCK 0x30
218#define COMLOCK 0x31
219#define COMLOCKST 0x32
220#define COMVERSION 0x40
221#define COMVOIDREADMODE 0x50
222
223#define COMFETCH 0x60
224#define COMREAD 0x61
225#define COMREADRAW 0x62
226#define COMREADALL 0x63
227
228#define COMLEADIN 0x70
229#define COMSEEK 0x71
230#define COMPAUSEON 0x80
231#define COMPAUSEOFF 0x81
232#define COMSTOP 0x82
233#define COMOPEN 0x90
234#define COMCLOSE 0x91
235#define COMPLAY 0xa0
236#define COMPLAY_TNO 0xa2
237#define COMSUBQ 0xb0
238#define COMLOCATION 0xb1
239
240#define COMCHCTRL 0xc0
241
242#define COMDRVTEST 0xd0
243#define COMTEST 0xd1
244
245
246
247
248
249
250inline static int flag_low(int flag, unsigned long timeout)
251{
252 int flag_high;
253 unsigned long count = 0;
254
255 while ((flag_high = (inb(STATUS_PORT) & flag)))
256 if (++count >= timeout)
257 break;
258
259 DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
260 flag, count, flag_high ? " timeout" : ""));
261 return !flag_high;
262}
263
264
265
266static int sleep_timeout;
267static DECLARE_WAIT_QUEUE_HEAD(waitq);
268static void sleep_timer(unsigned long data);
269static struct timer_list delay_timer = {function: sleep_timer};
270
271
272
273
274static void sleep_timer(unsigned long data)
275{
276 int flags = inb(STATUS_PORT) & FL_STDT;
277
278 if (flags == FL_STDT && --sleep_timeout > 0) {
279 mod_timer(&delay_timer, jiffies + HZ/100);
280 } else
281 wake_up(&waitq);
282}
283
284
285
286static int sleep_flag_low(int flag, unsigned long timeout)
287{
288 int flag_high;
289
290 DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
291
292 sleep_timeout = timeout;
293 flag_high = inb(STATUS_PORT) & flag;
294 if (flag_high && sleep_timeout > 0) {
295 mod_timer(&delay_timer, jiffies + HZ/100);
296 sleep_on(&waitq);
297 flag_high = inb(STATUS_PORT) & flag;
298 }
299
300 DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
301 flag, timeout, flag_high ? " timeout" : ""));
302 return !flag_high;
303}
304
305
306
307
308
309
310#define ERR_IF_CMD_TIMEOUT 0x100
311#define ERR_IF_ERR_TIMEOUT 0x101
312#define ERR_IF_RESP_TIMEOUT 0x102
313#define ERR_IF_DATA_TIMEOUT 0x103
314#define ERR_IF_NOSTAT 0x104
315
316
317
318static int send_cmd(int cmd)
319{
320 unsigned char ack;
321
322 DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
323
324 outb(HCON_DTS, HCON_PORT);
325 outb(cmd, COMIN_PORT);
326 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
327 return -ERR_IF_CMD_TIMEOUT;
328 ack = inb(DATA_PORT);
329 outb(HCON_SDRQB, HCON_PORT);
330 return ack==ST_OP_OK ? 0 : -ack;
331}
332
333
334
335static int send_params(struct cdrom_msf *params)
336{
337 unsigned char ack;
338
339 DEBUG((DEBUG_DRIVE_IF, "sending parameters"
340 " %02x:%02x:%02x"
341 " %02x:%02x:%02x",
342 params->cdmsf_min0,
343 params->cdmsf_sec0,
344 params->cdmsf_frame0,
345 params->cdmsf_min1,
346 params->cdmsf_sec1,
347 params->cdmsf_frame1));
348
349 outb(params->cdmsf_min0, COMIN_PORT);
350 outb(params->cdmsf_sec0, COMIN_PORT);
351 outb(params->cdmsf_frame0, COMIN_PORT);
352 outb(params->cdmsf_min1, COMIN_PORT);
353 outb(params->cdmsf_sec1, COMIN_PORT);
354 outb(params->cdmsf_frame1, COMIN_PORT);
355 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
356 return -ERR_IF_CMD_TIMEOUT;
357 ack = inb(DATA_PORT);
358 return ack==ST_PA_OK ? 0 : -ack;
359}
360
361
362
363static int send_seek_params(struct cdrom_msf *params)
364{
365 unsigned char ack;
366
367 DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
368 " %02x:%02x:%02x",
369 params->cdmsf_min0,
370 params->cdmsf_sec0,
371 params->cdmsf_frame0));
372
373 outb(params->cdmsf_min0, COMIN_PORT);
374 outb(params->cdmsf_sec0, COMIN_PORT);
375 outb(params->cdmsf_frame0, COMIN_PORT);
376 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
377 return -ERR_IF_CMD_TIMEOUT;
378 ack = inb(DATA_PORT);
379 return ack==ST_PA_OK ? 0 : -ack;
380}
381
382
383
384
385inline static int get_exec_status(int busy_waiting)
386{
387 unsigned char exec_status;
388
389 if (busy_waiting
390 ? !flag_low(FL_STEN, BUSY_TIMEOUT)
391 : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
392 return -ERR_IF_CMD_TIMEOUT;
393
394 exec_status = inb(DATA_PORT);
395 DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
396 return exec_status;
397}
398
399
400
401
402inline static int get_data(int short_timeout)
403{
404 unsigned char data;
405
406 if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
407 return -ERR_IF_DATA_TIMEOUT;
408
409 data = inb(DATA_PORT);
410 DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
411 return data;
412}
413
414
415
416static int reset_drive(void)
417{
418 unsigned long count = 0;
419 int flags;
420
421 DEBUG((DEBUG_DRIVE_IF, "reset drive"));
422
423 outb(0, RESET_PORT);
424 while (++count < RESET_WAIT)
425 inb(DATA_PORT);
426
427 count = 0;
428 while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
429 if (++count >= BUSY_TIMEOUT)
430 break;
431
432 DEBUG((DEBUG_DRIVE_IF, "reset %s",
433 flags == FL_RESET ? "succeeded" : "failed"));
434
435 if (flags != FL_RESET)
436 return 0;
437 outb(HCON_SDRQB, HCON_PORT);
438 return 1;
439}
440
441
442
443
444
445inline static int stdt_flags(void)
446{
447 return inb(STATUS_PORT) & FL_STDT;
448}
449
450
451
452inline static int fetch_status(void)
453{
454 unsigned char status;
455
456 if (inb(STATUS_PORT) & FL_STEN)
457 return -ERR_IF_NOSTAT;
458
459 status = inb(DATA_PORT);
460 DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
461 return status;
462}
463
464
465
466inline static void fetch_data(char *buf, int n)
467{
468 insb(DATA_PORT, buf, n);
469 DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
470}
471
472
473
474inline static void flush_data(void)
475{
476 while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
477 inb(DATA_PORT);
478 DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
479}
480
481
482
483
484
485
486inline static int exec_cmd(int cmd)
487{
488 int ack = send_cmd(cmd);
489 if (ack < 0)
490 return ack;
491 return get_exec_status(cmd < COMFETCH);
492}
493
494
495
496
497inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
498{
499 int ack = send_cmd(cmd);
500 if (ack < 0)
501 return ack;
502 return send_params(params);
503}
504
505
506
507inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
508{
509 int ack = send_cmd(cmd);
510 if (ack < 0)
511 return ack;
512 ack = send_seek_params(params);
513 if (ack < 0)
514 return ack;
515 return 0;
516}
517
518
519
520inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
521{
522 int ack = exec_read_cmd(cmd, params);
523 if (ack < 0)
524 return ack;
525 return get_exec_status(0);
526}
527
528
529
530
531
532inline static void single_bin2bcd(u_char *p)
533{
534 DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
535 *p = (*p % 10) | ((*p / 10) << 4);
536}
537
538
539
540static void bin2bcd(struct cdrom_msf *msf)
541{
542 single_bin2bcd(&msf->cdmsf_min0);
543 single_bin2bcd(&msf->cdmsf_sec0);
544 single_bin2bcd(&msf->cdmsf_frame0);
545 single_bin2bcd(&msf->cdmsf_min1);
546 single_bin2bcd(&msf->cdmsf_sec1);
547 single_bin2bcd(&msf->cdmsf_frame1);
548}
549
550
551
552#define CD_FPM (CD_SECS * CD_FRAMES)
553
554static void lba2msf(int lba, struct cdrom_msf *msf)
555{
556 DEBUG((DEBUG_CONV, "lba2msf %d", lba));
557 lba += CD_MSF_OFFSET;
558 msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
559 msf->cdmsf_sec0 = lba / CD_FRAMES;
560 msf->cdmsf_frame0 = lba % CD_FRAMES;
561 msf->cdmsf_min1 = 0;
562 msf->cdmsf_sec1 = 0;
563 msf->cdmsf_frame1 = 0;
564 bin2bcd(msf);
565}
566
567
568
569inline static u_char bcd2bin(u_char bcd)
570{
571 DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
572 return (bcd >> 4) * 10 + (bcd & 0x0f);
573}
574
575
576static void msf2lba(union cdrom_addr *addr)
577{
578 addr->lba = addr->msf.minute * CD_FPM
579 + addr->msf.second * CD_FRAMES
580 + addr->msf.frame - CD_MSF_OFFSET;
581}
582
583
584
585
586static void msf_bcd2bin(union cdrom_addr *addr)
587{
588 addr->msf.minute = bcd2bin(addr->msf.minute);
589 addr->msf.second = bcd2bin(addr->msf.second);
590 addr->msf.frame = bcd2bin(addr->msf.frame);
591}
592
593
594
595
596static int audio_status = CDROM_AUDIO_NO_STATUS;
597static char toc_uptodate = 0;
598static char disk_changed = 1;
599
600
601static int drive_status(void)
602{
603 int status;
604
605 status = exec_cmd(COMIOCTLISTAT);
606 DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
607 if (status < 0)
608 return status;
609 if (status == 0xff)
610 return -ERR_IF_NOSTAT;
611
612 if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
613 (audio_status == CDROM_AUDIO_PLAY)) {
614 audio_status = CDROM_AUDIO_COMPLETED;
615 }
616
617 if (status & ST_DSK_CHG) {
618 toc_uptodate = 0;
619 disk_changed = 1;
620 audio_status = CDROM_AUDIO_NO_STATUS;
621 }
622
623 return status;
624}
625
626
627
628
629
630static int get_q_channel(struct cdrom_subchnl *qp)
631{
632 int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
633
634 status = drive_status();
635 if (status < 0)
636 return status;
637 qp->cdsc_audiostatus = audio_status;
638
639 status = exec_cmd(COMSUBQ);
640 if (status < 0)
641 return status;
642
643 d1 = get_data(0);
644 if (d1 < 0)
645 return d1;
646 qp->cdsc_adr = d1;
647 qp->cdsc_ctrl = d1 >> 4;
648
649 d2 = get_data(0);
650 if (d2 < 0)
651 return d2;
652 qp->cdsc_trk = bcd2bin(d2);
653
654 d3 = get_data(0);
655 if (d3 < 0)
656 return d3;
657 qp->cdsc_ind = bcd2bin(d3);
658
659 d4 = get_data(0);
660 if (d4 < 0)
661 return d4;
662 qp->cdsc_reladdr.msf.minute = d4;
663
664 d5 = get_data(0);
665 if (d5 < 0)
666 return d5;
667 qp->cdsc_reladdr.msf.second = d5;
668
669 d6 = get_data(0);
670 if (d6 < 0)
671 return d6;
672 qp->cdsc_reladdr.msf.frame = d6;
673
674 d7 = get_data(0);
675 if (d7 < 0)
676 return d7;
677
678
679 d8 = get_data(0);
680 if (d8 < 0)
681 return d8;
682 qp->cdsc_absaddr.msf.minute = d8;
683
684 d9 = get_data(0);
685 if (d9 < 0)
686 return d9;
687 qp->cdsc_absaddr.msf.second = d9;
688
689 d10 = get_data(0);
690 if (d10 < 0)
691 return d10;
692 qp->cdsc_absaddr.msf.frame = d10;
693
694 DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
695 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
696
697 msf_bcd2bin(&qp->cdsc_absaddr);
698 msf_bcd2bin(&qp->cdsc_reladdr);
699 if (qp->cdsc_format == CDROM_LBA) {
700 msf2lba(&qp->cdsc_absaddr);
701 msf2lba(&qp->cdsc_reladdr);
702 }
703
704 return 0;
705}
706
707
708
709
710
711#define ERR_TOC_MISSINGINFO 0x120
712#define ERR_TOC_MISSINGENTRY 0x121
713
714
715struct cdrom_disk_info {
716 unsigned char first;
717 unsigned char last;
718 struct cdrom_msf0 disk_length;
719 struct cdrom_msf0 first_track;
720
721 unsigned char next;
722 struct cdrom_msf0 next_session;
723 struct cdrom_msf0 last_session;
724 unsigned char multi;
725 unsigned char xa;
726 unsigned char audio;
727};
728static struct cdrom_disk_info disk_info;
729
730#define MAX_TRACKS 111
731static struct cdrom_subchnl toc[MAX_TRACKS];
732
733#define QINFO_FIRSTTRACK 100
734#define QINFO_LASTTRACK 101
735#define QINFO_DISKLENGTH 102
736#define QINFO_NEXTSESSION 110
737
738#define I_FIRSTTRACK 0x01
739#define I_LASTTRACK 0x02
740#define I_DISKLENGTH 0x04
741#define I_NEXTSESSION 0x08
742#define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
743
744
745#if DEBUG_TOC
746void toc_debug_info(int i)
747{
748 printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
749 " %2d:%02d.%02d %2d:%02d.%02d\n",
750 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
751 toc[i].cdsc_trk, toc[i].cdsc_ind,
752 toc[i].cdsc_reladdr.msf.minute,
753 toc[i].cdsc_reladdr.msf.second,
754 toc[i].cdsc_reladdr.msf.frame,
755 toc[i].cdsc_absaddr.msf.minute,
756 toc[i].cdsc_absaddr.msf.second,
757 toc[i].cdsc_absaddr.msf.frame);
758}
759#endif
760
761
762static int read_toc(void)
763{
764 int status, limit, count;
765 unsigned char got_info = 0;
766 struct cdrom_subchnl q_info;
767#if DEBUG_TOC
768 int i;
769#endif
770
771 DEBUG((DEBUG_TOC, "starting read_toc"));
772
773 count = 0;
774 for (limit = 60; limit > 0; limit--) {
775 int index;
776
777 q_info.cdsc_format = CDROM_MSF;
778 status = get_q_channel(&q_info);
779 if (status < 0)
780 return status;
781
782 index = q_info.cdsc_ind;
783 if (index > 0 && index < MAX_TRACKS
784 && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
785 toc[index] = q_info;
786 DEBUG((DEBUG_TOC, "got %d", index));
787 if (index < 100)
788 count++;
789
790 switch (q_info.cdsc_ind) {
791 case QINFO_FIRSTTRACK:
792 got_info |= I_FIRSTTRACK;
793 break;
794 case QINFO_LASTTRACK:
795 got_info |= I_LASTTRACK;
796 break;
797 case QINFO_DISKLENGTH:
798 got_info |= I_DISKLENGTH;
799 break;
800 case QINFO_NEXTSESSION:
801 got_info |= I_NEXTSESSION;
802 break;
803 }
804 }
805
806 if ((got_info & I_ALL) == I_ALL
807 && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
808 >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
809 break;
810 }
811
812
813 if (disk_info.first == 0) {
814 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
815 disk_info.first_track.minute =
816 toc[disk_info.first].cdsc_absaddr.msf.minute;
817 disk_info.first_track.second =
818 toc[disk_info.first].cdsc_absaddr.msf.second;
819 disk_info.first_track.frame =
820 toc[disk_info.first].cdsc_absaddr.msf.frame;
821 }
822 disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
823 disk_info.disk_length.minute =
824 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
825 disk_info.disk_length.second =
826 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
827 disk_info.disk_length.frame =
828 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
829 disk_info.next_session.minute =
830 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
831 disk_info.next_session.second =
832 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
833 disk_info.next_session.frame =
834 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
835 disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
836 disk_info.last_session.minute =
837 toc[disk_info.next].cdsc_absaddr.msf.minute;
838 disk_info.last_session.second =
839 toc[disk_info.next].cdsc_absaddr.msf.second;
840 disk_info.last_session.frame =
841 toc[disk_info.next].cdsc_absaddr.msf.frame;
842 toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
843 disk_info.disk_length.minute;
844 toc[disk_info.last + 1].cdsc_absaddr.msf.second =
845 disk_info.disk_length.second;
846 toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
847 disk_info.disk_length.frame;
848#if DEBUG_TOC
849 for (i = 1; i <= disk_info.last + 1; i++)
850 toc_debug_info(i);
851 toc_debug_info(QINFO_FIRSTTRACK);
852 toc_debug_info(QINFO_LASTTRACK);
853 toc_debug_info(QINFO_DISKLENGTH);
854 toc_debug_info(QINFO_NEXTSESSION);
855#endif
856
857 DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
858 got_info, count));
859 if ((got_info & I_ALL) != I_ALL
860 || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
861 < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
862 return -ERR_TOC_MISSINGINFO;
863 return 0;
864}
865
866
867#ifdef MULTISESSION
868static int get_multi_disk_info(void)
869{
870 int sessions, status;
871 struct cdrom_msf multi_index;
872
873
874 for (sessions = 2; sessions < 10 ; sessions++) {
875 int count;
876
877 for (count = 100; count < MAX_TRACKS; count++)
878 toc[count].cdsc_ind = 0;
879
880 multi_index.cdmsf_min0 = disk_info.next_session.minute;
881 multi_index.cdmsf_sec0 = disk_info.next_session.second;
882 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
883 if (multi_index.cdmsf_sec0 >= 20)
884 multi_index.cdmsf_sec0 -= 20;
885 else {
886 multi_index.cdmsf_sec0 += 40;
887 multi_index.cdmsf_min0--;
888 }
889 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
890 multi_index.cdmsf_min0,
891 multi_index.cdmsf_sec0,
892 multi_index.cdmsf_frame0));
893 bin2bcd(&multi_index);
894 multi_index.cdmsf_min1 = 0;
895 multi_index.cdmsf_sec1 = 0;
896 multi_index.cdmsf_frame1 = 1;
897
898 status = exec_read_cmd(COMREAD, &multi_index);
899 if (status < 0) {
900 DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
901 -status));
902 break;
903 }
904 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
905 0 : -ERR_TOC_MISSINGINFO;
906 flush_data();
907 if (status < 0) {
908 DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
909 break;
910 }
911
912 status = read_toc();
913 if (status < 0) {
914 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
915 break;
916 }
917
918 disk_info.multi = 1;
919 }
920
921 exec_cmd(COMSTOP);
922
923 if (status < 0)
924 return -EIO;
925 return 0;
926}
927#endif
928
929
930static int update_toc(void)
931{
932 int status, count;
933
934 if (toc_uptodate)
935 return 0;
936
937 DEBUG((DEBUG_TOC, "starting update_toc"));
938
939 disk_info.first = 0;
940 for (count = 0; count < MAX_TRACKS; count++)
941 toc[count].cdsc_ind = 0;
942
943 status = exec_cmd(COMLEADIN);
944 if (status < 0)
945 return -EIO;
946
947 status = read_toc();
948 if (status < 0) {
949 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
950 return -EIO;
951 }
952
953
954 disk_info.audio =
955 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
956
957
958 disk_info.xa = drive_status() & ST_MODE2TRACK;
959
960
961 disk_info.multi = 0;
962#ifdef MULTISESSION
963 if (disk_info.xa)
964 get_multi_disk_info();
965#endif
966 if (disk_info.multi)
967 printk(KERN_WARNING "optcd: Multisession support experimental, "
968 "see linux/Documentation/cdrom/optcd\n");
969
970 DEBUG((DEBUG_TOC, "exiting update_toc"));
971
972 toc_uptodate = 1;
973 return 0;
974}
975
976
977
978
979#define CURRENT_VALID \
980 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
981 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
982
983
984
985#define NOBUF -1
986
987static char buf[CD_FRAMESIZE * N_BUFS];
988static volatile int buf_bn[N_BUFS], next_bn;
989static volatile int buf_in = 0, buf_out = NOBUF;
990
991inline static void opt_invalidate_buffers(void)
992{
993 int i;
994
995 DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
996
997 for (i = 0; i < N_BUFS; i++)
998 buf_bn[i] = NOBUF;
999 buf_out = NOBUF;
1000}
1001
1002
1003
1004
1005static void transfer(void)
1006{
1007#if DEBUG_BUFFERS | DEBUG_REQUEST
1008 printk(KERN_DEBUG "optcd: executing transfer\n");
1009#endif
1010
1011 if (!CURRENT_VALID)
1012 return;
1013 while (CURRENT -> nr_sectors) {
1014 int bn = CURRENT -> sector / 4;
1015 int i, offs, nr_sectors;
1016 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1017
1018 DEBUG((DEBUG_REQUEST, "found %d", i));
1019
1020 if (i >= N_BUFS) {
1021 buf_out = NOBUF;
1022 break;
1023 }
1024
1025 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1026 nr_sectors = 4 - (CURRENT -> sector & 3);
1027
1028 if (buf_out != i) {
1029 buf_out = i;
1030 if (buf_bn[i] != bn) {
1031 buf_out = NOBUF;
1032 continue;
1033 }
1034 }
1035
1036 if (nr_sectors > CURRENT -> nr_sectors)
1037 nr_sectors = CURRENT -> nr_sectors;
1038 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1039 CURRENT -> nr_sectors -= nr_sectors;
1040 CURRENT -> sector += nr_sectors;
1041 CURRENT -> buffer += nr_sectors * 512;
1042 }
1043}
1044
1045
1046
1047
1048enum state_e {
1049 S_IDLE,
1050 S_START,
1051 S_READ,
1052 S_DATA,
1053 S_STOP,
1054 S_STOPPING
1055};
1056
1057static volatile enum state_e state = S_IDLE;
1058#if DEBUG_STATE
1059static volatile enum state_e state_old = S_STOP;
1060static volatile int flags_old = 0;
1061static volatile long state_n = 0;
1062#endif
1063
1064
1065
1066
1067
1068
1069static int in_vfs = 0;
1070
1071
1072static volatile int transfer_is_active = 0;
1073static volatile int error = 0;
1074static int tries;
1075static int timeout = 0;
1076
1077static void poll(unsigned long data);
1078static struct timer_list req_timer = {function: poll};
1079
1080
1081static void poll(unsigned long data)
1082{
1083 static volatile int read_count = 1;
1084 int flags;
1085 int loop_again = 1;
1086 int status = 0;
1087 int skip = 0;
1088
1089 if (error) {
1090 printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
1091 opt_invalidate_buffers();
1092 if (!tries--) {
1093 printk(KERN_ERR "optcd: read block %d failed;"
1094 " Giving up\n", next_bn);
1095 if (transfer_is_active)
1096 loop_again = 0;
1097 if (CURRENT_VALID)
1098 end_request(0);
1099 tries = 5;
1100 }
1101 error = 0;
1102 state = S_STOP;
1103 }
1104
1105 while (loop_again)
1106 {
1107 loop_again = 0;
1108
1109
1110#if DEBUG_STATE
1111 if (state == state_old)
1112 state_n++;
1113 else {
1114 state_old = state;
1115 if (++state_n > 1)
1116 printk(KERN_DEBUG "optcd: %ld times "
1117 "in previous state\n", state_n);
1118 printk(KERN_DEBUG "optcd: state %d\n", state);
1119 state_n = 0;
1120 }
1121#endif
1122
1123 switch (state) {
1124 case S_IDLE:
1125 return;
1126 case S_START:
1127 if (in_vfs)
1128 break;
1129 if (send_cmd(COMDRVST)) {
1130 state = S_IDLE;
1131 while (CURRENT_VALID)
1132 end_request(0);
1133 return;
1134 }
1135 state = S_READ;
1136 timeout = READ_TIMEOUT;
1137 break;
1138 case S_READ: {
1139 struct cdrom_msf msf;
1140 if (!skip) {
1141 status = fetch_status();
1142 if (status < 0)
1143 break;
1144 if (status & ST_DSK_CHG) {
1145 toc_uptodate = 0;
1146 opt_invalidate_buffers();
1147 }
1148 }
1149 skip = 0;
1150 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1151 toc_uptodate = 0;
1152 opt_invalidate_buffers();
1153 printk(KERN_WARNING "optcd: %s\n",
1154 (status & ST_DOOR_OPEN)
1155 ? "door open"
1156 : "disk removed");
1157 state = S_IDLE;
1158 while (CURRENT_VALID)
1159 end_request(0);
1160 return;
1161 }
1162 if (!CURRENT_VALID) {
1163 state = S_STOP;
1164 loop_again = 1;
1165 break;
1166 }
1167 next_bn = CURRENT -> sector / 4;
1168 lba2msf(next_bn, &msf);
1169 read_count = N_BUFS;
1170 msf.cdmsf_frame1 = read_count;
1171
1172 DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1173 msf.cdmsf_min0,
1174 msf.cdmsf_sec0,
1175 msf.cdmsf_frame0,
1176 msf.cdmsf_min1,
1177 msf.cdmsf_sec1,
1178 msf.cdmsf_frame1));
1179 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1180 " buf_out:%d buf_bn:%d",
1181 next_bn,
1182 buf_in,
1183 buf_out,
1184 buf_bn[buf_in]));
1185
1186 exec_read_cmd(COMREAD, &msf);
1187 state = S_DATA;
1188 timeout = READ_TIMEOUT;
1189 break;
1190 }
1191 case S_DATA:
1192 flags = stdt_flags() & (FL_STEN|FL_DTEN);
1193
1194#if DEBUG_STATE
1195 if (flags != flags_old) {
1196 flags_old = flags;
1197 printk(KERN_DEBUG "optcd: flags:%x\n", flags);
1198 }
1199 if (flags == FL_STEN)
1200 printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
1201#endif
1202
1203 switch (flags) {
1204 case FL_DTEN:
1205 if (!tries--) {
1206 printk(KERN_ERR
1207 "optcd: read block %d failed; "
1208 "Giving up\n", next_bn);
1209 if (transfer_is_active) {
1210 tries = 0;
1211 break;
1212 }
1213 if (CURRENT_VALID)
1214 end_request(0);
1215 tries = 5;
1216 }
1217 state = S_START;
1218 timeout = READ_TIMEOUT;
1219 loop_again = 1;
1220 case (FL_STEN|FL_DTEN):
1221 break;
1222 default:
1223 tries = 5;
1224 if (!CURRENT_VALID && buf_in == buf_out) {
1225 state = S_STOP;
1226 loop_again = 1;
1227 break;
1228 }
1229 if (read_count<=0)
1230 printk(KERN_WARNING
1231 "optcd: warning - try to read"
1232 " 0 frames\n");
1233 while (read_count) {
1234 buf_bn[buf_in] = NOBUF;
1235 if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1236
1237 printk(KERN_ERR
1238 "read_count:%d "
1239 "CURRENT->nr_sectors:%ld "
1240 "buf_in:%d\n",
1241 read_count,
1242 CURRENT->nr_sectors,
1243 buf_in);
1244 printk(KERN_ERR
1245 "transfer active: %x\n",
1246 transfer_is_active);
1247 read_count = 0;
1248 state = S_STOP;
1249 loop_again = 1;
1250 end_request(0);
1251 break;
1252 }
1253 fetch_data(buf+
1254 CD_FRAMESIZE*buf_in,
1255 CD_FRAMESIZE);
1256 read_count--;
1257
1258 DEBUG((DEBUG_REQUEST,
1259 "S_DATA; ---I've read data- "
1260 "read_count: %d",
1261 read_count));
1262 DEBUG((DEBUG_REQUEST,
1263 "next_bn:%d buf_in:%d "
1264 "buf_out:%d buf_bn:%d",
1265 next_bn,
1266 buf_in,
1267 buf_out,
1268 buf_bn[buf_in]));
1269
1270 buf_bn[buf_in] = next_bn++;
1271 if (buf_out == NOBUF)
1272 buf_out = buf_in;
1273 buf_in = buf_in + 1 ==
1274 N_BUFS ? 0 : buf_in + 1;
1275 }
1276 if (!transfer_is_active) {
1277 while (CURRENT_VALID) {
1278 transfer();
1279 if (CURRENT -> nr_sectors == 0)
1280 end_request(1);
1281 else
1282 break;
1283 }
1284 }
1285
1286 if (CURRENT_VALID
1287 && (CURRENT -> sector / 4 < next_bn ||
1288 CURRENT -> sector / 4 >
1289 next_bn + N_BUFS)) {
1290 state = S_STOP;
1291 loop_again = 1;
1292 break;
1293 }
1294 timeout = READ_TIMEOUT;
1295 if (read_count == 0) {
1296 state = S_STOP;
1297 loop_again = 1;
1298 break;
1299 }
1300 }
1301 break;
1302 case S_STOP:
1303 if (read_count != 0)
1304 printk(KERN_ERR
1305 "optcd: discard data=%x frames\n",
1306 read_count);
1307 flush_data();
1308 if (send_cmd(COMDRVST)) {
1309 state = S_IDLE;
1310 while (CURRENT_VALID)
1311 end_request(0);
1312 return;
1313 }
1314 state = S_STOPPING;
1315 timeout = STOP_TIMEOUT;
1316 break;
1317 case S_STOPPING:
1318 status = fetch_status();
1319 if (status < 0 && timeout)
1320 break;
1321 if ((status >= 0) && (status & ST_DSK_CHG)) {
1322 toc_uptodate = 0;
1323 opt_invalidate_buffers();
1324 }
1325 if (CURRENT_VALID) {
1326 if (status >= 0) {
1327 state = S_READ;
1328 loop_again = 1;
1329 skip = 1;
1330 break;
1331 } else {
1332 state = S_START;
1333 timeout = 1;
1334 }
1335 } else {
1336 state = S_IDLE;
1337 return;
1338 }
1339 break;
1340 default:
1341 printk(KERN_ERR "optcd: invalid state %d\n", state);
1342 return;
1343 }
1344 }
1345
1346 if (!timeout--) {
1347 printk(KERN_ERR "optcd: timeout in state %d\n", state);
1348 state = S_STOP;
1349 if (exec_cmd(COMSTOP) < 0) {
1350 state = S_IDLE;
1351 while (CURRENT_VALID)
1352 end_request(0);
1353 return;
1354 }
1355 }
1356
1357 mod_timer(&req_timer, jiffies + HZ/100);
1358}
1359
1360
1361static void do_optcd_request(request_queue_t * q)
1362{
1363 DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1364 CURRENT -> sector, CURRENT -> nr_sectors));
1365
1366 if (disk_info.audio) {
1367 printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");
1368 end_request(0);
1369 return;
1370 }
1371
1372 transfer_is_active = 1;
1373 while (CURRENT_VALID) {
1374 if (CURRENT->bh) {
1375 if (!buffer_locked(CURRENT->bh))
1376 panic(DEVICE_NAME ": block not locked");
1377 }
1378 transfer();
1379 if (CURRENT -> nr_sectors == 0) {
1380 end_request(1);
1381 } else {
1382 buf_out = NOBUF;
1383 if (state == S_IDLE) {
1384
1385 if (update_toc() < 0) {
1386 while (CURRENT_VALID)
1387 end_request(0);
1388 break;
1389 }
1390
1391 state = S_START;
1392 timeout = READ_TIMEOUT;
1393 tries = 5;
1394
1395 mod_timer(&req_timer, jiffies + HZ/100);
1396 }
1397 break;
1398 }
1399 }
1400 transfer_is_active = 0;
1401
1402 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d",
1403 next_bn, buf_in, buf_out, buf_bn[buf_in]));
1404 DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1405}
1406
1407
1408
1409
1410static char auto_eject = 0;
1411
1412static int cdrompause(void)
1413{
1414 int status;
1415
1416 if (audio_status != CDROM_AUDIO_PLAY)
1417 return -EINVAL;
1418
1419 status = exec_cmd(COMPAUSEON);
1420 if (status < 0) {
1421 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1422 return -EIO;
1423 }
1424 audio_status = CDROM_AUDIO_PAUSED;
1425 return 0;
1426}
1427
1428
1429static int cdromresume(void)
1430{
1431 int status;
1432
1433 if (audio_status != CDROM_AUDIO_PAUSED)
1434 return -EINVAL;
1435
1436 status = exec_cmd(COMPAUSEOFF);
1437 if (status < 0) {
1438 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1439 audio_status = CDROM_AUDIO_ERROR;
1440 return -EIO;
1441 }
1442 audio_status = CDROM_AUDIO_PLAY;
1443 return 0;
1444}
1445
1446
1447static int cdromplaymsf(unsigned long arg)
1448{
1449 int status;
1450 struct cdrom_msf msf;
1451
1452 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1453 if (status)
1454 return status;
1455 copy_from_user(&msf, (void *) arg, sizeof msf);
1456
1457 bin2bcd(&msf);
1458 status = exec_long_cmd(COMPLAY, &msf);
1459 if (status < 0) {
1460 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1461 audio_status = CDROM_AUDIO_ERROR;
1462 return -EIO;
1463 }
1464
1465 audio_status = CDROM_AUDIO_PLAY;
1466 return 0;
1467}
1468
1469
1470static int cdromplaytrkind(unsigned long arg)
1471{
1472 int status;
1473 struct cdrom_ti ti;
1474 struct cdrom_msf msf;
1475
1476 status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1477 if (status)
1478 return status;
1479 copy_from_user(&ti, (void *) arg, sizeof ti);
1480
1481 if (ti.cdti_trk0 < disk_info.first
1482 || ti.cdti_trk0 > disk_info.last
1483 || ti.cdti_trk1 < ti.cdti_trk0)
1484 return -EINVAL;
1485 if (ti.cdti_trk1 > disk_info.last)
1486 ti.cdti_trk1 = disk_info.last;
1487
1488 msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1489 msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1490 msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1491 msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1492 msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1493 msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1494
1495 DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1496 msf.cdmsf_min0,
1497 msf.cdmsf_sec0,
1498 msf.cdmsf_frame0,
1499 msf.cdmsf_min1,
1500 msf.cdmsf_sec1,
1501 msf.cdmsf_frame1));
1502
1503 bin2bcd(&msf);
1504 status = exec_long_cmd(COMPLAY, &msf);
1505 if (status < 0) {
1506 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1507 audio_status = CDROM_AUDIO_ERROR;
1508 return -EIO;
1509 }
1510
1511 audio_status = CDROM_AUDIO_PLAY;
1512 return 0;
1513}
1514
1515
1516static int cdromreadtochdr(unsigned long arg)
1517{
1518 int status;
1519 struct cdrom_tochdr tochdr;
1520
1521 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1522 if (status)
1523 return status;
1524
1525 tochdr.cdth_trk0 = disk_info.first;
1526 tochdr.cdth_trk1 = disk_info.last;
1527
1528 copy_to_user((void *) arg, &tochdr, sizeof tochdr);
1529 return 0;
1530}
1531
1532
1533static int cdromreadtocentry(unsigned long arg)
1534{
1535 int status;
1536 struct cdrom_tocentry entry;
1537 struct cdrom_subchnl *tocptr;
1538
1539 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1540 if (status)
1541 return status;
1542 copy_from_user(&entry, (void *) arg, sizeof entry);
1543
1544 if (entry.cdte_track == CDROM_LEADOUT)
1545 tocptr = &toc[disk_info.last + 1];
1546 else if (entry.cdte_track > disk_info.last
1547 || entry.cdte_track < disk_info.first)
1548 return -EINVAL;
1549 else
1550 tocptr = &toc[entry.cdte_track];
1551
1552 entry.cdte_adr = tocptr->cdsc_adr;
1553 entry.cdte_ctrl = tocptr->cdsc_ctrl;
1554 entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1555 entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1556 entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1557
1558
1559 if (entry.cdte_format == CDROM_LBA)
1560 msf2lba(&entry.cdte_addr);
1561 else if (entry.cdte_format != CDROM_MSF)
1562 return -EINVAL;
1563
1564 copy_to_user((void *) arg, &entry, sizeof entry);
1565 return 0;
1566}
1567
1568
1569static int cdromvolctrl(unsigned long arg)
1570{
1571 int status;
1572 struct cdrom_volctrl volctrl;
1573 struct cdrom_msf msf;
1574
1575 status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1576 if (status)
1577 return status;
1578 copy_from_user(&volctrl, (char *) arg, sizeof volctrl);
1579
1580 msf.cdmsf_min0 = 0x10;
1581 msf.cdmsf_sec0 = 0x32;
1582 msf.cdmsf_frame0 = volctrl.channel0;
1583 msf.cdmsf_min1 = volctrl.channel1;
1584 msf.cdmsf_sec1 = volctrl.channel2;
1585 msf.cdmsf_frame1 = volctrl.channel3;
1586
1587 status = exec_long_cmd(COMCHCTRL, &msf);
1588 if (status < 0) {
1589 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1590 return -EIO;
1591 }
1592 return 0;
1593}
1594
1595
1596static int cdromsubchnl(unsigned long arg)
1597{
1598 int status;
1599 struct cdrom_subchnl subchnl;
1600
1601 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1602 if (status)
1603 return status;
1604 copy_from_user(&subchnl, (void *) arg, sizeof subchnl);
1605
1606 if (subchnl.cdsc_format != CDROM_LBA
1607 && subchnl.cdsc_format != CDROM_MSF)
1608 return -EINVAL;
1609
1610 status = get_q_channel(&subchnl);
1611 if (status < 0) {
1612 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1613 return -EIO;
1614 }
1615
1616 copy_to_user((void *) arg, &subchnl, sizeof subchnl);
1617 return 0;
1618}
1619
1620
1621static int cdromread(unsigned long arg, int blocksize, int cmd)
1622{
1623 int status;
1624 struct cdrom_msf msf;
1625 char buf[CD_FRAMESIZE_RAWER];
1626
1627 status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1628 if (status)
1629 return status;
1630 copy_from_user(&msf, (void *) arg, sizeof msf);
1631
1632 bin2bcd(&msf);
1633 msf.cdmsf_min1 = 0;
1634 msf.cdmsf_sec1 = 0;
1635 msf.cdmsf_frame1 = 1;
1636 status = exec_read_cmd(cmd, &msf);
1637
1638 DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1639
1640 if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1641 return -EIO;
1642 fetch_data(buf, blocksize);
1643
1644 copy_to_user((void *) arg, &buf, blocksize);
1645 return 0;
1646}
1647
1648
1649static int cdromseek(unsigned long arg)
1650{
1651 int status;
1652 struct cdrom_msf msf;
1653
1654 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1655 if (status)
1656 return status;
1657 copy_from_user(&msf, (void *) arg, sizeof msf);
1658
1659 bin2bcd(&msf);
1660 status = exec_seek_cmd(COMSEEK, &msf);
1661
1662 DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1663
1664 if (status < 0)
1665 return -EIO;
1666 return 0;
1667}
1668
1669
1670#ifdef MULTISESSION
1671static int cdrommultisession(unsigned long arg)
1672{
1673 int status;
1674 struct cdrom_multisession ms;
1675
1676 status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1677 if (status)
1678 return status;
1679 copy_from_user(&ms, (void*) arg, sizeof ms);
1680
1681 ms.addr.msf.minute = disk_info.last_session.minute;
1682 ms.addr.msf.second = disk_info.last_session.second;
1683 ms.addr.msf.frame = disk_info.last_session.frame;
1684
1685 if (ms.addr_format != CDROM_LBA
1686 && ms.addr_format != CDROM_MSF)
1687 return -EINVAL;
1688 if (ms.addr_format == CDROM_LBA)
1689 msf2lba(&ms.addr);
1690
1691 ms.xa_flag = disk_info.xa;
1692
1693 copy_to_user((void*) arg, &ms,
1694 sizeof(struct cdrom_multisession));
1695
1696#if DEBUG_MULTIS
1697 if (ms.addr_format == CDROM_MSF)
1698 printk(KERN_DEBUG
1699 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1700 ms.xa_flag,
1701 ms.addr.msf.minute,
1702 ms.addr.msf.second,
1703 ms.addr.msf.frame);
1704 else
1705 printk(KERN_DEBUG
1706 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1707 ms.xa_flag,
1708 ms.addr.lba,
1709 disk_info.last_session.minute,
1710 disk_info.last_session.second,
1711 disk_info.last_session.frame);
1712#endif
1713
1714 return 0;
1715}
1716#endif
1717
1718
1719static int cdromreset(void)
1720{
1721 if (state != S_IDLE) {
1722 error = 1;
1723 tries = 0;
1724 }
1725
1726 toc_uptodate = 0;
1727 disk_changed = 1;
1728 opt_invalidate_buffers();
1729 audio_status = CDROM_AUDIO_NO_STATUS;
1730
1731 if (!reset_drive())
1732 return -EIO;
1733 return 0;
1734}
1735
1736
1737
1738
1739static int opt_ioctl(struct inode *ip, struct file *fp,
1740 unsigned int cmd, unsigned long arg)
1741{
1742 int status, err, retval = 0;
1743
1744 DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1745
1746 if (!ip)
1747 return -EINVAL;
1748
1749 if (cmd == CDROMRESET)
1750 return cdromreset();
1751
1752
1753 if (state != S_IDLE || in_vfs)
1754 return -EBUSY;
1755
1756 in_vfs = 1;
1757
1758 status = drive_status();
1759 if (status < 0) {
1760 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1761 in_vfs = 0;
1762 return -EIO;
1763 }
1764
1765 if (status & ST_DOOR_OPEN)
1766 switch (cmd) {
1767 case CDROMCLOSETRAY:
1768
1769 err = exec_cmd(COMCLOSE);
1770 if (err < 0) {
1771 DEBUG((DEBUG_VFS,
1772 "exec_cmd COMCLOSE: %02x", -err));
1773 in_vfs = 0;
1774 return -EIO;
1775 }
1776 break;
1777 default: in_vfs = 0;
1778 return -EBUSY;
1779 }
1780
1781 err = update_toc();
1782 if (err < 0) {
1783 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1784 in_vfs = 0;
1785 return -EIO;
1786 }
1787
1788 DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1789
1790 switch (cmd) {
1791 case CDROMPAUSE: retval = cdrompause(); break;
1792 case CDROMRESUME: retval = cdromresume(); break;
1793 case CDROMPLAYMSF: retval = cdromplaymsf(arg); break;
1794 case CDROMPLAYTRKIND: retval = cdromplaytrkind(arg); break;
1795 case CDROMREADTOCHDR: retval = cdromreadtochdr(arg); break;
1796 case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break;
1797
1798 case CDROMSTOP: err = exec_cmd(COMSTOP);
1799 if (err < 0) {
1800 DEBUG((DEBUG_VFS,
1801 "exec_cmd COMSTOP: %02x",
1802 -err));
1803 retval = -EIO;
1804 } else
1805 audio_status = CDROM_AUDIO_NO_STATUS;
1806 break;
1807 case CDROMSTART: break;
1808 case CDROMEJECT: err = exec_cmd(COMUNLOCK);
1809 if (err < 0) {
1810 DEBUG((DEBUG_VFS,
1811 "exec_cmd COMUNLOCK: %02x",
1812 -err));
1813 retval = -EIO;
1814 break;
1815 }
1816 err = exec_cmd(COMOPEN);
1817 if (err < 0) {
1818 DEBUG((DEBUG_VFS,
1819 "exec_cmd COMOPEN: %02x",
1820 -err));
1821 retval = -EIO;
1822 }
1823 break;
1824
1825 case CDROMVOLCTRL: retval = cdromvolctrl(arg); break;
1826 case CDROMSUBCHNL: retval = cdromsubchnl(arg); break;
1827
1828
1829
1830 case CDROMREADMODE2: retval = -EINVAL; break;
1831 case CDROMREADMODE1: retval = -EINVAL; break;
1832
1833
1834 case CDROMREADAUDIO: retval = -EINVAL; break;
1835
1836 case CDROMEJECT_SW: auto_eject = (char) arg;
1837 break;
1838
1839#ifdef MULTISESSION
1840 case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1841#endif
1842
1843 case CDROM_GET_MCN: retval = -EINVAL; break;
1844 case CDROMVOLREAD: retval = -EINVAL; break;
1845
1846 case CDROMREADRAW:
1847
1848 retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);
1849 break;
1850 case CDROMREADCOOKED:
1851 retval = cdromread(arg, CD_FRAMESIZE, COMREAD);
1852 break;
1853 case CDROMREADALL:
1854 retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);
1855 break;
1856
1857 case CDROMSEEK: retval = cdromseek(arg); break;
1858 case CDROMPLAYBLK: retval = -EINVAL; break;
1859 case CDROMCLOSETRAY: break;
1860 default: retval = -EINVAL;
1861 }
1862 in_vfs = 0;
1863 return retval;
1864}
1865
1866
1867static int open_count = 0;
1868
1869
1870static int opt_open(struct inode *ip, struct file *fp)
1871{
1872 DEBUG((DEBUG_VFS, "starting opt_open"));
1873
1874 if (!open_count && state == S_IDLE) {
1875 int status;
1876
1877 toc_uptodate = 0;
1878 opt_invalidate_buffers();
1879
1880 status = exec_cmd(COMCLOSE);
1881 if (status < 0) {
1882 DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1883 }
1884
1885 status = drive_status();
1886 if (status < 0) {
1887 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1888 goto err_out;
1889 }
1890 DEBUG((DEBUG_VFS, "status: %02x", status));
1891 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1892 printk(KERN_INFO "optcd: no disk or door open\n");
1893 goto err_out;
1894 }
1895 status = exec_cmd(COMLOCK);
1896 if (status < 0) {
1897 DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1898 }
1899 status = update_toc();
1900 if (status < 0) {
1901 DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1902 status = exec_cmd(COMUNLOCK);
1903 if (status < 0) {
1904 DEBUG((DEBUG_VFS,
1905 "exec_cmd COMUNLOCK: %02x", -status));
1906 }
1907 goto err_out;
1908 }
1909 open_count++;
1910 }
1911
1912 DEBUG((DEBUG_VFS, "exiting opt_open"));
1913
1914 return 0;
1915
1916err_out:
1917 return -EIO;
1918}
1919
1920
1921
1922static int opt_release(struct inode *ip, struct file *fp)
1923{
1924 int status;
1925
1926 DEBUG((DEBUG_VFS, "executing opt_release"));
1927 DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1928 ip, ip -> i_rdev, fp));
1929
1930 if (!--open_count) {
1931 toc_uptodate = 0;
1932 opt_invalidate_buffers();
1933 status = exec_cmd(COMUNLOCK);
1934 if (status < 0) {
1935 DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1936 }
1937 if (auto_eject) {
1938 status = exec_cmd(COMOPEN);
1939 DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1940 }
1941 del_timer(&delay_timer);
1942 del_timer(&req_timer);
1943 }
1944 return 0;
1945}
1946
1947
1948
1949static int opt_media_change(kdev_t dev)
1950{
1951 DEBUG((DEBUG_VFS, "executing opt_media_change"));
1952 DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1953
1954 if (disk_changed) {
1955 disk_changed = 0;
1956 return 1;
1957 }
1958 return 0;
1959}
1960
1961
1962
1963
1964
1965
1966static int __init version_ok(void)
1967{
1968 char devname[100];
1969 int count, i, ch, status;
1970
1971 status = exec_cmd(COMVERSION);
1972 if (status < 0) {
1973 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1974 return 0;
1975 }
1976 if ((count = get_data(1)) < 0) {
1977 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1978 return 0;
1979 }
1980 for (i = 0, ch = -1; count > 0; count--) {
1981 if ((ch = get_data(1)) < 0) {
1982 DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1983 break;
1984 }
1985 if (i < 99)
1986 devname[i++] = ch;
1987 }
1988 devname[i] = '\0';
1989 if (ch < 0)
1990 return 0;
1991
1992 printk(KERN_INFO "optcd: Device %s detected\n", devname);
1993 return ((devname[0] == 'D')
1994 && (devname[1] == 'O')
1995 && (devname[2] == 'L')
1996 && (devname[3] == 'P')
1997 && (devname[4] == 'H')
1998 && (devname[5] == 'I')
1999 && (devname[6] == 'N'));
2000}
2001
2002
2003static struct block_device_operations opt_fops = {
2004 owner: THIS_MODULE,
2005 open: opt_open,
2006 release: opt_release,
2007 ioctl: opt_ioctl,
2008 check_media_change: opt_media_change,
2009};
2010
2011#ifndef MODULE
2012
2013static int optcd_setup(char *str)
2014{
2015 int ints[4];
2016 (void)get_options(str, ARRAY_SIZE(ints), ints);
2017
2018 if (ints[0] > 0)
2019 optcd_port = ints[1];
2020
2021 return 1;
2022}
2023
2024__setup("optcd=", optcd_setup);
2025
2026#endif
2027
2028
2029
2030int __init optcd_init(void)
2031{
2032 int status;
2033
2034 if (optcd_port <= 0) {
2035 printk(KERN_INFO
2036 "optcd: no Optics Storage CDROM Initialization\n");
2037 return -EIO;
2038 }
2039 if (check_region(optcd_port, 4)) {
2040 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2041 optcd_port);
2042 return -EIO;
2043 }
2044
2045 if (!reset_drive()) {
2046 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2047 return -EIO;
2048 }
2049 if (!version_ok()) {
2050 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2051 return -EIO;
2052 }
2053 status = exec_cmd(COMINITDOUBLE);
2054 if (status < 0) {
2055 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2056 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2057 return -EIO;
2058 }
2059 if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2060 {
2061 printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2062 return -EIO;
2063 }
2064 devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
2065 S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
2066 hardsect_size[MAJOR_NR] = &hsecsize;
2067 blksize_size[MAJOR_NR] = &blksize;
2068 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
2069 read_ahead[MAJOR_NR] = 4;
2070 request_region(optcd_port, 4, "optcd");
2071 register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);
2072
2073 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2074 return 0;
2075}
2076
2077
2078void __exit optcd_exit(void)
2079{
2080 devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,
2081 DEVFS_SPECIAL_BLK, 0));
2082 if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2083 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2084 return;
2085 }
2086 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
2087 release_region(optcd_port, 4);
2088 printk(KERN_INFO "optcd: module released.\n");
2089}
2090
2091#ifdef MODULE
2092module_init(optcd_init);
2093#endif
2094module_exit(optcd_exit);
2095
2096
2097MODULE_LICENSE("GPL");
2098