1 /* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
2 $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $
4 Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
7 Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
8 by Eberhard Moenkeberg (emoenke@gwdg.de).
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet.
29 Detection of disk change doesn't work.
30 21-5-95 v0.1 First ALPHA version. CD can be mounted. The
31 device major nr is borrowed from the Aztech
32 driver. Speed is around 240 kb/s, as measured
33 with "time dd if=/dev/cdrom of=/dev/null \
35 24-6-95 v0.2 Reworked the #defines for the command codes
36 and the like, as well as the structure of
37 the hardware communication protocol, to
38 reflect the "official" documentation, kindly
39 supplied by C.K. Tan, Optics Storage Pte. Ltd.
40 Also tidied up the state machine somewhat.
41 28-6-95 v0.3 Removed the ISP-16 interface code, as this
42 should go into its own driver. The driver now
44 Disk change detection now seems to work, too.
45 This version became part of the standard
46 kernel as of version 1.3.7
47 24-9-95 v0.4 Re-inserted ISP-16 interface code which I
48 copied from sjcd.c, with a few changes.
49 Updated README.optcd. Submitted for
51 29-9-95 v0.4a Fixed bug that prevented compilation as module
52 25-10-95 v0.5 Started multisession code. Implementation
53 copied from Werner Zimmermann, who copied it
54 from Heiko Schlittermann's mcdx.
55 17-1-96 v0.6 Multisession works; some cleanup too.
56 18-4-96 v0.7 Increased some timing constants;
57 thanks to Luke McFarlane. Also tidied up some
58 printk behaviour. ISP16 initialization
59 is now handled by a separate driver.
61 09-11-99 Make kernel-parameter implementation work with 2.3.x
62 Removed init_module & cleanup_module in favor of
63 module_init & module_exit.
64 Torben Mathiasen <tmm@image.dk>
70 #include <linux/module.h>
72 #include <linux/ioport.h>
73 #include <linux/init.h>
74 #include <linux/devfs_fs_kernel.h>
78 #define MAJOR_NR OPTICS_CDROM_MAJOR
79 #include <linux/blk.h>
81 #include <linux/cdrom.h>
84 #include <asm/uaccess.h>
90 /* Don't forget to add new debug flags here. */
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
94 static void debug(int debug_this
, const char* fmt
, ...)
103 vsprintf(s
, fmt
, args
);
104 printk(KERN_DEBUG
"optcd: %s\n", s
);
111 static int blksize
= 2048;
112 static int hsecsize
= 2048;
115 /* Drive hardware/firmware characteristics
116 Identifiers in accordance with Optics Storage documentation */
119 #define optcd_port optcd /* Needed for the modutils. */
120 static short optcd_port
= OPTCD_PORTBASE
; /* I/O base of drive. */
121 MODULE_PARM(optcd_port
, "h");
122 /* Drive registers, read */
123 #define DATA_PORT optcd_port /* Read data/status */
124 #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */
126 /* Drive registers, write */
127 #define COMIN_PORT optcd_port /* For passing command/parameter */
128 #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */
129 #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */
132 /* Command completion/status read from DATA register */
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
154 /* Error codes (appear as command completion code from DATA register) */
155 /* Player related errors */
156 #define ERR_ILLCMD 0x11 /* Illegal command to player module */
157 #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */
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 /* PLL lock error */
163 #define ERR_SUB_TIM 0x18 /* Subcode timeout error */
164 #define ERR_SUB_NF 0x19 /* Subcode not found error */
165 #define ERR_TRAY 0x1a
166 #define ERR_TOC 0x1b /* Table of Contents read error */
167 #define ERR_JUMP 0x1c
169 #define ERR_MODE 0x21
170 #define ERR_FORM 0x22
171 #define ERR_HEADADDR 0x23 /* Header Address not found */
173 #define ERR_ECC 0x25 /* Uncorrectable ECC error */
174 #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */
175 #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */
176 #define ERR_VDST 0x28 /* VDST not found */
178 #define ERR_READ_TIM 0x31 /* Read timeout error */
179 #define ERR_DEC_STP 0x32 /* Decoder stopped */
180 #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */
181 /* Function abort codes */
182 #define ERR_KEY 0x41 /* Key -Detected abort */
183 #define ERR_READ_FINISH 0x42 /* Read Finish */
184 /* Second Byte diagnostic codes */
185 #define ERR_NOBSYNC 0x01 /* No block sync */
186 #define ERR_SHORTB 0x02 /* Short block */
187 #define ERR_LONGB 0x03 /* Long block */
188 #define ERR_SHORTDSP 0x04 /* Short DSP word */
189 #define ERR_LONGDSP 0x05 /* Long DSP word */
192 /* Status availability flags read from STATUS register */
193 #define FL_EJECT 0x20
194 #define FL_WAIT 0x10 /* active low */
195 #define FL_EOP 0x08 /* active low */
196 #define FL_STEN 0x04 /* Status available when low */
197 #define FL_DTEN 0x02 /* Data available when low */
198 #define FL_DRQ 0x01 /* active low */
199 #define FL_RESET 0xde /* These bits are high after a reset */
200 #define FL_STDT (FL_STEN|FL_DTEN)
203 /* Transfer mode, written to HCON register */
204 #define HCON_DTS 0x08
205 #define HCON_SDRQB 0x04
206 #define HCON_LOHI 0x02
207 #define HCON_DMA16 0x01
210 /* Drive command set, written to COMIN register */
211 /* Quick response commands */
212 #define COMDRVST 0x20 /* Drive Status Read */
213 #define COMERRST 0x21 /* Error Status Read */
214 #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */
215 #define COMINITSINGLE 0x28 /* Initialize Single Speed */
216 #define COMINITDOUBLE 0x29 /* Initialize Double Speed */
217 #define COMUNLOCK 0x30 /* Unlock */
218 #define COMLOCK 0x31 /* Lock */
219 #define COMLOCKST 0x32 /* Lock/Unlock Status */
220 #define COMVERSION 0x40 /* Get Firmware Revision */
221 #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */
223 #define COMFETCH 0x60 /* Prefetch Data */
224 #define COMREAD 0x61 /* Read */
225 #define COMREADRAW 0x62 /* Read Raw Data */
226 #define COMREADALL 0x63 /* Read All 2646 Bytes */
227 /* Player control commands */
228 #define COMLEADIN 0x70 /* Seek To Lead-in */
229 #define COMSEEK 0x71 /* Seek */
230 #define COMPAUSEON 0x80 /* Pause On */
231 #define COMPAUSEOFF 0x81 /* Pause Off */
232 #define COMSTOP 0x82 /* Stop */
233 #define COMOPEN 0x90 /* Open Tray Door */
234 #define COMCLOSE 0x91 /* Close Tray Door */
235 #define COMPLAY 0xa0 /* Audio Play */
236 #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */
237 #define COMSUBQ 0xb0 /* Read Sub-q Code */
238 #define COMLOCATION 0xb1 /* Read Head Position */
239 /* Audio control commands */
240 #define COMCHCTRL 0xc0 /* Audio Channel Control */
241 /* Miscellaneous (test) commands */
242 #define COMDRVTEST 0xd0 /* Write Test Bytes */
243 #define COMTEST 0xd1 /* Diagnostic Test */
245 /* Low level drive interface. Only here we do actual I/O
246 Waiting for status / data available */
249 /* Busy wait until FLAG goes low. Return 0 on timeout. */
250 inline static int flag_low(int flag
, unsigned long timeout
)
253 unsigned long count
= 0;
255 while ((flag_high
= (inb(STATUS_PORT
) & flag
)))
256 if (++count
>= timeout
)
259 DEBUG((DEBUG_DRIVE_IF
, "flag_low 0x%x count %ld%s",
260 flag
, count
, flag_high
? " timeout" : ""));
265 /* Timed waiting for status or data */
266 static int sleep_timeout
; /* max # of ticks to sleep */
267 static DECLARE_WAIT_QUEUE_HEAD(waitq
);
268 static void sleep_timer(unsigned long data
);
269 static struct timer_list delay_timer
= {function
: sleep_timer
};
272 /* Timer routine: wake up when desired flag goes low,
273 or when timeout expires. */
274 static void sleep_timer(unsigned long data
)
276 int flags
= inb(STATUS_PORT
) & FL_STDT
;
278 if (flags
== FL_STDT
&& --sleep_timeout
> 0) {
279 mod_timer(&delay_timer
, jiffies
+ HZ
/100); /* multi-statement macro */
285 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
286 static int sleep_flag_low(int flag
, unsigned long timeout
)
290 DEBUG((DEBUG_DRIVE_IF
, "sleep_flag_low"));
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);
297 flag_high
= inb(STATUS_PORT
) & flag
;
300 DEBUG((DEBUG_DRIVE_IF
, "flag 0x%x count %ld%s",
301 flag
, timeout
, flag_high
? " timeout" : ""));
305 /* Low level drive interface. Only here we do actual I/O
306 Sending commands and parameters */
309 /* Errors in the command protocol */
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
317 /* Send command code. Return <0 indicates error */
318 static int send_cmd(int cmd
)
322 DEBUG((DEBUG_DRIVE_IF
, "sending command 0x%02x\n", cmd
));
324 outb(HCON_DTS
, HCON_PORT
); /* Enable Suspend Data Transfer */
325 outb(cmd
, COMIN_PORT
); /* Send command code */
326 if (!flag_low(FL_STEN
, BUSY_TIMEOUT
)) /* Wait for status */
327 return -ERR_IF_CMD_TIMEOUT
;
328 ack
= inb(DATA_PORT
); /* read command acknowledge */
329 outb(HCON_SDRQB
, HCON_PORT
); /* Disable Suspend Data Transfer */
330 return ack
==ST_OP_OK
? 0 : -ack
;
334 /* Send command parameters. Return <0 indicates error */
335 static int send_params(struct cdrom_msf
*params
)
339 DEBUG((DEBUG_DRIVE_IF
, "sending parameters"
344 params
->cdmsf_frame0
,
347 params
->cdmsf_frame1
));
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
)) /* Wait for status */
356 return -ERR_IF_CMD_TIMEOUT
;
357 ack
= inb(DATA_PORT
); /* read command acknowledge */
358 return ack
==ST_PA_OK
? 0 : -ack
;
362 /* Send parameters for SEEK command. Return <0 indicates error */
363 static int send_seek_params(struct cdrom_msf
*params
)
367 DEBUG((DEBUG_DRIVE_IF
, "sending seek parameters"
371 params
->cdmsf_frame0
));
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
)) /* Wait for status */
377 return -ERR_IF_CMD_TIMEOUT
;
378 ack
= inb(DATA_PORT
); /* read command acknowledge */
379 return ack
==ST_PA_OK
? 0 : -ack
;
383 /* Wait for command execution status. Choice between busy waiting
384 and sleeping. Return value <0 indicates timeout. */
385 inline static int get_exec_status(int busy_waiting
)
387 unsigned char exec_status
;
390 ? !flag_low(FL_STEN
, BUSY_TIMEOUT
)
391 : !sleep_flag_low(FL_STEN
, SLEEP_TIMEOUT
))
392 return -ERR_IF_CMD_TIMEOUT
;
394 exec_status
= inb(DATA_PORT
);
395 DEBUG((DEBUG_DRIVE_IF
, "returned exec status 0x%02x", exec_status
));
400 /* Wait busy for extra byte of data that a command returns.
401 Return value <0 indicates timeout. */
402 inline static int get_data(int short_timeout
)
406 if (!flag_low(FL_STEN
, short_timeout
? FAST_TIMEOUT
: BUSY_TIMEOUT
))
407 return -ERR_IF_DATA_TIMEOUT
;
409 data
= inb(DATA_PORT
);
410 DEBUG((DEBUG_DRIVE_IF
, "returned data 0x%02x", data
));
415 /* Returns 0 if failed */
416 static int reset_drive(void)
418 unsigned long count
= 0;
421 DEBUG((DEBUG_DRIVE_IF
, "reset drive"));
424 while (++count
< RESET_WAIT
)
428 while ((flags
= (inb(STATUS_PORT
) & FL_RESET
)) != FL_RESET
)
429 if (++count
>= BUSY_TIMEOUT
)
432 DEBUG((DEBUG_DRIVE_IF
, "reset %s",
433 flags
== FL_RESET
? "succeeded" : "failed"));
435 if (flags
!= FL_RESET
)
436 return 0; /* Reset failed */
437 outb(HCON_SDRQB
, HCON_PORT
); /* Disable Suspend Data Transfer */
438 return 1; /* Reset succeeded */
442 /* Facilities for asynchronous operation */
444 /* Read status/data availability flags FL_STEN and FL_DTEN */
445 inline static int stdt_flags(void)
447 return inb(STATUS_PORT
) & FL_STDT
;
451 /* Fetch status that has previously been waited for. <0 means not available */
452 inline static int fetch_status(void)
454 unsigned char status
;
456 if (inb(STATUS_PORT
) & FL_STEN
)
457 return -ERR_IF_NOSTAT
;
459 status
= inb(DATA_PORT
);
460 DEBUG((DEBUG_DRIVE_IF
, "fetched exec status 0x%02x", status
));
465 /* Fetch data that has previously been waited for. */
466 inline static void fetch_data(char *buf
, int n
)
468 insb(DATA_PORT
, buf
, n
);
469 DEBUG((DEBUG_DRIVE_IF
, "fetched 0x%x bytes", n
));
473 /* Flush status and data fifos */
474 inline static void flush_data(void)
476 while ((inb(STATUS_PORT
) & FL_STDT
) != FL_STDT
)
478 DEBUG((DEBUG_DRIVE_IF
, "flushed fifos"));
481 /* Command protocol */
484 /* Send a simple command and wait for response. Command codes < COMFETCH
485 are quick response commands */
486 inline static int exec_cmd(int cmd
)
488 int ack
= send_cmd(cmd
);
491 return get_exec_status(cmd
< COMFETCH
);
495 /* Send a command with parameters. Don't wait for the response,
496 * which consists of data blocks read from the CD. */
497 inline static int exec_read_cmd(int cmd
, struct cdrom_msf
*params
)
499 int ack
= send_cmd(cmd
);
502 return send_params(params
);
506 /* Send a seek command with parameters and wait for response */
507 inline static int exec_seek_cmd(int cmd
, struct cdrom_msf
*params
)
509 int ack
= send_cmd(cmd
);
512 ack
= send_seek_params(params
);
519 /* Send a command with parameters and wait for response */
520 inline static int exec_long_cmd(int cmd
, struct cdrom_msf
*params
)
522 int ack
= exec_read_cmd(cmd
, params
);
525 return get_exec_status(0);
528 /* Address conversion routines */
531 /* Binary to BCD (2 digits) */
532 inline static void single_bin2bcd(u_char
*p
)
534 DEBUG((DEBUG_CONV
, "bin2bcd %02d", *p
));
535 *p
= (*p
% 10) | ((*p
/ 10) << 4);
539 /* Convert entire msf struct */
540 static void bin2bcd(struct cdrom_msf
*msf
)
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
);
551 /* Linear block address to minute, second, frame form */
552 #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */
554 static void lba2msf(int lba
, struct cdrom_msf
*msf
)
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
;
563 msf
->cdmsf_frame1
= 0;
568 /* Two BCD digits to binary */
569 inline static u_char
bcd2bin(u_char bcd
)
571 DEBUG((DEBUG_CONV
, "bcd2bin %x%02x", bcd
));
572 return (bcd
>> 4) * 10 + (bcd
& 0x0f);
576 static void msf2lba(union cdrom_addr
*addr
)
578 addr
->lba
= addr
->msf
.minute
* CD_FPM
579 + addr
->msf
.second
* CD_FRAMES
580 + addr
->msf
.frame
- CD_MSF_OFFSET
;
584 /* Minute, second, frame address BCD to binary or to linear address,
586 static void msf_bcd2bin(union cdrom_addr
*addr
)
588 addr
->msf
.minute
= bcd2bin(addr
->msf
.minute
);
589 addr
->msf
.second
= bcd2bin(addr
->msf
.second
);
590 addr
->msf
.frame
= bcd2bin(addr
->msf
.frame
);
593 /* High level drive commands */
596 static int audio_status
= CDROM_AUDIO_NO_STATUS
;
597 static char toc_uptodate
= 0;
598 static char disk_changed
= 1;
600 /* Get drive status, flagging completion of audio play and disk changes. */
601 static int drive_status(void)
605 status
= exec_cmd(COMIOCTLISTAT
);
606 DEBUG((DEBUG_DRIVE_IF
, "IOCTLISTAT: %03x", status
));
609 if (status
== 0xff) /* No status available */
610 return -ERR_IF_NOSTAT
;
612 if (((status
& ST_MODE_BITS
) != ST_M_AUDIO
) &&
613 (audio_status
== CDROM_AUDIO_PLAY
)) {
614 audio_status
= CDROM_AUDIO_COMPLETED
;
617 if (status
& ST_DSK_CHG
) {
620 audio_status
= CDROM_AUDIO_NO_STATUS
;
627 /* Read the current Q-channel info. Also used for reading the
628 table of contents. qp->cdsc_format must be set on entry to
629 indicate the desired address format */
630 static int get_q_channel(struct cdrom_subchnl
*qp
)
632 int status
, d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
;
634 status
= drive_status();
637 qp
->cdsc_audiostatus
= audio_status
;
639 status
= exec_cmd(COMSUBQ
);
647 qp
->cdsc_ctrl
= d1
>> 4;
652 qp
->cdsc_trk
= bcd2bin(d2
);
657 qp
->cdsc_ind
= bcd2bin(d3
);
662 qp
->cdsc_reladdr
.msf
.minute
= d4
;
667 qp
->cdsc_reladdr
.msf
.second
= d5
;
672 qp
->cdsc_reladdr
.msf
.frame
= d6
;
682 qp
->cdsc_absaddr
.msf
.minute
= d8
;
687 qp
->cdsc_absaddr
.msf
.second
= d9
;
692 qp
->cdsc_absaddr
.msf
.frame
= d10
;
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
));
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
);
707 /* Table of contents handling */
710 /* Errors in table of contents */
711 #define ERR_TOC_MISSINGINFO 0x120
712 #define ERR_TOC_MISSINGENTRY 0x121
715 struct cdrom_disk_info
{
718 struct cdrom_msf0 disk_length
;
719 struct cdrom_msf0 first_track
;
720 /* Multisession info: */
722 struct cdrom_msf0 next_session
;
723 struct cdrom_msf0 last_session
;
728 static struct cdrom_disk_info disk_info
;
730 #define MAX_TRACKS 111
731 static struct cdrom_subchnl toc
[MAX_TRACKS
];
733 #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */
734 #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */
735 #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */
736 #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */
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)
746 void toc_debug_info(int i
)
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
);
762 static int read_toc(void)
764 int status
, limit
, count
;
765 unsigned char got_info
= 0;
766 struct cdrom_subchnl q_info
;
771 DEBUG((DEBUG_TOC
, "starting read_toc"));
774 for (limit
= 60; limit
> 0; limit
--) {
777 q_info
.cdsc_format
= CDROM_MSF
;
778 status
= get_q_channel(&q_info
);
782 index
= q_info
.cdsc_ind
;
783 if (index
> 0 && index
< MAX_TRACKS
784 && q_info
.cdsc_trk
== 0 && toc
[index
].cdsc_ind
== 0) {
786 DEBUG((DEBUG_TOC
, "got %d", index
));
790 switch (q_info
.cdsc_ind
) {
791 case QINFO_FIRSTTRACK
:
792 got_info
|= I_FIRSTTRACK
;
794 case QINFO_LASTTRACK
:
795 got_info
|= I_LASTTRACK
;
797 case QINFO_DISKLENGTH
:
798 got_info
|= I_DISKLENGTH
;
800 case QINFO_NEXTSESSION
:
801 got_info
|= I_NEXTSESSION
;
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)
812 /* Construct disk_info from TOC */
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
;
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
;
849 for (i
= 1; i
<= disk_info
.last
+ 1; 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
);
857 DEBUG((DEBUG_TOC
, "exiting read_toc, got_info %x, count %d",
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
;
868 static int get_multi_disk_info(void)
870 int sessions
, status
;
871 struct cdrom_msf multi_index
;
874 for (sessions
= 2; sessions
< 10 /* %%for now */; sessions
++) {
877 for (count
= 100; count
< MAX_TRACKS
; count
++)
878 toc
[count
].cdsc_ind
= 0;
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;
886 multi_index
.cdmsf_sec0
+= 40;
887 multi_index
.cdmsf_min0
--;
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;
898 status
= exec_read_cmd(COMREAD
, &multi_index
);
900 DEBUG((DEBUG_TOC
, "exec_read_cmd COMREAD: %02x",
904 status
= sleep_flag_low(FL_DTEN
, MULTI_SEEK_TIMEOUT
) ?
905 0 : -ERR_TOC_MISSINGINFO
;
908 DEBUG((DEBUG_TOC
, "sleep_flag_low: %02x", -status
));
914 DEBUG((DEBUG_TOC
, "read_toc: %02x", -status
));
930 static int update_toc(void)
937 DEBUG((DEBUG_TOC
, "starting update_toc"));
940 for (count
= 0; count
< MAX_TRACKS
; count
++)
941 toc
[count
].cdsc_ind
= 0;
943 status
= exec_cmd(COMLEADIN
);
949 DEBUG((DEBUG_TOC
, "read_toc: %02x", -status
));
953 /* Audio disk detection. Look at first track. */
955 (toc
[disk_info
.first
].cdsc_ctrl
& CDROM_DATA_TRACK
) ? 0 : 1;
958 disk_info
.xa
= drive_status() & ST_MODE2TRACK
;
960 /* Multisession detection: if we want this, define MULTISESSION */
964 get_multi_disk_info(); /* Here disk_info.multi is set */
967 printk(KERN_WARNING
"optcd: Multisession support experimental, "
968 "see linux/Documentation/cdrom/optcd\n");
970 DEBUG((DEBUG_TOC
, "exiting update_toc"));
976 /* Request handling */
979 #define CURRENT_VALID \
980 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
981 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
984 /* Buffers for block size conversion. */
987 static char buf
[CD_FRAMESIZE
* N_BUFS
];
988 static volatile int buf_bn
[N_BUFS
], next_bn
;
989 static volatile int buf_in
= 0, buf_out
= NOBUF
;
991 inline static void opt_invalidate_buffers(void)
995 DEBUG((DEBUG_BUFFERS
, "executing opt_invalidate_buffers"));
997 for (i
= 0; i
< N_BUFS
; i
++)
1003 /* Take care of the different block sizes between cdrom and Linux.
1004 When Linux gets variable block sizes this will probably go away. */
1005 static void transfer(void)
1007 #if DEBUG_BUFFERS | DEBUG_REQUEST
1008 printk(KERN_DEBUG
"optcd: executing transfer\n");
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
);
1018 DEBUG((DEBUG_REQUEST
, "found %d", i
));
1025 offs
= (i
* 4 + (CURRENT
-> sector
& 3)) * 512;
1026 nr_sectors
= 4 - (CURRENT
-> sector
& 3);
1030 if (buf_bn
[i
] != bn
) {
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;
1046 /* State machine for reading disk blocks */
1057 static volatile enum state_e state
= S_IDLE
;
1059 static volatile enum state_e state_old
= S_STOP
;
1060 static volatile int flags_old
= 0;
1061 static volatile long state_n
= 0;
1065 /* Used as mutex to keep do_optcd_request (and other processes calling
1066 ioctl) out while some process is inside a VFS call.
1067 Reverse is accomplished by checking if state = S_IDLE upon entry
1068 of opt_ioctl and opt_media_change. */
1069 static int in_vfs
= 0;
1072 static volatile int transfer_is_active
= 0;
1073 static volatile int error
= 0; /* %% do something with this?? */
1074 static int tries
; /* ibid?? */
1075 static int timeout
= 0;
1077 static void poll(unsigned long data
);
1078 static struct timer_list req_timer
= {function
: poll
};
1081 static void poll(unsigned long data
)
1083 static volatile int read_count
= 1;
1090 printk(KERN_ERR
"optcd: I/O error 0x%02x\n", error
);
1091 opt_invalidate_buffers();
1093 printk(KERN_ERR
"optcd: read block %d failed;"
1094 " Giving up\n", next_bn
);
1095 if (transfer_is_active
)
1107 loop_again
= 0; /* each case must flip this back to 1 if we want
1108 to come back up here */
1111 if (state
== state_old
)
1116 printk(KERN_DEBUG
"optcd: %ld times "
1117 "in previous state\n", state_n
);
1118 printk(KERN_DEBUG
"optcd: state %d\n", state
);
1129 if (send_cmd(COMDRVST
)) {
1131 while (CURRENT_VALID
)
1136 timeout
= READ_TIMEOUT
;
1139 struct cdrom_msf msf
;
1141 status
= fetch_status();
1144 if (status
& ST_DSK_CHG
) {
1146 opt_invalidate_buffers();
1150 if ((status
& ST_DOOR_OPEN
) || (status
& ST_DRVERR
)) {
1152 opt_invalidate_buffers();
1153 printk(KERN_WARNING
"optcd: %s\n",
1154 (status
& ST_DOOR_OPEN
)
1158 while (CURRENT_VALID
)
1162 if (!CURRENT_VALID
) {
1167 next_bn
= CURRENT
-> sector
/ 4;
1168 lba2msf(next_bn
, &msf
);
1169 read_count
= N_BUFS
;
1170 msf
.cdmsf_frame1
= read_count
; /* Not BCD! */
1172 DEBUG((DEBUG_REQUEST
, "reading %x:%x.%x %x:%x.%x",
1179 DEBUG((DEBUG_REQUEST
, "next_bn:%d buf_in:%d"
1180 " buf_out:%d buf_bn:%d",
1186 exec_read_cmd(COMREAD
, &msf
);
1188 timeout
= READ_TIMEOUT
;
1192 flags
= stdt_flags() & (FL_STEN
|FL_DTEN
);
1195 if (flags
!= flags_old
) {
1197 printk(KERN_DEBUG
"optcd: flags:%x\n", flags
);
1199 if (flags
== FL_STEN
)
1200 printk(KERN_DEBUG
"timeout cnt: %d\n", timeout
);
1204 case FL_DTEN
: /* only STEN low */
1207 "optcd: read block %d failed; "
1208 "Giving up\n", next_bn
);
1209 if (transfer_is_active
) {
1218 timeout
= READ_TIMEOUT
;
1220 case (FL_STEN
|FL_DTEN
): /* both high */
1222 default: /* DTEN low */
1224 if (!CURRENT_VALID
&& buf_in
== buf_out
) {
1231 "optcd: warning - try to read"
1233 while (read_count
) {
1234 buf_bn
[buf_in
] = NOBUF
;
1235 if (!flag_low(FL_DTEN
, BUSY_TIMEOUT
)) {
1236 /* should be no waiting here!?? */
1239 "CURRENT->nr_sectors:%ld "
1242 CURRENT
->nr_sectors
,
1245 "transfer active: %x\n",
1246 transfer_is_active
);
1254 CD_FRAMESIZE
*buf_in
,
1258 DEBUG((DEBUG_REQUEST
,
1259 "S_DATA; ---I've read data- "
1262 DEBUG((DEBUG_REQUEST
,
1263 "next_bn:%d buf_in:%d "
1264 "buf_out:%d buf_bn:%d",
1270 buf_bn
[buf_in
] = next_bn
++;
1271 if (buf_out
== NOBUF
)
1273 buf_in
= buf_in
+ 1 ==
1274 N_BUFS
? 0 : buf_in
+ 1;
1276 if (!transfer_is_active
) {
1277 while (CURRENT_VALID
) {
1279 if (CURRENT
-> nr_sectors
== 0)
1287 && (CURRENT
-> sector
/ 4 < next_bn
||
1288 CURRENT
-> sector
/ 4 >
1289 next_bn
+ N_BUFS
)) {
1294 timeout
= READ_TIMEOUT
;
1295 if (read_count
== 0) {
1303 if (read_count
!= 0)
1305 "optcd: discard data=%x frames\n",
1308 if (send_cmd(COMDRVST
)) {
1310 while (CURRENT_VALID
)
1315 timeout
= STOP_TIMEOUT
;
1318 status
= fetch_status();
1319 if (status
< 0 && timeout
)
1321 if ((status
>= 0) && (status
& ST_DSK_CHG
)) {
1323 opt_invalidate_buffers();
1325 if (CURRENT_VALID
) {
1341 printk(KERN_ERR
"optcd: invalid state %d\n", state
);
1347 printk(KERN_ERR
"optcd: timeout in state %d\n", state
);
1349 if (exec_cmd(COMSTOP
) < 0) {
1351 while (CURRENT_VALID
)
1357 mod_timer(&req_timer
, jiffies
+ HZ
/100);
1361 static void do_optcd_request(request_queue_t
* q
)
1363 DEBUG((DEBUG_REQUEST
, "do_optcd_request(%ld+%ld)",
1364 CURRENT
-> sector
, CURRENT
-> nr_sectors
));
1366 if (disk_info
.audio
) {
1367 printk(KERN_WARNING
"optcd: tried to mount an Audio CD\n");
1372 transfer_is_active
= 1;
1373 while (CURRENT_VALID
) {
1375 if (!buffer_locked(CURRENT
->bh
))
1376 panic(DEVICE_NAME
": block not locked");
1378 transfer(); /* First try to transfer block from buffers */
1379 if (CURRENT
-> nr_sectors
== 0) {
1381 } else { /* Want to read a block not in buffer */
1383 if (state
== S_IDLE
) {
1384 /* %% Should this block the request queue?? */
1385 if (update_toc() < 0) {
1386 while (CURRENT_VALID
)
1390 /* Start state machine */
1392 timeout
= READ_TIMEOUT
;
1394 /* %% why not start right away?? */
1395 mod_timer(&req_timer
, jiffies
+ HZ
/100);
1400 transfer_is_active
= 0;
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"));
1410 static char auto_eject
= 0;
1412 static int cdrompause(void)
1416 if (audio_status
!= CDROM_AUDIO_PLAY
)
1419 status
= exec_cmd(COMPAUSEON
);
1421 DEBUG((DEBUG_VFS
, "exec_cmd COMPAUSEON: %02x", -status
));
1424 audio_status
= CDROM_AUDIO_PAUSED
;
1429 static int cdromresume(void)
1433 if (audio_status
!= CDROM_AUDIO_PAUSED
)
1436 status
= exec_cmd(COMPAUSEOFF
);
1438 DEBUG((DEBUG_VFS
, "exec_cmd COMPAUSEOFF: %02x", -status
));
1439 audio_status
= CDROM_AUDIO_ERROR
;
1442 audio_status
= CDROM_AUDIO_PLAY
;
1447 static int cdromplaymsf(unsigned long arg
)
1450 struct cdrom_msf msf
;
1452 status
= verify_area(VERIFY_READ
, (void *) arg
, sizeof msf
);
1455 copy_from_user(&msf
, (void *) arg
, sizeof msf
);
1458 status
= exec_long_cmd(COMPLAY
, &msf
);
1460 DEBUG((DEBUG_VFS
, "exec_long_cmd COMPLAY: %02x", -status
));
1461 audio_status
= CDROM_AUDIO_ERROR
;
1465 audio_status
= CDROM_AUDIO_PLAY
;
1470 static int cdromplaytrkind(unsigned long arg
)
1474 struct cdrom_msf msf
;
1476 status
= verify_area(VERIFY_READ
, (void *) arg
, sizeof ti
);
1479 copy_from_user(&ti
, (void *) arg
, sizeof ti
);
1481 if (ti
.cdti_trk0
< disk_info
.first
1482 || ti
.cdti_trk0
> disk_info
.last
1483 || ti
.cdti_trk1
< ti
.cdti_trk0
)
1485 if (ti
.cdti_trk1
> disk_info
.last
)
1486 ti
.cdti_trk1
= disk_info
.last
;
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
;
1495 DEBUG((DEBUG_VFS
, "play %02d:%02d.%02d to %02d:%02d.%02d",
1504 status
= exec_long_cmd(COMPLAY
, &msf
);
1506 DEBUG((DEBUG_VFS
, "exec_long_cmd COMPLAY: %02x", -status
));
1507 audio_status
= CDROM_AUDIO_ERROR
;
1511 audio_status
= CDROM_AUDIO_PLAY
;
1516 static int cdromreadtochdr(unsigned long arg
)
1519 struct cdrom_tochdr tochdr
;
1521 status
= verify_area(VERIFY_WRITE
, (void *) arg
, sizeof tochdr
);
1525 tochdr
.cdth_trk0
= disk_info
.first
;
1526 tochdr
.cdth_trk1
= disk_info
.last
;
1528 copy_to_user((void *) arg
, &tochdr
, sizeof tochdr
);
1533 static int cdromreadtocentry(unsigned long arg
)
1536 struct cdrom_tocentry entry
;
1537 struct cdrom_subchnl
*tocptr
;
1539 status
= verify_area(VERIFY_WRITE
, (void *) arg
, sizeof entry
);
1542 copy_from_user(&entry
, (void *) arg
, sizeof entry
);
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
)
1550 tocptr
= &toc
[entry
.cdte_track
];
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 /* %% What should go into entry.cdte_datamode? */
1559 if (entry
.cdte_format
== CDROM_LBA
)
1560 msf2lba(&entry
.cdte_addr
);
1561 else if (entry
.cdte_format
!= CDROM_MSF
)
1564 copy_to_user((void *) arg
, &entry
, sizeof entry
);
1569 static int cdromvolctrl(unsigned long arg
)
1572 struct cdrom_volctrl volctrl
;
1573 struct cdrom_msf msf
;
1575 status
= verify_area(VERIFY_READ
, (void *) arg
, sizeof volctrl
);
1578 copy_from_user(&volctrl
, (char *) arg
, sizeof volctrl
);
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
;
1587 status
= exec_long_cmd(COMCHCTRL
, &msf
);
1589 DEBUG((DEBUG_VFS
, "exec_long_cmd COMCHCTRL: %02x", -status
));
1596 static int cdromsubchnl(unsigned long arg
)
1599 struct cdrom_subchnl subchnl
;
1601 status
= verify_area(VERIFY_WRITE
, (void *) arg
, sizeof subchnl
);
1604 copy_from_user(&subchnl
, (void *) arg
, sizeof subchnl
);
1606 if (subchnl
.cdsc_format
!= CDROM_LBA
1607 && subchnl
.cdsc_format
!= CDROM_MSF
)
1610 status
= get_q_channel(&subchnl
);
1612 DEBUG((DEBUG_VFS
, "get_q_channel: %02x", -status
));
1616 copy_to_user((void *) arg
, &subchnl
, sizeof subchnl
);
1621 static int cdromread(unsigned long arg
, int blocksize
, int cmd
)
1624 struct cdrom_msf msf
;
1625 char buf
[CD_FRAMESIZE_RAWER
];
1627 status
= verify_area(VERIFY_WRITE
, (void *) arg
, blocksize
);
1630 copy_from_user(&msf
, (void *) arg
, sizeof msf
);
1635 msf
.cdmsf_frame1
= 1; /* read only one frame */
1636 status
= exec_read_cmd(cmd
, &msf
);
1638 DEBUG((DEBUG_VFS
, "read cmd status 0x%x", status
));
1640 if (!sleep_flag_low(FL_DTEN
, SLEEP_TIMEOUT
))
1642 fetch_data(buf
, blocksize
);
1644 copy_to_user((void *) arg
, &buf
, blocksize
);
1649 static int cdromseek(unsigned long arg
)
1652 struct cdrom_msf msf
;
1654 status
= verify_area(VERIFY_READ
, (void *) arg
, sizeof msf
);
1657 copy_from_user(&msf
, (void *) arg
, sizeof msf
);
1660 status
= exec_seek_cmd(COMSEEK
, &msf
);
1662 DEBUG((DEBUG_VFS
, "COMSEEK status 0x%x", status
));
1671 static int cdrommultisession(unsigned long arg
)
1674 struct cdrom_multisession ms
;
1676 status
= verify_area(VERIFY_WRITE
, (void*) arg
, sizeof ms
);
1679 copy_from_user(&ms
, (void*) arg
, sizeof ms
);
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
;
1685 if (ms
.addr_format
!= CDROM_LBA
1686 && ms
.addr_format
!= CDROM_MSF
)
1688 if (ms
.addr_format
== CDROM_LBA
)
1691 ms
.xa_flag
= disk_info
.xa
;
1693 copy_to_user((void*) arg
, &ms
,
1694 sizeof(struct cdrom_multisession
));
1697 if (ms
.addr_format
== CDROM_MSF
)
1699 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1706 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1709 disk_info
.last_session
.minute
,
1710 disk_info
.last_session
.second
,
1711 disk_info
.last_session
.frame
);
1719 static int cdromreset(void)
1721 if (state
!= S_IDLE
) {
1728 opt_invalidate_buffers();
1729 audio_status
= CDROM_AUDIO_NO_STATUS
;
1739 static int opt_ioctl(struct inode
*ip
, struct file
*fp
,
1740 unsigned int cmd
, unsigned long arg
)
1742 int status
, err
, retval
= 0;
1744 DEBUG((DEBUG_VFS
, "starting opt_ioctl"));
1749 if (cmd
== CDROMRESET
)
1750 return cdromreset();
1752 /* is do_optcd_request or another ioctl busy? */
1753 if (state
!= S_IDLE
|| in_vfs
)
1758 status
= drive_status();
1760 DEBUG((DEBUG_VFS
, "drive_status: %02x", -status
));
1765 if (status
& ST_DOOR_OPEN
)
1766 switch (cmd
) { /* Actions that can be taken with door open */
1767 case CDROMCLOSETRAY
:
1768 /* We do this before trying to read the toc. */
1769 err
= exec_cmd(COMCLOSE
);
1772 "exec_cmd COMCLOSE: %02x", -err
));
1777 default: in_vfs
= 0;
1783 DEBUG((DEBUG_VFS
, "update_toc: %02x", -err
));
1788 DEBUG((DEBUG_VFS
, "ioctl cmd 0x%x", 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;
1798 case CDROMSTOP
: err
= exec_cmd(COMSTOP
);
1801 "exec_cmd COMSTOP: %02x",
1805 audio_status
= CDROM_AUDIO_NO_STATUS
;
1807 case CDROMSTART
: break; /* This is a no-op */
1808 case CDROMEJECT
: err
= exec_cmd(COMUNLOCK
);
1811 "exec_cmd COMUNLOCK: %02x",
1816 err
= exec_cmd(COMOPEN
);
1819 "exec_cmd COMOPEN: %02x",
1825 case CDROMVOLCTRL
: retval
= cdromvolctrl(arg
); break;
1826 case CDROMSUBCHNL
: retval
= cdromsubchnl(arg
); break;
1828 /* The drive detects the mode and automatically delivers the
1829 correct 2048 bytes, so we don't need these IOCTLs */
1830 case CDROMREADMODE2
: retval
= -EINVAL
; break;
1831 case CDROMREADMODE1
: retval
= -EINVAL
; break;
1833 /* Drive doesn't support reading audio */
1834 case CDROMREADAUDIO
: retval
= -EINVAL
; break;
1836 case CDROMEJECT_SW
: auto_eject
= (char) arg
;
1840 case CDROMMULTISESSION
: retval
= cdrommultisession(arg
); break;
1843 case CDROM_GET_MCN
: retval
= -EINVAL
; break; /* not implemented */
1844 case CDROMVOLREAD
: retval
= -EINVAL
; break; /* not implemented */
1847 /* this drive delivers 2340 bytes in raw mode */
1848 retval
= cdromread(arg
, CD_FRAMESIZE_RAW1
, COMREADRAW
);
1850 case CDROMREADCOOKED
:
1851 retval
= cdromread(arg
, CD_FRAMESIZE
, COMREAD
);
1854 retval
= cdromread(arg
, CD_FRAMESIZE_RAWER
, COMREADALL
);
1857 case CDROMSEEK
: retval
= cdromseek(arg
); break;
1858 case CDROMPLAYBLK
: retval
= -EINVAL
; break; /* not implemented */
1859 case CDROMCLOSETRAY
: break; /* The action was taken earlier */
1860 default: retval
= -EINVAL
;
1867 static int open_count
= 0;
1869 /* Open device special file; check that a disk is in. */
1870 static int opt_open(struct inode
*ip
, struct file
*fp
)
1872 DEBUG((DEBUG_VFS
, "starting opt_open"));
1876 if (!open_count
&& state
== S_IDLE
) {
1880 opt_invalidate_buffers();
1882 status
= exec_cmd(COMCLOSE
); /* close door */
1884 DEBUG((DEBUG_VFS
, "exec_cmd COMCLOSE: %02x", -status
));
1887 status
= drive_status();
1889 DEBUG((DEBUG_VFS
, "drive_status: %02x", -status
));
1892 DEBUG((DEBUG_VFS
, "status: %02x", status
));
1893 if ((status
& ST_DOOR_OPEN
) || (status
& ST_DRVERR
)) {
1894 printk(KERN_INFO
"optcd: no disk or door open\n");
1897 status
= exec_cmd(COMLOCK
); /* Lock door */
1899 DEBUG((DEBUG_VFS
, "exec_cmd COMLOCK: %02x", -status
));
1901 status
= update_toc(); /* Read table of contents */
1903 DEBUG((DEBUG_VFS
, "update_toc: %02x", -status
));
1904 status
= exec_cmd(COMUNLOCK
); /* Unlock door */
1907 "exec_cmd COMUNLOCK: %02x", -status
));
1914 DEBUG((DEBUG_VFS
, "exiting opt_open"));
1924 /* Release device special file; flush all blocks from the buffer cache */
1925 static int opt_release(struct inode
*ip
, struct file
*fp
)
1929 DEBUG((DEBUG_VFS
, "executing opt_release"));
1930 DEBUG((DEBUG_VFS
, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1931 ip
, ip
-> i_rdev
, fp
));
1933 if (!--open_count
) {
1935 opt_invalidate_buffers();
1936 status
= exec_cmd(COMUNLOCK
); /* Unlock door */
1938 DEBUG((DEBUG_VFS
, "exec_cmd COMUNLOCK: %02x", -status
));
1941 status
= exec_cmd(COMOPEN
);
1942 DEBUG((DEBUG_VFS
, "exec_cmd COMOPEN: %02x", -status
));
1944 del_timer(&delay_timer
);
1945 del_timer(&req_timer
);
1952 /* Check if disk has been changed */
1953 static int opt_media_change(kdev_t dev
)
1955 DEBUG((DEBUG_VFS
, "executing opt_media_change"));
1956 DEBUG((DEBUG_VFS
, "dev: 0x%x; disk_changed = %d\n", dev
, disk_changed
));
1965 /* Driver initialisation */
1968 /* Returns 1 if a drive is detected with a version string
1969 starting with "DOLPHIN". Otherwise 0. */
1970 static int __init
version_ok(void)
1973 int count
, i
, ch
, status
;
1975 status
= exec_cmd(COMVERSION
);
1977 DEBUG((DEBUG_VFS
, "exec_cmd COMVERSION: %02x", -status
));
1980 if ((count
= get_data(1)) < 0) {
1981 DEBUG((DEBUG_VFS
, "get_data(1): %02x", -count
));
1984 for (i
= 0, ch
= -1; count
> 0; count
--) {
1985 if ((ch
= get_data(1)) < 0) {
1986 DEBUG((DEBUG_VFS
, "get_data(1): %02x", -ch
));
1996 printk(KERN_INFO
"optcd: Device %s detected\n", devname
);
1997 return ((devname
[0] == 'D')
1998 && (devname
[1] == 'O')
1999 && (devname
[2] == 'L')
2000 && (devname
[3] == 'P')
2001 && (devname
[4] == 'H')
2002 && (devname
[5] == 'I')
2003 && (devname
[6] == 'N'));
2007 static struct block_device_operations opt_fops
= {
2009 release
: opt_release
,
2011 check_media_change
: opt_media_change
,
2015 /* Get kernel parameter when used as a kernel driver */
2016 static int optcd_setup(char *str
)
2019 (void)get_options(str
, ARRAY_SIZE(ints
), ints
);
2022 optcd_port
= ints
[1];
2027 __setup("optcd=", optcd_setup
);
2031 /* Test for presence of drive and initialize it. Called at boot time
2032 or during module initialisation. */
2033 int __init
optcd_init(void)
2037 if (optcd_port
<= 0) {
2039 "optcd: no Optics Storage CDROM Initialization\n");
2042 if (check_region(optcd_port
, 4)) {
2043 printk(KERN_ERR
"optcd: conflict, I/O port 0x%x already used\n",
2048 if (!reset_drive()) {
2049 printk(KERN_ERR
"optcd: drive at 0x%x not ready\n", optcd_port
);
2052 if (!version_ok()) {
2053 printk(KERN_ERR
"optcd: unknown drive detected; aborting\n");
2056 status
= exec_cmd(COMINITDOUBLE
);
2058 printk(KERN_ERR
"optcd: cannot init double speed mode\n");
2059 DEBUG((DEBUG_VFS
, "exec_cmd COMINITDOUBLE: %02x", -status
));
2062 if (devfs_register_blkdev(MAJOR_NR
, "optcd", &opt_fops
) != 0)
2064 printk(KERN_ERR
"optcd: unable to get major %d\n", MAJOR_NR
);
2067 devfs_register (NULL
, "optcd", DEVFS_FL_DEFAULT
, MAJOR_NR
, 0,
2068 S_IFBLK
| S_IRUGO
| S_IWUGO
, &opt_fops
, NULL
);
2069 hardsect_size
[MAJOR_NR
] = &hsecsize
;
2070 blksize_size
[MAJOR_NR
] = &blksize
;
2071 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
2072 read_ahead
[MAJOR_NR
] = 4;
2073 request_region(optcd_port
, 4, "optcd");
2074 register_disk(NULL
, MKDEV(MAJOR_NR
,0), 1, &opt_fops
, 0);
2076 printk(KERN_INFO
"optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port
);
2081 void __exit
optcd_exit(void)
2083 devfs_unregister(devfs_find_handle(NULL
, "optcd", 0, 0,
2084 DEVFS_SPECIAL_BLK
, 0));
2085 if (devfs_unregister_blkdev(MAJOR_NR
, "optcd") == -EINVAL
) {
2086 printk(KERN_ERR
"optcd: what's that: can't unregister\n");
2089 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
2090 release_region(optcd_port
, 4);
2091 printk(KERN_INFO
"optcd: module released.\n");
2095 module_init(optcd_init
);
2097 module_exit(optcd_exit
);