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
75#include <asm/io.h>
76#include <linux/blkdev.h>
77
78#include <linux/cdrom.h>
79#include "optcd.h"
80
81#include <asm/uaccess.h>
82
83#define MAJOR_NR OPTICS_CDROM_MAJOR
84#define QUEUE (opt_queue)
85#define CURRENT elv_next_request(opt_queue)
86
87
88
89
90
91
92#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
93 DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
94#define DEBUG(x) debug x
95static void debug(int debug_this, const char* fmt, ...)
96{
97 char s[1024];
98 va_list args;
99
100 if (!debug_this)
101 return;
102
103 va_start(args, fmt);
104 vsprintf(s, fmt, args);
105 printk(KERN_DEBUG "optcd: %s\n", s);
106 va_end(args);
107}
108#else
109#define DEBUG(x)
110#endif
111
112
113
114
115
116
117#define optcd_port optcd
118static short optcd_port = OPTCD_PORTBASE;
119MODULE_PARM(optcd_port, "h");
120
121#define DATA_PORT optcd_port
122#define STATUS_PORT optcd_port+1
123
124
125#define COMIN_PORT optcd_port
126#define RESET_PORT optcd_port+1
127#define HCON_PORT optcd_port+2
128
129
130
131#define ST_DRVERR 0x80
132#define ST_DOOR_OPEN 0x40
133#define ST_MIXEDMODE_DISK 0x20
134#define ST_MODE_BITS 0x1c
135#define ST_M_STOP 0x00
136#define ST_M_READ 0x04
137#define ST_M_AUDIO 0x04
138#define ST_M_PAUSE 0x08
139#define ST_M_INITIAL 0x0c
140#define ST_M_ERROR 0x10
141#define ST_M_OTHERS 0x14
142#define ST_MODE2TRACK 0x02
143#define ST_DSK_CHG 0x01
144#define ST_L_LOCK 0x01
145#define ST_CMD_OK 0x00
146#define ST_OP_OK 0x01
147#define ST_PA_OK 0x02
148#define ST_OP_ERROR 0x05
149#define ST_PA_ERROR 0x06
150
151
152
153
154#define ERR_ILLCMD 0x11
155#define ERR_ILLPARM 0x12
156#define ERR_SLEDGE 0x13
157#define ERR_FOCUS 0x14
158#define ERR_MOTOR 0x15
159#define ERR_RADIAL 0x16
160#define ERR_PLL 0x17
161#define ERR_SUB_TIM 0x18
162#define ERR_SUB_NF 0x19
163#define ERR_TRAY 0x1a
164#define ERR_TOC 0x1b
165#define ERR_JUMP 0x1c
166
167#define ERR_MODE 0x21
168#define ERR_FORM 0x22
169#define ERR_HEADADDR 0x23
170#define ERR_CRC 0x24
171#define ERR_ECC 0x25
172#define ERR_CRC_UNC 0x26
173#define ERR_ILLBSYNC 0x27
174#define ERR_VDST 0x28
175
176#define ERR_READ_TIM 0x31
177#define ERR_DEC_STP 0x32
178#define ERR_DEC_TIM 0x33
179
180#define ERR_KEY 0x41
181#define ERR_READ_FINISH 0x42
182
183#define ERR_NOBSYNC 0x01
184#define ERR_SHORTB 0x02
185#define ERR_LONGB 0x03
186#define ERR_SHORTDSP 0x04
187#define ERR_LONGDSP 0x05
188
189
190
191#define FL_EJECT 0x20
192#define FL_WAIT 0x10
193#define FL_EOP 0x08
194#define FL_STEN 0x04
195#define FL_DTEN 0x02
196#define FL_DRQ 0x01
197#define FL_RESET 0xde
198#define FL_STDT (FL_STEN|FL_DTEN)
199
200
201
202#define HCON_DTS 0x08
203#define HCON_SDRQB 0x04
204#define HCON_LOHI 0x02
205#define HCON_DMA16 0x01
206
207
208
209
210#define COMDRVST 0x20
211#define COMERRST 0x21
212#define COMIOCTLISTAT 0x22
213#define COMINITSINGLE 0x28
214#define COMINITDOUBLE 0x29
215#define COMUNLOCK 0x30
216#define COMLOCK 0x31
217#define COMLOCKST 0x32
218#define COMVERSION 0x40
219#define COMVOIDREADMODE 0x50
220
221#define COMFETCH 0x60
222#define COMREAD 0x61
223#define COMREADRAW 0x62
224#define COMREADALL 0x63
225
226#define COMLEADIN 0x70
227#define COMSEEK 0x71
228#define COMPAUSEON 0x80
229#define COMPAUSEOFF 0x81
230#define COMSTOP 0x82
231#define COMOPEN 0x90
232#define COMCLOSE 0x91
233#define COMPLAY 0xa0
234#define COMPLAY_TNO 0xa2
235#define COMSUBQ 0xb0
236#define COMLOCATION 0xb1
237
238#define COMCHCTRL 0xc0
239
240#define COMDRVTEST 0xd0
241#define COMTEST 0xd1
242
243
244
245
246
247
248inline static int flag_low(int flag, unsigned long timeout)
249{
250 int flag_high;
251 unsigned long count = 0;
252
253 while ((flag_high = (inb(STATUS_PORT) & flag)))
254 if (++count >= timeout)
255 break;
256
257 DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
258 flag, count, flag_high ? " timeout" : ""));
259 return !flag_high;
260}
261
262
263
264static int sleep_timeout;
265static DECLARE_WAIT_QUEUE_HEAD(waitq);
266static void sleep_timer(unsigned long data);
267static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0);
268static spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED;
269static struct request_queue *opt_queue;
270
271
272
273static void sleep_timer(unsigned long data)
274{
275 int flags = inb(STATUS_PORT) & FL_STDT;
276
277 if (flags == FL_STDT && --sleep_timeout > 0) {
278 mod_timer(&delay_timer, jiffies + HZ/100);
279 } else
280 wake_up(&waitq);
281}
282
283
284
285static int sleep_flag_low(int flag, unsigned long timeout)
286{
287 int flag_high;
288
289 DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
290
291 sleep_timeout = timeout;
292 flag_high = inb(STATUS_PORT) & flag;
293 if (flag_high && sleep_timeout > 0) {
294 mod_timer(&delay_timer, jiffies + HZ/100);
295 sleep_on(&waitq);
296 flag_high = inb(STATUS_PORT) & flag;
297 }
298
299 DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
300 flag, timeout, flag_high ? " timeout" : ""));
301 return !flag_high;
302}
303
304
305
306
307
308
309#define ERR_IF_CMD_TIMEOUT 0x100
310#define ERR_IF_ERR_TIMEOUT 0x101
311#define ERR_IF_RESP_TIMEOUT 0x102
312#define ERR_IF_DATA_TIMEOUT 0x103
313#define ERR_IF_NOSTAT 0x104
314
315
316
317static int send_cmd(int cmd)
318{
319 unsigned char ack;
320
321 DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
322
323 outb(HCON_DTS, HCON_PORT);
324 outb(cmd, COMIN_PORT);
325 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
326 return -ERR_IF_CMD_TIMEOUT;
327 ack = inb(DATA_PORT);
328 outb(HCON_SDRQB, HCON_PORT);
329 return ack==ST_OP_OK ? 0 : -ack;
330}
331
332
333
334static int send_params(struct cdrom_msf *params)
335{
336 unsigned char ack;
337
338 DEBUG((DEBUG_DRIVE_IF, "sending parameters"
339 " %02x:%02x:%02x"
340 " %02x:%02x:%02x",
341 params->cdmsf_min0,
342 params->cdmsf_sec0,
343 params->cdmsf_frame0,
344 params->cdmsf_min1,
345 params->cdmsf_sec1,
346 params->cdmsf_frame1));
347
348 outb(params->cdmsf_min0, COMIN_PORT);
349 outb(params->cdmsf_sec0, COMIN_PORT);
350 outb(params->cdmsf_frame0, COMIN_PORT);
351 outb(params->cdmsf_min1, COMIN_PORT);
352 outb(params->cdmsf_sec1, COMIN_PORT);
353 outb(params->cdmsf_frame1, COMIN_PORT);
354 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
355 return -ERR_IF_CMD_TIMEOUT;
356 ack = inb(DATA_PORT);
357 return ack==ST_PA_OK ? 0 : -ack;
358}
359
360
361
362static int send_seek_params(struct cdrom_msf *params)
363{
364 unsigned char ack;
365
366 DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
367 " %02x:%02x:%02x",
368 params->cdmsf_min0,
369 params->cdmsf_sec0,
370 params->cdmsf_frame0));
371
372 outb(params->cdmsf_min0, COMIN_PORT);
373 outb(params->cdmsf_sec0, COMIN_PORT);
374 outb(params->cdmsf_frame0, COMIN_PORT);
375 if (!flag_low(FL_STEN, BUSY_TIMEOUT))
376 return -ERR_IF_CMD_TIMEOUT;
377 ack = inb(DATA_PORT);
378 return ack==ST_PA_OK ? 0 : -ack;
379}
380
381
382
383
384inline static int get_exec_status(int busy_waiting)
385{
386 unsigned char exec_status;
387
388 if (busy_waiting
389 ? !flag_low(FL_STEN, BUSY_TIMEOUT)
390 : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
391 return -ERR_IF_CMD_TIMEOUT;
392
393 exec_status = inb(DATA_PORT);
394 DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
395 return exec_status;
396}
397
398
399
400
401inline static int get_data(int short_timeout)
402{
403 unsigned char data;
404
405 if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
406 return -ERR_IF_DATA_TIMEOUT;
407
408 data = inb(DATA_PORT);
409 DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
410 return data;
411}
412
413
414
415static int reset_drive(void)
416{
417 unsigned long count = 0;
418 int flags;
419
420 DEBUG((DEBUG_DRIVE_IF, "reset drive"));
421
422 outb(0, RESET_PORT);
423 while (++count < RESET_WAIT)
424 inb(DATA_PORT);
425
426 count = 0;
427 while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
428 if (++count >= BUSY_TIMEOUT)
429 break;
430
431 DEBUG((DEBUG_DRIVE_IF, "reset %s",
432 flags == FL_RESET ? "succeeded" : "failed"));
433
434 if (flags != FL_RESET)
435 return 0;
436 outb(HCON_SDRQB, HCON_PORT);
437 return 1;
438}
439
440
441
442
443
444inline static int stdt_flags(void)
445{
446 return inb(STATUS_PORT) & FL_STDT;
447}
448
449
450
451inline static int fetch_status(void)
452{
453 unsigned char status;
454
455 if (inb(STATUS_PORT) & FL_STEN)
456 return -ERR_IF_NOSTAT;
457
458 status = inb(DATA_PORT);
459 DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
460 return status;
461}
462
463
464
465inline static void fetch_data(char *buf, int n)
466{
467 insb(DATA_PORT, buf, n);
468 DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
469}
470
471
472
473inline static void flush_data(void)
474{
475 while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
476 inb(DATA_PORT);
477 DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
478}
479
480
481
482
483
484
485inline static int exec_cmd(int cmd)
486{
487 int ack = send_cmd(cmd);
488 if (ack < 0)
489 return ack;
490 return get_exec_status(cmd < COMFETCH);
491}
492
493
494
495
496inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
497{
498 int ack = send_cmd(cmd);
499 if (ack < 0)
500 return ack;
501 return send_params(params);
502}
503
504
505
506inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
507{
508 int ack = send_cmd(cmd);
509 if (ack < 0)
510 return ack;
511 ack = send_seek_params(params);
512 if (ack < 0)
513 return ack;
514 return 0;
515}
516
517
518
519inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
520{
521 int ack = exec_read_cmd(cmd, params);
522 if (ack < 0)
523 return ack;
524 return get_exec_status(0);
525}
526
527
528
529
530
531inline static void single_bin2bcd(u_char *p)
532{
533 DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
534 *p = (*p % 10) | ((*p / 10) << 4);
535}
536
537
538
539static void bin2bcd(struct cdrom_msf *msf)
540{
541 single_bin2bcd(&msf->cdmsf_min0);
542 single_bin2bcd(&msf->cdmsf_sec0);
543 single_bin2bcd(&msf->cdmsf_frame0);
544 single_bin2bcd(&msf->cdmsf_min1);
545 single_bin2bcd(&msf->cdmsf_sec1);
546 single_bin2bcd(&msf->cdmsf_frame1);
547}
548
549
550
551#define CD_FPM (CD_SECS * CD_FRAMES)
552
553static void lba2msf(int lba, struct cdrom_msf *msf)
554{
555 DEBUG((DEBUG_CONV, "lba2msf %d", lba));
556 lba += CD_MSF_OFFSET;
557 msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
558 msf->cdmsf_sec0 = lba / CD_FRAMES;
559 msf->cdmsf_frame0 = lba % CD_FRAMES;
560 msf->cdmsf_min1 = 0;
561 msf->cdmsf_sec1 = 0;
562 msf->cdmsf_frame1 = 0;
563 bin2bcd(msf);
564}
565
566
567
568inline static u_char bcd2bin(u_char bcd)
569{
570 DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
571 return (bcd >> 4) * 10 + (bcd & 0x0f);
572}
573
574
575static void msf2lba(union cdrom_addr *addr)
576{
577 addr->lba = addr->msf.minute * CD_FPM
578 + addr->msf.second * CD_FRAMES
579 + addr->msf.frame - CD_MSF_OFFSET;
580}
581
582
583
584
585static void msf_bcd2bin(union cdrom_addr *addr)
586{
587 addr->msf.minute = bcd2bin(addr->msf.minute);
588 addr->msf.second = bcd2bin(addr->msf.second);
589 addr->msf.frame = bcd2bin(addr->msf.frame);
590}
591
592
593
594
595static int audio_status = CDROM_AUDIO_NO_STATUS;
596static char toc_uptodate = 0;
597static char disk_changed = 1;
598
599
600static int drive_status(void)
601{
602 int status;
603
604 status = exec_cmd(COMIOCTLISTAT);
605 DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
606 if (status < 0)
607 return status;
608 if (status == 0xff)
609 return -ERR_IF_NOSTAT;
610
611 if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
612 (audio_status == CDROM_AUDIO_PLAY)) {
613 audio_status = CDROM_AUDIO_COMPLETED;
614 }
615
616 if (status & ST_DSK_CHG) {
617 toc_uptodate = 0;
618 disk_changed = 1;
619 audio_status = CDROM_AUDIO_NO_STATUS;
620 }
621
622 return status;
623}
624
625
626
627
628
629static int get_q_channel(struct cdrom_subchnl *qp)
630{
631 int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
632
633 status = drive_status();
634 if (status < 0)
635 return status;
636 qp->cdsc_audiostatus = audio_status;
637
638 status = exec_cmd(COMSUBQ);
639 if (status < 0)
640 return status;
641
642 d1 = get_data(0);
643 if (d1 < 0)
644 return d1;
645 qp->cdsc_adr = d1;
646 qp->cdsc_ctrl = d1 >> 4;
647
648 d2 = get_data(0);
649 if (d2 < 0)
650 return d2;
651 qp->cdsc_trk = bcd2bin(d2);
652
653 d3 = get_data(0);
654 if (d3 < 0)
655 return d3;
656 qp->cdsc_ind = bcd2bin(d3);
657
658 d4 = get_data(0);
659 if (d4 < 0)
660 return d4;
661 qp->cdsc_reladdr.msf.minute = d4;
662
663 d5 = get_data(0);
664 if (d5 < 0)
665 return d5;
666 qp->cdsc_reladdr.msf.second = d5;
667
668 d6 = get_data(0);
669 if (d6 < 0)
670 return d6;
671 qp->cdsc_reladdr.msf.frame = d6;
672
673 d7 = get_data(0);
674 if (d7 < 0)
675 return d7;
676
677
678 d8 = get_data(0);
679 if (d8 < 0)
680 return d8;
681 qp->cdsc_absaddr.msf.minute = d8;
682
683 d9 = get_data(0);
684 if (d9 < 0)
685 return d9;
686 qp->cdsc_absaddr.msf.second = d9;
687
688 d10 = get_data(0);
689 if (d10 < 0)
690 return d10;
691 qp->cdsc_absaddr.msf.frame = d10;
692
693 DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
694 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
695
696 msf_bcd2bin(&qp->cdsc_absaddr);
697 msf_bcd2bin(&qp->cdsc_reladdr);
698 if (qp->cdsc_format == CDROM_LBA) {
699 msf2lba(&qp->cdsc_absaddr);
700 msf2lba(&qp->cdsc_reladdr);
701 }
702
703 return 0;
704}
705
706
707
708
709
710#define ERR_TOC_MISSINGINFO 0x120
711#define ERR_TOC_MISSINGENTRY 0x121
712
713
714struct cdrom_disk_info {
715 unsigned char first;
716 unsigned char last;
717 struct cdrom_msf0 disk_length;
718 struct cdrom_msf0 first_track;
719
720 unsigned char next;
721 struct cdrom_msf0 next_session;
722 struct cdrom_msf0 last_session;
723 unsigned char multi;
724 unsigned char xa;
725 unsigned char audio;
726};
727static struct cdrom_disk_info disk_info;
728
729#define MAX_TRACKS 111
730static struct cdrom_subchnl toc[MAX_TRACKS];
731
732#define QINFO_FIRSTTRACK 100
733#define QINFO_LASTTRACK 101
734#define QINFO_DISKLENGTH 102
735#define QINFO_NEXTSESSION 110
736
737#define I_FIRSTTRACK 0x01
738#define I_LASTTRACK 0x02
739#define I_DISKLENGTH 0x04
740#define I_NEXTSESSION 0x08
741#define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
742
743
744#if DEBUG_TOC
745static void toc_debug_info(int i)
746{
747 printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
748 " %2d:%02d.%02d %2d:%02d.%02d\n",
749 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
750 toc[i].cdsc_trk, toc[i].cdsc_ind,
751 toc[i].cdsc_reladdr.msf.minute,
752 toc[i].cdsc_reladdr.msf.second,
753 toc[i].cdsc_reladdr.msf.frame,
754 toc[i].cdsc_absaddr.msf.minute,
755 toc[i].cdsc_absaddr.msf.second,
756 toc[i].cdsc_absaddr.msf.frame);
757}
758#endif
759
760
761static int read_toc(void)
762{
763 int status, limit, count;
764 unsigned char got_info = 0;
765 struct cdrom_subchnl q_info;
766#if DEBUG_TOC
767 int i;
768#endif
769
770 DEBUG((DEBUG_TOC, "starting read_toc"));
771
772 count = 0;
773 for (limit = 60; limit > 0; limit--) {
774 int index;
775
776 q_info.cdsc_format = CDROM_MSF;
777 status = get_q_channel(&q_info);
778 if (status < 0)
779 return status;
780
781 index = q_info.cdsc_ind;
782 if (index > 0 && index < MAX_TRACKS
783 && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
784 toc[index] = q_info;
785 DEBUG((DEBUG_TOC, "got %d", index));
786 if (index < 100)
787 count++;
788
789 switch (q_info.cdsc_ind) {
790 case QINFO_FIRSTTRACK:
791 got_info |= I_FIRSTTRACK;
792 break;
793 case QINFO_LASTTRACK:
794 got_info |= I_LASTTRACK;
795 break;
796 case QINFO_DISKLENGTH:
797 got_info |= I_DISKLENGTH;
798 break;
799 case QINFO_NEXTSESSION:
800 got_info |= I_NEXTSESSION;
801 break;
802 }
803 }
804
805 if ((got_info & I_ALL) == I_ALL
806 && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
807 >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
808 break;
809 }
810
811
812 if (disk_info.first == 0) {
813 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
814 disk_info.first_track.minute =
815 toc[disk_info.first].cdsc_absaddr.msf.minute;
816 disk_info.first_track.second =
817 toc[disk_info.first].cdsc_absaddr.msf.second;
818 disk_info.first_track.frame =
819 toc[disk_info.first].cdsc_absaddr.msf.frame;
820 }
821 disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
822 disk_info.disk_length.minute =
823 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
824 disk_info.disk_length.second =
825 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
826 disk_info.disk_length.frame =
827 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
828 disk_info.next_session.minute =
829 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
830 disk_info.next_session.second =
831 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
832 disk_info.next_session.frame =
833 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
834 disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
835 disk_info.last_session.minute =
836 toc[disk_info.next].cdsc_absaddr.msf.minute;
837 disk_info.last_session.second =
838 toc[disk_info.next].cdsc_absaddr.msf.second;
839 disk_info.last_session.frame =
840 toc[disk_info.next].cdsc_absaddr.msf.frame;
841 toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
842 disk_info.disk_length.minute;
843 toc[disk_info.last + 1].cdsc_absaddr.msf.second =
844 disk_info.disk_length.second;
845 toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
846 disk_info.disk_length.frame;
847#if DEBUG_TOC
848 for (i = 1; i <= disk_info.last + 1; i++)
849 toc_debug_info(i);
850 toc_debug_info(QINFO_FIRSTTRACK);
851 toc_debug_info(QINFO_LASTTRACK);
852 toc_debug_info(QINFO_DISKLENGTH);
853 toc_debug_info(QINFO_NEXTSESSION);
854#endif
855
856 DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
857 got_info, count));
858 if ((got_info & I_ALL) != I_ALL
859 || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
860 < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
861 return -ERR_TOC_MISSINGINFO;
862 return 0;
863}
864
865
866#ifdef MULTISESSION
867static int get_multi_disk_info(void)
868{
869 int sessions, status;
870 struct cdrom_msf multi_index;
871
872
873 for (sessions = 2; sessions < 10 ; sessions++) {
874 int count;
875
876 for (count = 100; count < MAX_TRACKS; count++)
877 toc[count].cdsc_ind = 0;
878
879 multi_index.cdmsf_min0 = disk_info.next_session.minute;
880 multi_index.cdmsf_sec0 = disk_info.next_session.second;
881 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
882 if (multi_index.cdmsf_sec0 >= 20)
883 multi_index.cdmsf_sec0 -= 20;
884 else {
885 multi_index.cdmsf_sec0 += 40;
886 multi_index.cdmsf_min0--;
887 }
888 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
889 multi_index.cdmsf_min0,
890 multi_index.cdmsf_sec0,
891 multi_index.cdmsf_frame0));
892 bin2bcd(&multi_index);
893 multi_index.cdmsf_min1 = 0;
894 multi_index.cdmsf_sec1 = 0;
895 multi_index.cdmsf_frame1 = 1;
896
897 status = exec_read_cmd(COMREAD, &multi_index);
898 if (status < 0) {
899 DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
900 -status));
901 break;
902 }
903 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
904 0 : -ERR_TOC_MISSINGINFO;
905 flush_data();
906 if (status < 0) {
907 DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
908 break;
909 }
910
911 status = read_toc();
912 if (status < 0) {
913 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
914 break;
915 }
916
917 disk_info.multi = 1;
918 }
919
920 exec_cmd(COMSTOP);
921
922 if (status < 0)
923 return -EIO;
924 return 0;
925}
926#endif
927
928
929static int update_toc(void)
930{
931 int status, count;
932
933 if (toc_uptodate)
934 return 0;
935
936 DEBUG((DEBUG_TOC, "starting update_toc"));
937
938 disk_info.first = 0;
939 for (count = 0; count < MAX_TRACKS; count++)
940 toc[count].cdsc_ind = 0;
941
942 status = exec_cmd(COMLEADIN);
943 if (status < 0)
944 return -EIO;
945
946 status = read_toc();
947 if (status < 0) {
948 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
949 return -EIO;
950 }
951
952
953 disk_info.audio =
954 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
955
956
957 disk_info.xa = drive_status() & ST_MODE2TRACK;
958
959
960 disk_info.multi = 0;
961#ifdef MULTISESSION
962 if (disk_info.xa)
963 get_multi_disk_info();
964#endif
965 if (disk_info.multi)
966 printk(KERN_WARNING "optcd: Multisession support experimental, "
967 "see Documentation/cdrom/optcd\n");
968
969 DEBUG((DEBUG_TOC, "exiting update_toc"));
970
971 toc_uptodate = 1;
972 return 0;
973}
974
975
976
977static int current_valid(void)
978{
979 return CURRENT &&
980 CURRENT->cmd == READ &&
981 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 0);
1369 return;
1370 }
1371
1372 transfer_is_active = 1;
1373 while (current_valid()) {
1374 transfer();
1375 if (CURRENT -> nr_sectors == 0) {
1376 end_request(CURRENT, 1);
1377 } else {
1378 buf_out = NOBUF;
1379 if (state == S_IDLE) {
1380
1381 if (update_toc() < 0) {
1382 while (current_valid())
1383 end_request(CURRENT, 0);
1384 break;
1385 }
1386
1387 state = S_START;
1388 timeout = READ_TIMEOUT;
1389 tries = 5;
1390
1391 mod_timer(&req_timer, jiffies + HZ/100);
1392 }
1393 break;
1394 }
1395 }
1396 transfer_is_active = 0;
1397
1398 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d",
1399 next_bn, buf_in, buf_out, buf_bn[buf_in]));
1400 DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1401}
1402
1403
1404
1405
1406static char auto_eject = 0;
1407
1408static int cdrompause(void)
1409{
1410 int status;
1411
1412 if (audio_status != CDROM_AUDIO_PLAY)
1413 return -EINVAL;
1414
1415 status = exec_cmd(COMPAUSEON);
1416 if (status < 0) {
1417 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1418 return -EIO;
1419 }
1420 audio_status = CDROM_AUDIO_PAUSED;
1421 return 0;
1422}
1423
1424
1425static int cdromresume(void)
1426{
1427 int status;
1428
1429 if (audio_status != CDROM_AUDIO_PAUSED)
1430 return -EINVAL;
1431
1432 status = exec_cmd(COMPAUSEOFF);
1433 if (status < 0) {
1434 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1435 audio_status = CDROM_AUDIO_ERROR;
1436 return -EIO;
1437 }
1438 audio_status = CDROM_AUDIO_PLAY;
1439 return 0;
1440}
1441
1442
1443static int cdromplaymsf(void __user *arg)
1444{
1445 int status;
1446 struct cdrom_msf msf;
1447
1448 if (copy_from_user(&msf, arg, sizeof msf))
1449 return -EFAULT;
1450
1451 bin2bcd(&msf);
1452 status = exec_long_cmd(COMPLAY, &msf);
1453 if (status < 0) {
1454 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1455 audio_status = CDROM_AUDIO_ERROR;
1456 return -EIO;
1457 }
1458
1459 audio_status = CDROM_AUDIO_PLAY;
1460 return 0;
1461}
1462
1463
1464static int cdromplaytrkind(void __user *arg)
1465{
1466 int status;
1467 struct cdrom_ti ti;
1468 struct cdrom_msf msf;
1469
1470 if (copy_from_user(&ti, arg, sizeof ti))
1471 return -EFAULT;
1472
1473 if (ti.cdti_trk0 < disk_info.first
1474 || ti.cdti_trk0 > disk_info.last
1475 || ti.cdti_trk1 < ti.cdti_trk0)
1476 return -EINVAL;
1477 if (ti.cdti_trk1 > disk_info.last)
1478 ti.cdti_trk1 = disk_info.last;
1479
1480 msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1481 msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1482 msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1483 msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1484 msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1485 msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1486
1487 DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1488 msf.cdmsf_min0,
1489 msf.cdmsf_sec0,
1490 msf.cdmsf_frame0,
1491 msf.cdmsf_min1,
1492 msf.cdmsf_sec1,
1493 msf.cdmsf_frame1));
1494
1495 bin2bcd(&msf);
1496 status = exec_long_cmd(COMPLAY, &msf);
1497 if (status < 0) {
1498 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1499 audio_status = CDROM_AUDIO_ERROR;
1500 return -EIO;
1501 }
1502
1503 audio_status = CDROM_AUDIO_PLAY;
1504 return 0;
1505}
1506
1507
1508static int cdromreadtochdr(void __user *arg)
1509{
1510 struct cdrom_tochdr tochdr;
1511
1512 tochdr.cdth_trk0 = disk_info.first;
1513 tochdr.cdth_trk1 = disk_info.last;
1514
1515 return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0;
1516}
1517
1518
1519static int cdromreadtocentry(void __user *arg)
1520{
1521 struct cdrom_tocentry entry;
1522 struct cdrom_subchnl *tocptr;
1523
1524 if (copy_from_user(&entry, arg, sizeof entry))
1525 return -EFAULT;
1526
1527 if (entry.cdte_track == CDROM_LEADOUT)
1528 tocptr = &toc[disk_info.last + 1];
1529 else if (entry.cdte_track > disk_info.last
1530 || entry.cdte_track < disk_info.first)
1531 return -EINVAL;
1532 else
1533 tocptr = &toc[entry.cdte_track];
1534
1535 entry.cdte_adr = tocptr->cdsc_adr;
1536 entry.cdte_ctrl = tocptr->cdsc_ctrl;
1537 entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1538 entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1539 entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1540
1541
1542 if (entry.cdte_format == CDROM_LBA)
1543 msf2lba(&entry.cdte_addr);
1544 else if (entry.cdte_format != CDROM_MSF)
1545 return -EINVAL;
1546
1547 return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0;
1548}
1549
1550
1551static int cdromvolctrl(void __user *arg)
1552{
1553 int status;
1554 struct cdrom_volctrl volctrl;
1555 struct cdrom_msf msf;
1556
1557 if (copy_from_user(&volctrl, arg, sizeof volctrl))
1558 return -EFAULT;
1559
1560 msf.cdmsf_min0 = 0x10;
1561 msf.cdmsf_sec0 = 0x32;
1562 msf.cdmsf_frame0 = volctrl.channel0;
1563 msf.cdmsf_min1 = volctrl.channel1;
1564 msf.cdmsf_sec1 = volctrl.channel2;
1565 msf.cdmsf_frame1 = volctrl.channel3;
1566
1567 status = exec_long_cmd(COMCHCTRL, &msf);
1568 if (status < 0) {
1569 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1570 return -EIO;
1571 }
1572 return 0;
1573}
1574
1575
1576static int cdromsubchnl(void __user *arg)
1577{
1578 int status;
1579 struct cdrom_subchnl subchnl;
1580
1581 if (copy_from_user(&subchnl, arg, sizeof subchnl))
1582 return -EFAULT;
1583
1584 if (subchnl.cdsc_format != CDROM_LBA
1585 && subchnl.cdsc_format != CDROM_MSF)
1586 return -EINVAL;
1587
1588 status = get_q_channel(&subchnl);
1589 if (status < 0) {
1590 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1591 return -EIO;
1592 }
1593
1594 if (copy_to_user(arg, &subchnl, sizeof subchnl))
1595 return -EFAULT;
1596 return 0;
1597}
1598
1599
1600static struct gendisk *optcd_disk;
1601
1602
1603static int cdromread(void __user *arg, int blocksize, int cmd)
1604{
1605 int status;
1606 struct cdrom_msf msf;
1607
1608 if (copy_from_user(&msf, arg, sizeof msf))
1609 return -EFAULT;
1610
1611 bin2bcd(&msf);
1612 msf.cdmsf_min1 = 0;
1613 msf.cdmsf_sec1 = 0;
1614 msf.cdmsf_frame1 = 1;
1615 status = exec_read_cmd(cmd, &msf);
1616
1617 DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1618
1619 if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1620 return -EIO;
1621
1622 fetch_data(optcd_disk->private_data, blocksize);
1623
1624 if (copy_to_user(arg, optcd_disk->private_data, blocksize))
1625 return -EFAULT;
1626
1627 return 0;
1628}
1629
1630
1631static int cdromseek(void __user *arg)
1632{
1633 int status;
1634 struct cdrom_msf msf;
1635
1636 if (copy_from_user(&msf, arg, sizeof msf))
1637 return -EFAULT;
1638
1639 bin2bcd(&msf);
1640 status = exec_seek_cmd(COMSEEK, &msf);
1641
1642 DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1643
1644 if (status < 0)
1645 return -EIO;
1646 return 0;
1647}
1648
1649
1650#ifdef MULTISESSION
1651static int cdrommultisession(void __user *arg)
1652{
1653 struct cdrom_multisession ms;
1654
1655 if (copy_from_user(&ms, arg, sizeof ms))
1656 return -EFAULT;
1657
1658 ms.addr.msf.minute = disk_info.last_session.minute;
1659 ms.addr.msf.second = disk_info.last_session.second;
1660 ms.addr.msf.frame = disk_info.last_session.frame;
1661
1662 if (ms.addr_format != CDROM_LBA
1663 && ms.addr_format != CDROM_MSF)
1664 return -EINVAL;
1665 if (ms.addr_format == CDROM_LBA)
1666 msf2lba(&ms.addr);
1667
1668 ms.xa_flag = disk_info.xa;
1669
1670 if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession)))
1671 return -EFAULT;
1672
1673#if DEBUG_MULTIS
1674 if (ms.addr_format == CDROM_MSF)
1675 printk(KERN_DEBUG
1676 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1677 ms.xa_flag,
1678 ms.addr.msf.minute,
1679 ms.addr.msf.second,
1680 ms.addr.msf.frame);
1681 else
1682 printk(KERN_DEBUG
1683 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1684 ms.xa_flag,
1685 ms.addr.lba,
1686 disk_info.last_session.minute,
1687 disk_info.last_session.second,
1688 disk_info.last_session.frame);
1689#endif
1690
1691 return 0;
1692}
1693#endif
1694
1695
1696static int cdromreset(void)
1697{
1698 if (state != S_IDLE) {
1699 error = 1;
1700 tries = 0;
1701 }
1702
1703 toc_uptodate = 0;
1704 disk_changed = 1;
1705 opt_invalidate_buffers();
1706 audio_status = CDROM_AUDIO_NO_STATUS;
1707
1708 if (!reset_drive())
1709 return -EIO;
1710 return 0;
1711}
1712
1713
1714
1715
1716static int opt_ioctl(struct inode *ip, struct file *fp,
1717 unsigned int cmd, unsigned long arg)
1718{
1719 int status, err, retval = 0;
1720 void __user *argp = (void __user *)arg;
1721
1722 DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1723
1724 if (!ip)
1725 return -EINVAL;
1726
1727 if (cmd == CDROMRESET)
1728 return cdromreset();
1729
1730
1731 if (state != S_IDLE || in_vfs)
1732 return -EBUSY;
1733
1734 in_vfs = 1;
1735
1736 status = drive_status();
1737 if (status < 0) {
1738 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1739 in_vfs = 0;
1740 return -EIO;
1741 }
1742
1743 if (status & ST_DOOR_OPEN)
1744 switch (cmd) {
1745 case CDROMCLOSETRAY:
1746
1747 err = exec_cmd(COMCLOSE);
1748 if (err < 0) {
1749 DEBUG((DEBUG_VFS,
1750 "exec_cmd COMCLOSE: %02x", -err));
1751 in_vfs = 0;
1752 return -EIO;
1753 }
1754 break;
1755 default: in_vfs = 0;
1756 return -EBUSY;
1757 }
1758
1759 err = update_toc();
1760 if (err < 0) {
1761 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1762 in_vfs = 0;
1763 return -EIO;
1764 }
1765
1766 DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1767
1768 switch (cmd) {
1769 case CDROMPAUSE: retval = cdrompause(); break;
1770 case CDROMRESUME: retval = cdromresume(); break;
1771 case CDROMPLAYMSF: retval = cdromplaymsf(argp); break;
1772 case CDROMPLAYTRKIND: retval = cdromplaytrkind(argp); break;
1773 case CDROMREADTOCHDR: retval = cdromreadtochdr(argp); break;
1774 case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break;
1775
1776 case CDROMSTOP: err = exec_cmd(COMSTOP);
1777 if (err < 0) {
1778 DEBUG((DEBUG_VFS,
1779 "exec_cmd COMSTOP: %02x",
1780 -err));
1781 retval = -EIO;
1782 } else
1783 audio_status = CDROM_AUDIO_NO_STATUS;
1784 break;
1785 case CDROMSTART: break;
1786 case CDROMEJECT: err = exec_cmd(COMUNLOCK);
1787 if (err < 0) {
1788 DEBUG((DEBUG_VFS,
1789 "exec_cmd COMUNLOCK: %02x",
1790 -err));
1791 retval = -EIO;
1792 break;
1793 }
1794 err = exec_cmd(COMOPEN);
1795 if (err < 0) {
1796 DEBUG((DEBUG_VFS,
1797 "exec_cmd COMOPEN: %02x",
1798 -err));
1799 retval = -EIO;
1800 }
1801 break;
1802
1803 case CDROMVOLCTRL: retval = cdromvolctrl(argp); break;
1804 case CDROMSUBCHNL: retval = cdromsubchnl(argp); break;
1805
1806
1807
1808 case CDROMREADMODE2: retval = -EINVAL; break;
1809 case CDROMREADMODE1: retval = -EINVAL; break;
1810
1811
1812 case CDROMREADAUDIO: retval = -EINVAL; break;
1813
1814 case CDROMEJECT_SW: auto_eject = (char) arg;
1815 break;
1816
1817#ifdef MULTISESSION
1818 case CDROMMULTISESSION: retval = cdrommultisession(argp); break;
1819#endif
1820
1821 case CDROM_GET_MCN: retval = -EINVAL; break;
1822 case CDROMVOLREAD: retval = -EINVAL; break;
1823
1824 case CDROMREADRAW:
1825
1826 retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW);
1827 break;
1828 case CDROMREADCOOKED:
1829 retval = cdromread(argp, CD_FRAMESIZE, COMREAD);
1830 break;
1831 case CDROMREADALL:
1832 retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL);
1833 break;
1834
1835 case CDROMSEEK: retval = cdromseek(argp); break;
1836 case CDROMPLAYBLK: retval = -EINVAL; break;
1837 case CDROMCLOSETRAY: break;
1838 default: retval = -EINVAL;
1839 }
1840 in_vfs = 0;
1841 return retval;
1842}
1843
1844
1845static int open_count = 0;
1846
1847
1848static int opt_open(struct inode *ip, struct file *fp)
1849{
1850 DEBUG((DEBUG_VFS, "starting opt_open"));
1851
1852 if (!open_count && state == S_IDLE) {
1853 int status;
1854 char *buf;
1855
1856 buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL);
1857 if (!buf) {
1858 printk(KERN_INFO "optcd: cannot allocate read buffer\n");
1859 return -ENOMEM;
1860 }
1861 optcd_disk->private_data = buf;
1862
1863 toc_uptodate = 0;
1864 opt_invalidate_buffers();
1865
1866 status = exec_cmd(COMCLOSE);
1867 if (status < 0) {
1868 DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1869 }
1870
1871 status = drive_status();
1872 if (status < 0) {
1873 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1874 goto err_out;
1875 }
1876 DEBUG((DEBUG_VFS, "status: %02x", status));
1877 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1878 printk(KERN_INFO "optcd: no disk or door open\n");
1879 goto err_out;
1880 }
1881 status = exec_cmd(COMLOCK);
1882 if (status < 0) {
1883 DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1884 }
1885 status = update_toc();
1886 if (status < 0) {
1887 DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1888 status = exec_cmd(COMUNLOCK);
1889 if (status < 0) {
1890 DEBUG((DEBUG_VFS,
1891 "exec_cmd COMUNLOCK: %02x", -status));
1892 }
1893 goto err_out;
1894 }
1895 open_count++;
1896 }
1897
1898 DEBUG((DEBUG_VFS, "exiting opt_open"));
1899
1900 return 0;
1901
1902err_out:
1903 return -EIO;
1904}
1905
1906
1907
1908static int opt_release(struct inode *ip, struct file *fp)
1909{
1910 int status;
1911
1912 DEBUG((DEBUG_VFS, "executing opt_release"));
1913 DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n",
1914 ip, ip->i_bdev->bd_disk->disk_name, fp));
1915
1916 if (!--open_count) {
1917 toc_uptodate = 0;
1918 opt_invalidate_buffers();
1919 status = exec_cmd(COMUNLOCK);
1920 if (status < 0) {
1921 DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1922 }
1923 if (auto_eject) {
1924 status = exec_cmd(COMOPEN);
1925 DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1926 }
1927 kfree(optcd_disk->private_data);
1928 del_timer(&delay_timer);
1929 del_timer(&req_timer);
1930 }
1931 return 0;
1932}
1933
1934
1935
1936static int opt_media_change(struct gendisk *disk)
1937{
1938 DEBUG((DEBUG_VFS, "executing opt_media_change"));
1939 DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n",
1940 disk->disk_name, disk_changed));
1941
1942 if (disk_changed) {
1943 disk_changed = 0;
1944 return 1;
1945 }
1946 return 0;
1947}
1948
1949
1950
1951
1952
1953
1954static int __init version_ok(void)
1955{
1956 char devname[100];
1957 int count, i, ch, status;
1958
1959 status = exec_cmd(COMVERSION);
1960 if (status < 0) {
1961 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1962 return 0;
1963 }
1964 if ((count = get_data(1)) < 0) {
1965 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1966 return 0;
1967 }
1968 for (i = 0, ch = -1; count > 0; count--) {
1969 if ((ch = get_data(1)) < 0) {
1970 DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1971 break;
1972 }
1973 if (i < 99)
1974 devname[i++] = ch;
1975 }
1976 devname[i] = '\0';
1977 if (ch < 0)
1978 return 0;
1979
1980 printk(KERN_INFO "optcd: Device %s detected\n", devname);
1981 return ((devname[0] == 'D')
1982 && (devname[1] == 'O')
1983 && (devname[2] == 'L')
1984 && (devname[3] == 'P')
1985 && (devname[4] == 'H')
1986 && (devname[5] == 'I')
1987 && (devname[6] == 'N'));
1988}
1989
1990
1991static struct block_device_operations opt_fops = {
1992 .owner = THIS_MODULE,
1993 .open = opt_open,
1994 .release = opt_release,
1995 .ioctl = opt_ioctl,
1996 .media_changed = opt_media_change,
1997};
1998
1999#ifndef MODULE
2000
2001static int optcd_setup(char *str)
2002{
2003 int ints[4];
2004 (void)get_options(str, ARRAY_SIZE(ints), ints);
2005
2006 if (ints[0] > 0)
2007 optcd_port = ints[1];
2008
2009 return 1;
2010}
2011
2012__setup("optcd=", optcd_setup);
2013
2014#endif
2015
2016
2017
2018static int __init optcd_init(void)
2019{
2020 int status;
2021
2022 if (optcd_port <= 0) {
2023 printk(KERN_INFO
2024 "optcd: no Optics Storage CDROM Initialization\n");
2025 return -EIO;
2026 }
2027 optcd_disk = alloc_disk(1);
2028 if (!optcd_disk) {
2029 printk(KERN_ERR "optcd: can't allocate disk\n");
2030 return -ENOMEM;
2031 }
2032 optcd_disk->major = MAJOR_NR;
2033 optcd_disk->first_minor = 0;
2034 optcd_disk->fops = &opt_fops;
2035 sprintf(optcd_disk->disk_name, "optcd");
2036 sprintf(optcd_disk->devfs_name, "optcd");
2037
2038 if (!request_region(optcd_port, 4, "optcd")) {
2039 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2040 optcd_port);
2041 put_disk(optcd_disk);
2042 return -EIO;
2043 }
2044
2045 if (!reset_drive()) {
2046 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2047 release_region(optcd_port, 4);
2048 put_disk(optcd_disk);
2049 return -EIO;
2050 }
2051 if (!version_ok()) {
2052 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2053 release_region(optcd_port, 4);
2054 put_disk(optcd_disk);
2055 return -EIO;
2056 }
2057 status = exec_cmd(COMINITDOUBLE);
2058 if (status < 0) {
2059 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2060 release_region(optcd_port, 4);
2061 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2062 put_disk(optcd_disk);
2063 return -EIO;
2064 }
2065 if (register_blkdev(MAJOR_NR, "optcd")) {
2066 release_region(optcd_port, 4);
2067 put_disk(optcd_disk);
2068 return -EIO;
2069 }
2070
2071
2072 opt_queue = blk_init_queue(do_optcd_request, &optcd_lock);
2073 if (!opt_queue) {
2074 unregister_blkdev(MAJOR_NR, "optcd");
2075 release_region(optcd_port, 4);
2076 put_disk(optcd_disk);
2077 return -ENOMEM;
2078 }
2079
2080 blk_queue_hardsect_size(opt_queue, 2048);
2081 optcd_disk->queue = opt_queue;
2082 add_disk(optcd_disk);
2083
2084 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2085 return 0;
2086}
2087
2088
2089static void __exit optcd_exit(void)
2090{
2091 del_gendisk(optcd_disk);
2092 put_disk(optcd_disk);
2093 if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2094 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2095 return;
2096 }
2097 blk_cleanup_queue(opt_queue);
2098 release_region(optcd_port, 4);
2099 printk(KERN_INFO "optcd: module released.\n");
2100}
2101
2102module_init(optcd_init);
2103module_exit(optcd_exit);
2104
2105MODULE_LICENSE("GPL");
2106MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR);
2107