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>
76 #include <linux/blkdev.h>
78 #include <linux/cdrom.h>
81 #include <asm/uaccess.h>
83 #define MAJOR_NR OPTICS_CDROM_MAJOR
84 #define QUEUE (opt_queue)
85 #define CURRENT elv_next_request(opt_queue)
91 /* Don't forget to add new debug flags here. */
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
95 static void debug(int debug_this
, const char* fmt
, ...)
104 vsnprintf(s
, sizeof(s
), fmt
, args
);
105 printk(KERN_DEBUG
"optcd: %s\n", s
);
113 /* Drive hardware/firmware characteristics
114 Identifiers in accordance with Optics Storage documentation */
117 #define optcd_port optcd /* Needed for the modutils. */
118 static short optcd_port
= OPTCD_PORTBASE
; /* I/O base of drive. */
119 module_param(optcd_port
, short, 0);
120 /* Drive registers, read */
121 #define DATA_PORT optcd_port /* Read data/status */
122 #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */
124 /* Drive registers, write */
125 #define COMIN_PORT optcd_port /* For passing command/parameter */
126 #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */
127 #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */
130 /* Command completion/status read from DATA register */
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
152 /* Error codes (appear as command completion code from DATA register) */
153 /* Player related errors */
154 #define ERR_ILLCMD 0x11 /* Illegal command to player module */
155 #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */
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 /* PLL lock error */
161 #define ERR_SUB_TIM 0x18 /* Subcode timeout error */
162 #define ERR_SUB_NF 0x19 /* Subcode not found error */
163 #define ERR_TRAY 0x1a
164 #define ERR_TOC 0x1b /* Table of Contents read error */
165 #define ERR_JUMP 0x1c
167 #define ERR_MODE 0x21
168 #define ERR_FORM 0x22
169 #define ERR_HEADADDR 0x23 /* Header Address not found */
171 #define ERR_ECC 0x25 /* Uncorrectable ECC error */
172 #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */
173 #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */
174 #define ERR_VDST 0x28 /* VDST not found */
176 #define ERR_READ_TIM 0x31 /* Read timeout error */
177 #define ERR_DEC_STP 0x32 /* Decoder stopped */
178 #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */
179 /* Function abort codes */
180 #define ERR_KEY 0x41 /* Key -Detected abort */
181 #define ERR_READ_FINISH 0x42 /* Read Finish */
182 /* Second Byte diagnostic codes */
183 #define ERR_NOBSYNC 0x01 /* No block sync */
184 #define ERR_SHORTB 0x02 /* Short block */
185 #define ERR_LONGB 0x03 /* Long block */
186 #define ERR_SHORTDSP 0x04 /* Short DSP word */
187 #define ERR_LONGDSP 0x05 /* Long DSP word */
190 /* Status availability flags read from STATUS register */
191 #define FL_EJECT 0x20
192 #define FL_WAIT 0x10 /* active low */
193 #define FL_EOP 0x08 /* active low */
194 #define FL_STEN 0x04 /* Status available when low */
195 #define FL_DTEN 0x02 /* Data available when low */
196 #define FL_DRQ 0x01 /* active low */
197 #define FL_RESET 0xde /* These bits are high after a reset */
198 #define FL_STDT (FL_STEN|FL_DTEN)
201 /* Transfer mode, written to HCON register */
202 #define HCON_DTS 0x08
203 #define HCON_SDRQB 0x04
204 #define HCON_LOHI 0x02
205 #define HCON_DMA16 0x01
208 /* Drive command set, written to COMIN register */
209 /* Quick response commands */
210 #define COMDRVST 0x20 /* Drive Status Read */
211 #define COMERRST 0x21 /* Error Status Read */
212 #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */
213 #define COMINITSINGLE 0x28 /* Initialize Single Speed */
214 #define COMINITDOUBLE 0x29 /* Initialize Double Speed */
215 #define COMUNLOCK 0x30 /* Unlock */
216 #define COMLOCK 0x31 /* Lock */
217 #define COMLOCKST 0x32 /* Lock/Unlock Status */
218 #define COMVERSION 0x40 /* Get Firmware Revision */
219 #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */
221 #define COMFETCH 0x60 /* Prefetch Data */
222 #define COMREAD 0x61 /* Read */
223 #define COMREADRAW 0x62 /* Read Raw Data */
224 #define COMREADALL 0x63 /* Read All 2646 Bytes */
225 /* Player control commands */
226 #define COMLEADIN 0x70 /* Seek To Lead-in */
227 #define COMSEEK 0x71 /* Seek */
228 #define COMPAUSEON 0x80 /* Pause On */
229 #define COMPAUSEOFF 0x81 /* Pause Off */
230 #define COMSTOP 0x82 /* Stop */
231 #define COMOPEN 0x90 /* Open Tray Door */
232 #define COMCLOSE 0x91 /* Close Tray Door */
233 #define COMPLAY 0xa0 /* Audio Play */
234 #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */
235 #define COMSUBQ 0xb0 /* Read Sub-q Code */
236 #define COMLOCATION 0xb1 /* Read Head Position */
237 /* Audio control commands */
238 #define COMCHCTRL 0xc0 /* Audio Channel Control */
239 /* Miscellaneous (test) commands */
240 #define COMDRVTEST 0xd0 /* Write Test Bytes */
241 #define COMTEST 0xd1 /* Diagnostic Test */
243 /* Low level drive interface. Only here we do actual I/O
244 Waiting for status / data available */
247 /* Busy wait until FLAG goes low. Return 0 on timeout. */
248 static inline int flag_low(int flag
, unsigned long timeout
)
251 unsigned long count
= 0;
253 while ((flag_high
= (inb(STATUS_PORT
) & flag
)))
254 if (++count
>= timeout
)
257 DEBUG((DEBUG_DRIVE_IF
, "flag_low 0x%x count %ld%s",
258 flag
, count
, flag_high
? " timeout" : ""));
263 /* Timed waiting for status or data */
264 static int sleep_timeout
; /* max # of ticks to sleep */
265 static DECLARE_WAIT_QUEUE_HEAD(waitq
);
266 static void sleep_timer(unsigned long data
);
267 static DEFINE_TIMER(delay_timer
, sleep_timer
, 0, 0);
268 static DEFINE_SPINLOCK(optcd_lock
);
269 static struct request_queue
*opt_queue
;
271 /* Timer routine: wake up when desired flag goes low,
272 or when timeout expires. */
273 static void sleep_timer(unsigned long data
)
275 int flags
= inb(STATUS_PORT
) & FL_STDT
;
277 if (flags
== FL_STDT
&& --sleep_timeout
> 0) {
278 mod_timer(&delay_timer
, jiffies
+ HZ
/100); /* multi-statement macro */
284 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
285 static int sleep_flag_low(int flag
, unsigned long timeout
)
289 DEBUG((DEBUG_DRIVE_IF
, "sleep_flag_low"));
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);
296 flag_high
= inb(STATUS_PORT
) & flag
;
299 DEBUG((DEBUG_DRIVE_IF
, "flag 0x%x count %ld%s",
300 flag
, timeout
, flag_high
? " timeout" : ""));
304 /* Low level drive interface. Only here we do actual I/O
305 Sending commands and parameters */
308 /* Errors in the command protocol */
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
316 /* Send command code. Return <0 indicates error */
317 static int send_cmd(int cmd
)
321 DEBUG((DEBUG_DRIVE_IF
, "sending command 0x%02x\n", cmd
));
323 outb(HCON_DTS
, HCON_PORT
); /* Enable Suspend Data Transfer */
324 outb(cmd
, COMIN_PORT
); /* Send command code */
325 if (!flag_low(FL_STEN
, BUSY_TIMEOUT
)) /* Wait for status */
326 return -ERR_IF_CMD_TIMEOUT
;
327 ack
= inb(DATA_PORT
); /* read command acknowledge */
328 outb(HCON_SDRQB
, HCON_PORT
); /* Disable Suspend Data Transfer */
329 return ack
==ST_OP_OK
? 0 : -ack
;
333 /* Send command parameters. Return <0 indicates error */
334 static int send_params(struct cdrom_msf
*params
)
338 DEBUG((DEBUG_DRIVE_IF
, "sending parameters"
343 params
->cdmsf_frame0
,
346 params
->cdmsf_frame1
));
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
)) /* Wait for status */
355 return -ERR_IF_CMD_TIMEOUT
;
356 ack
= inb(DATA_PORT
); /* read command acknowledge */
357 return ack
==ST_PA_OK
? 0 : -ack
;
361 /* Send parameters for SEEK command. Return <0 indicates error */
362 static int send_seek_params(struct cdrom_msf
*params
)
366 DEBUG((DEBUG_DRIVE_IF
, "sending seek parameters"
370 params
->cdmsf_frame0
));
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
)) /* Wait for status */
376 return -ERR_IF_CMD_TIMEOUT
;
377 ack
= inb(DATA_PORT
); /* read command acknowledge */
378 return ack
==ST_PA_OK
? 0 : -ack
;
382 /* Wait for command execution status. Choice between busy waiting
383 and sleeping. Return value <0 indicates timeout. */
384 static inline int get_exec_status(int busy_waiting
)
386 unsigned char exec_status
;
389 ? !flag_low(FL_STEN
, BUSY_TIMEOUT
)
390 : !sleep_flag_low(FL_STEN
, SLEEP_TIMEOUT
))
391 return -ERR_IF_CMD_TIMEOUT
;
393 exec_status
= inb(DATA_PORT
);
394 DEBUG((DEBUG_DRIVE_IF
, "returned exec status 0x%02x", exec_status
));
399 /* Wait busy for extra byte of data that a command returns.
400 Return value <0 indicates timeout. */
401 static inline int get_data(int short_timeout
)
405 if (!flag_low(FL_STEN
, short_timeout
? FAST_TIMEOUT
: BUSY_TIMEOUT
))
406 return -ERR_IF_DATA_TIMEOUT
;
408 data
= inb(DATA_PORT
);
409 DEBUG((DEBUG_DRIVE_IF
, "returned data 0x%02x", data
));
414 /* Returns 0 if failed */
415 static int reset_drive(void)
417 unsigned long count
= 0;
420 DEBUG((DEBUG_DRIVE_IF
, "reset drive"));
423 while (++count
< RESET_WAIT
)
427 while ((flags
= (inb(STATUS_PORT
) & FL_RESET
)) != FL_RESET
)
428 if (++count
>= BUSY_TIMEOUT
)
431 DEBUG((DEBUG_DRIVE_IF
, "reset %s",
432 flags
== FL_RESET
? "succeeded" : "failed"));
434 if (flags
!= FL_RESET
)
435 return 0; /* Reset failed */
436 outb(HCON_SDRQB
, HCON_PORT
); /* Disable Suspend Data Transfer */
437 return 1; /* Reset succeeded */
441 /* Facilities for asynchronous operation */
443 /* Read status/data availability flags FL_STEN and FL_DTEN */
444 static inline int stdt_flags(void)
446 return inb(STATUS_PORT
) & FL_STDT
;
450 /* Fetch status that has previously been waited for. <0 means not available */
451 static inline int fetch_status(void)
453 unsigned char status
;
455 if (inb(STATUS_PORT
) & FL_STEN
)
456 return -ERR_IF_NOSTAT
;
458 status
= inb(DATA_PORT
);
459 DEBUG((DEBUG_DRIVE_IF
, "fetched exec status 0x%02x", status
));
464 /* Fetch data that has previously been waited for. */
465 static inline void fetch_data(char *buf
, int n
)
467 insb(DATA_PORT
, buf
, n
);
468 DEBUG((DEBUG_DRIVE_IF
, "fetched 0x%x bytes", n
));
472 /* Flush status and data fifos */
473 static inline void flush_data(void)
475 while ((inb(STATUS_PORT
) & FL_STDT
) != FL_STDT
)
477 DEBUG((DEBUG_DRIVE_IF
, "flushed fifos"));
480 /* Command protocol */
483 /* Send a simple command and wait for response. Command codes < COMFETCH
484 are quick response commands */
485 static inline int exec_cmd(int cmd
)
487 int ack
= send_cmd(cmd
);
490 return get_exec_status(cmd
< COMFETCH
);
494 /* Send a command with parameters. Don't wait for the response,
495 * which consists of data blocks read from the CD. */
496 static inline int exec_read_cmd(int cmd
, struct cdrom_msf
*params
)
498 int ack
= send_cmd(cmd
);
501 return send_params(params
);
505 /* Send a seek command with parameters and wait for response */
506 static inline int exec_seek_cmd(int cmd
, struct cdrom_msf
*params
)
508 int ack
= send_cmd(cmd
);
511 ack
= send_seek_params(params
);
518 /* Send a command with parameters and wait for response */
519 static inline int exec_long_cmd(int cmd
, struct cdrom_msf
*params
)
521 int ack
= exec_read_cmd(cmd
, params
);
524 return get_exec_status(0);
527 /* Address conversion routines */
530 /* Binary to BCD (2 digits) */
531 static inline void single_bin2bcd(u_char
*p
)
533 DEBUG((DEBUG_CONV
, "bin2bcd %02d", *p
));
534 *p
= (*p
% 10) | ((*p
/ 10) << 4);
538 /* Convert entire msf struct */
539 static void bin2bcd(struct cdrom_msf
*msf
)
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
);
550 /* Linear block address to minute, second, frame form */
551 #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */
553 static void lba2msf(int lba
, struct cdrom_msf
*msf
)
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
;
562 msf
->cdmsf_frame1
= 0;
567 /* Two BCD digits to binary */
568 static inline u_char
bcd2bin(u_char bcd
)
570 DEBUG((DEBUG_CONV
, "bcd2bin %x%02x", bcd
));
571 return (bcd
>> 4) * 10 + (bcd
& 0x0f);
575 static void msf2lba(union cdrom_addr
*addr
)
577 addr
->lba
= addr
->msf
.minute
* CD_FPM
578 + addr
->msf
.second
* CD_FRAMES
579 + addr
->msf
.frame
- CD_MSF_OFFSET
;
583 /* Minute, second, frame address BCD to binary or to linear address,
585 static void msf_bcd2bin(union cdrom_addr
*addr
)
587 addr
->msf
.minute
= bcd2bin(addr
->msf
.minute
);
588 addr
->msf
.second
= bcd2bin(addr
->msf
.second
);
589 addr
->msf
.frame
= bcd2bin(addr
->msf
.frame
);
592 /* High level drive commands */
595 static int audio_status
= CDROM_AUDIO_NO_STATUS
;
596 static char toc_uptodate
= 0;
597 static char disk_changed
= 1;
599 /* Get drive status, flagging completion of audio play and disk changes. */
600 static int drive_status(void)
604 status
= exec_cmd(COMIOCTLISTAT
);
605 DEBUG((DEBUG_DRIVE_IF
, "IOCTLISTAT: %03x", status
));
608 if (status
== 0xff) /* No status available */
609 return -ERR_IF_NOSTAT
;
611 if (((status
& ST_MODE_BITS
) != ST_M_AUDIO
) &&
612 (audio_status
== CDROM_AUDIO_PLAY
)) {
613 audio_status
= CDROM_AUDIO_COMPLETED
;
616 if (status
& ST_DSK_CHG
) {
619 audio_status
= CDROM_AUDIO_NO_STATUS
;
626 /* Read the current Q-channel info. Also used for reading the
627 table of contents. qp->cdsc_format must be set on entry to
628 indicate the desired address format */
629 static int get_q_channel(struct cdrom_subchnl
*qp
)
631 int status
, d1
, d2
, d3
, d4
, d5
, d6
, d7
, d8
, d9
, d10
;
633 status
= drive_status();
636 qp
->cdsc_audiostatus
= audio_status
;
638 status
= exec_cmd(COMSUBQ
);
646 qp
->cdsc_ctrl
= d1
>> 4;
651 qp
->cdsc_trk
= bcd2bin(d2
);
656 qp
->cdsc_ind
= bcd2bin(d3
);
661 qp
->cdsc_reladdr
.msf
.minute
= d4
;
666 qp
->cdsc_reladdr
.msf
.second
= d5
;
671 qp
->cdsc_reladdr
.msf
.frame
= d6
;
681 qp
->cdsc_absaddr
.msf
.minute
= d8
;
686 qp
->cdsc_absaddr
.msf
.second
= d9
;
691 qp
->cdsc_absaddr
.msf
.frame
= d10
;
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
));
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
);
706 /* Table of contents handling */
709 /* Errors in table of contents */
710 #define ERR_TOC_MISSINGINFO 0x120
711 #define ERR_TOC_MISSINGENTRY 0x121
714 struct cdrom_disk_info
{
717 struct cdrom_msf0 disk_length
;
718 struct cdrom_msf0 first_track
;
719 /* Multisession info: */
721 struct cdrom_msf0 next_session
;
722 struct cdrom_msf0 last_session
;
727 static struct cdrom_disk_info disk_info
;
729 #define MAX_TRACKS 111
730 static struct cdrom_subchnl toc
[MAX_TRACKS
];
732 #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */
733 #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */
734 #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */
735 #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */
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)
745 static void toc_debug_info(int i
)
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
);
761 static int read_toc(void)
763 int status
, limit
, count
;
764 unsigned char got_info
= 0;
765 struct cdrom_subchnl q_info
;
770 DEBUG((DEBUG_TOC
, "starting read_toc"));
773 for (limit
= 60; limit
> 0; limit
--) {
776 q_info
.cdsc_format
= CDROM_MSF
;
777 status
= get_q_channel(&q_info
);
781 index
= q_info
.cdsc_ind
;
782 if (index
> 0 && index
< MAX_TRACKS
783 && q_info
.cdsc_trk
== 0 && toc
[index
].cdsc_ind
== 0) {
785 DEBUG((DEBUG_TOC
, "got %d", index
));
789 switch (q_info
.cdsc_ind
) {
790 case QINFO_FIRSTTRACK
:
791 got_info
|= I_FIRSTTRACK
;
793 case QINFO_LASTTRACK
:
794 got_info
|= I_LASTTRACK
;
796 case QINFO_DISKLENGTH
:
797 got_info
|= I_DISKLENGTH
;
799 case QINFO_NEXTSESSION
:
800 got_info
|= I_NEXTSESSION
;
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)
811 /* Construct disk_info from TOC */
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
;
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
;
848 for (i
= 1; i
<= disk_info
.last
+ 1; 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
);
856 DEBUG((DEBUG_TOC
, "exiting read_toc, got_info %x, count %d",
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
;
867 static int get_multi_disk_info(void)
869 int sessions
, status
;
870 struct cdrom_msf multi_index
;
873 for (sessions
= 2; sessions
< 10 /* %%for now */; sessions
++) {
876 for (count
= 100; count
< MAX_TRACKS
; count
++)
877 toc
[count
].cdsc_ind
= 0;
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;
885 multi_index
.cdmsf_sec0
+= 40;
886 multi_index
.cdmsf_min0
--;
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;
897 status
= exec_read_cmd(COMREAD
, &multi_index
);
899 DEBUG((DEBUG_TOC
, "exec_read_cmd COMREAD: %02x",
903 status
= sleep_flag_low(FL_DTEN
, MULTI_SEEK_TIMEOUT
) ?
904 0 : -ERR_TOC_MISSINGINFO
;
907 DEBUG((DEBUG_TOC
, "sleep_flag_low: %02x", -status
));
913 DEBUG((DEBUG_TOC
, "read_toc: %02x", -status
));
926 #endif /* MULTISESSION */
929 static int update_toc(void)
936 DEBUG((DEBUG_TOC
, "starting update_toc"));
939 for (count
= 0; count
< MAX_TRACKS
; count
++)
940 toc
[count
].cdsc_ind
= 0;
942 status
= exec_cmd(COMLEADIN
);
948 DEBUG((DEBUG_TOC
, "read_toc: %02x", -status
));
952 /* Audio disk detection. Look at first track. */
954 (toc
[disk_info
.first
].cdsc_ctrl
& CDROM_DATA_TRACK
) ? 0 : 1;
957 disk_info
.xa
= drive_status() & ST_MODE2TRACK
;
959 /* Multisession detection: if we want this, define MULTISESSION */
963 get_multi_disk_info(); /* Here disk_info.multi is set */
964 #endif /* MULTISESSION */
966 printk(KERN_WARNING
"optcd: Multisession support experimental, "
967 "see Documentation/cdrom/optcd\n");
969 DEBUG((DEBUG_TOC
, "exiting update_toc"));
975 /* Request handling */
977 static int current_valid(void)
980 CURRENT
->cmd
== READ
&&
981 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 static inline 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");
1011 if (!current_valid())
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
)
1097 if (current_valid())
1098 end_request(CURRENT
, 0);
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())
1132 end_request(CURRENT
, 0);
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())
1159 end_request(CURRENT
, 0);
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
) {
1213 if (current_valid())
1214 end_request(CURRENT
, 0);
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
);
1250 end_request(CURRENT
, 0);
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)
1280 end_request(CURRENT
, 1);
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())
1311 end_request(CURRENT
, 0);
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())
1352 end_request(CURRENT
, 0);
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");
1368 end_request(CURRENT
, 0);
1372 transfer_is_active
= 1;
1373 while (current_valid()) {
1374 transfer(); /* First try to transfer block from buffers */
1375 if (CURRENT
-> nr_sectors
== 0) {
1376 end_request(CURRENT
, 1);
1377 } else { /* Want to read a block not in buffer */
1379 if (state
== S_IDLE
) {
1380 /* %% Should this block the request queue?? */
1381 if (update_toc() < 0) {
1382 while (current_valid())
1383 end_request(CURRENT
, 0);
1386 /* Start state machine */
1388 timeout
= READ_TIMEOUT
;
1390 /* %% why not start right away?? */
1391 mod_timer(&req_timer
, jiffies
+ HZ
/100);
1396 transfer_is_active
= 0;
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"));
1406 static char auto_eject
= 0;
1408 static int cdrompause(void)
1412 if (audio_status
!= CDROM_AUDIO_PLAY
)
1415 status
= exec_cmd(COMPAUSEON
);
1417 DEBUG((DEBUG_VFS
, "exec_cmd COMPAUSEON: %02x", -status
));
1420 audio_status
= CDROM_AUDIO_PAUSED
;
1425 static int cdromresume(void)
1429 if (audio_status
!= CDROM_AUDIO_PAUSED
)
1432 status
= exec_cmd(COMPAUSEOFF
);
1434 DEBUG((DEBUG_VFS
, "exec_cmd COMPAUSEOFF: %02x", -status
));
1435 audio_status
= CDROM_AUDIO_ERROR
;
1438 audio_status
= CDROM_AUDIO_PLAY
;
1443 static int cdromplaymsf(void __user
*arg
)
1446 struct cdrom_msf msf
;
1448 if (copy_from_user(&msf
, arg
, sizeof msf
))
1452 status
= exec_long_cmd(COMPLAY
, &msf
);
1454 DEBUG((DEBUG_VFS
, "exec_long_cmd COMPLAY: %02x", -status
));
1455 audio_status
= CDROM_AUDIO_ERROR
;
1459 audio_status
= CDROM_AUDIO_PLAY
;
1464 static int cdromplaytrkind(void __user
*arg
)
1468 struct cdrom_msf msf
;
1470 if (copy_from_user(&ti
, arg
, sizeof ti
))
1473 if (ti
.cdti_trk0
< disk_info
.first
1474 || ti
.cdti_trk0
> disk_info
.last
1475 || ti
.cdti_trk1
< ti
.cdti_trk0
)
1477 if (ti
.cdti_trk1
> disk_info
.last
)
1478 ti
.cdti_trk1
= disk_info
.last
;
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
;
1487 DEBUG((DEBUG_VFS
, "play %02d:%02d.%02d to %02d:%02d.%02d",
1496 status
= exec_long_cmd(COMPLAY
, &msf
);
1498 DEBUG((DEBUG_VFS
, "exec_long_cmd COMPLAY: %02x", -status
));
1499 audio_status
= CDROM_AUDIO_ERROR
;
1503 audio_status
= CDROM_AUDIO_PLAY
;
1508 static int cdromreadtochdr(void __user
*arg
)
1510 struct cdrom_tochdr tochdr
;
1512 tochdr
.cdth_trk0
= disk_info
.first
;
1513 tochdr
.cdth_trk1
= disk_info
.last
;
1515 return copy_to_user(arg
, &tochdr
, sizeof tochdr
) ? -EFAULT
: 0;
1519 static int cdromreadtocentry(void __user
*arg
)
1521 struct cdrom_tocentry entry
;
1522 struct cdrom_subchnl
*tocptr
;
1524 if (copy_from_user(&entry
, arg
, sizeof entry
))
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
)
1533 tocptr
= &toc
[entry
.cdte_track
];
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 /* %% What should go into entry.cdte_datamode? */
1542 if (entry
.cdte_format
== CDROM_LBA
)
1543 msf2lba(&entry
.cdte_addr
);
1544 else if (entry
.cdte_format
!= CDROM_MSF
)
1547 return copy_to_user(arg
, &entry
, sizeof entry
) ? -EFAULT
: 0;
1551 static int cdromvolctrl(void __user
*arg
)
1554 struct cdrom_volctrl volctrl
;
1555 struct cdrom_msf msf
;
1557 if (copy_from_user(&volctrl
, arg
, sizeof volctrl
))
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
;
1567 status
= exec_long_cmd(COMCHCTRL
, &msf
);
1569 DEBUG((DEBUG_VFS
, "exec_long_cmd COMCHCTRL: %02x", -status
));
1576 static int cdromsubchnl(void __user
*arg
)
1579 struct cdrom_subchnl subchnl
;
1581 if (copy_from_user(&subchnl
, arg
, sizeof subchnl
))
1584 if (subchnl
.cdsc_format
!= CDROM_LBA
1585 && subchnl
.cdsc_format
!= CDROM_MSF
)
1588 status
= get_q_channel(&subchnl
);
1590 DEBUG((DEBUG_VFS
, "get_q_channel: %02x", -status
));
1594 if (copy_to_user(arg
, &subchnl
, sizeof subchnl
))
1600 static struct gendisk
*optcd_disk
;
1603 static int cdromread(void __user
*arg
, int blocksize
, int cmd
)
1606 struct cdrom_msf msf
;
1608 if (copy_from_user(&msf
, arg
, sizeof msf
))
1614 msf
.cdmsf_frame1
= 1; /* read only one frame */
1615 status
= exec_read_cmd(cmd
, &msf
);
1617 DEBUG((DEBUG_VFS
, "read cmd status 0x%x", status
));
1619 if (!sleep_flag_low(FL_DTEN
, SLEEP_TIMEOUT
))
1622 fetch_data(optcd_disk
->private_data
, blocksize
);
1624 if (copy_to_user(arg
, optcd_disk
->private_data
, blocksize
))
1631 static int cdromseek(void __user
*arg
)
1634 struct cdrom_msf msf
;
1636 if (copy_from_user(&msf
, arg
, sizeof msf
))
1640 status
= exec_seek_cmd(COMSEEK
, &msf
);
1642 DEBUG((DEBUG_VFS
, "COMSEEK status 0x%x", status
));
1651 static int cdrommultisession(void __user
*arg
)
1653 struct cdrom_multisession ms
;
1655 if (copy_from_user(&ms
, arg
, sizeof ms
))
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
;
1662 if (ms
.addr_format
!= CDROM_LBA
1663 && ms
.addr_format
!= CDROM_MSF
)
1665 if (ms
.addr_format
== CDROM_LBA
)
1668 ms
.xa_flag
= disk_info
.xa
;
1670 if (copy_to_user(arg
, &ms
, sizeof(struct cdrom_multisession
)))
1674 if (ms
.addr_format
== CDROM_MSF
)
1676 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1683 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1686 disk_info
.last_session
.minute
,
1687 disk_info
.last_session
.second
,
1688 disk_info
.last_session
.frame
);
1689 #endif /* DEBUG_MULTIS */
1693 #endif /* MULTISESSION */
1696 static int cdromreset(void)
1698 if (state
!= S_IDLE
) {
1705 opt_invalidate_buffers();
1706 audio_status
= CDROM_AUDIO_NO_STATUS
;
1716 static int opt_ioctl(struct inode
*ip
, struct file
*fp
,
1717 unsigned int cmd
, unsigned long arg
)
1719 int status
, err
, retval
= 0;
1720 void __user
*argp
= (void __user
*)arg
;
1722 DEBUG((DEBUG_VFS
, "starting opt_ioctl"));
1727 if (cmd
== CDROMRESET
)
1728 return cdromreset();
1730 /* is do_optcd_request or another ioctl busy? */
1731 if (state
!= S_IDLE
|| in_vfs
)
1736 status
= drive_status();
1738 DEBUG((DEBUG_VFS
, "drive_status: %02x", -status
));
1743 if (status
& ST_DOOR_OPEN
)
1744 switch (cmd
) { /* Actions that can be taken with door open */
1745 case CDROMCLOSETRAY
:
1746 /* We do this before trying to read the toc. */
1747 err
= exec_cmd(COMCLOSE
);
1750 "exec_cmd COMCLOSE: %02x", -err
));
1755 default: in_vfs
= 0;
1761 DEBUG((DEBUG_VFS
, "update_toc: %02x", -err
));
1766 DEBUG((DEBUG_VFS
, "ioctl cmd 0x%x", 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;
1776 case CDROMSTOP
: err
= exec_cmd(COMSTOP
);
1779 "exec_cmd COMSTOP: %02x",
1783 audio_status
= CDROM_AUDIO_NO_STATUS
;
1785 case CDROMSTART
: break; /* This is a no-op */
1786 case CDROMEJECT
: err
= exec_cmd(COMUNLOCK
);
1789 "exec_cmd COMUNLOCK: %02x",
1794 err
= exec_cmd(COMOPEN
);
1797 "exec_cmd COMOPEN: %02x",
1803 case CDROMVOLCTRL
: retval
= cdromvolctrl(argp
); break;
1804 case CDROMSUBCHNL
: retval
= cdromsubchnl(argp
); break;
1806 /* The drive detects the mode and automatically delivers the
1807 correct 2048 bytes, so we don't need these IOCTLs */
1808 case CDROMREADMODE2
: retval
= -EINVAL
; break;
1809 case CDROMREADMODE1
: retval
= -EINVAL
; break;
1811 /* Drive doesn't support reading audio */
1812 case CDROMREADAUDIO
: retval
= -EINVAL
; break;
1814 case CDROMEJECT_SW
: auto_eject
= (char) arg
;
1818 case CDROMMULTISESSION
: retval
= cdrommultisession(argp
); break;
1821 case CDROM_GET_MCN
: retval
= -EINVAL
; break; /* not implemented */
1822 case CDROMVOLREAD
: retval
= -EINVAL
; break; /* not implemented */
1825 /* this drive delivers 2340 bytes in raw mode */
1826 retval
= cdromread(argp
, CD_FRAMESIZE_RAW1
, COMREADRAW
);
1828 case CDROMREADCOOKED
:
1829 retval
= cdromread(argp
, CD_FRAMESIZE
, COMREAD
);
1832 retval
= cdromread(argp
, CD_FRAMESIZE_RAWER
, COMREADALL
);
1835 case CDROMSEEK
: retval
= cdromseek(argp
); break;
1836 case CDROMPLAYBLK
: retval
= -EINVAL
; break; /* not implemented */
1837 case CDROMCLOSETRAY
: break; /* The action was taken earlier */
1838 default: retval
= -EINVAL
;
1845 static int open_count
= 0;
1847 /* Open device special file; check that a disk is in. */
1848 static int opt_open(struct inode
*ip
, struct file
*fp
)
1850 DEBUG((DEBUG_VFS
, "starting opt_open"));
1852 if (!open_count
&& state
== S_IDLE
) {
1856 buf
= kmalloc(CD_FRAMESIZE_RAWER
, GFP_KERNEL
);
1858 printk(KERN_INFO
"optcd: cannot allocate read buffer\n");
1861 optcd_disk
->private_data
= buf
; /* save read buffer */
1864 opt_invalidate_buffers();
1866 status
= exec_cmd(COMCLOSE
); /* close door */
1868 DEBUG((DEBUG_VFS
, "exec_cmd COMCLOSE: %02x", -status
));
1871 status
= drive_status();
1873 DEBUG((DEBUG_VFS
, "drive_status: %02x", -status
));
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");
1881 status
= exec_cmd(COMLOCK
); /* Lock door */
1883 DEBUG((DEBUG_VFS
, "exec_cmd COMLOCK: %02x", -status
));
1885 status
= update_toc(); /* Read table of contents */
1887 DEBUG((DEBUG_VFS
, "update_toc: %02x", -status
));
1888 status
= exec_cmd(COMUNLOCK
); /* Unlock door */
1891 "exec_cmd COMUNLOCK: %02x", -status
));
1898 DEBUG((DEBUG_VFS
, "exiting opt_open"));
1907 /* Release device special file; flush all blocks from the buffer cache */
1908 static int opt_release(struct inode
*ip
, struct file
*fp
)
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
));
1916 if (!--open_count
) {
1918 opt_invalidate_buffers();
1919 status
= exec_cmd(COMUNLOCK
); /* Unlock door */
1921 DEBUG((DEBUG_VFS
, "exec_cmd COMUNLOCK: %02x", -status
));
1924 status
= exec_cmd(COMOPEN
);
1925 DEBUG((DEBUG_VFS
, "exec_cmd COMOPEN: %02x", -status
));
1927 kfree(optcd_disk
->private_data
);
1928 del_timer(&delay_timer
);
1929 del_timer(&req_timer
);
1935 /* Check if disk has been changed */
1936 static int opt_media_change(struct gendisk
*disk
)
1938 DEBUG((DEBUG_VFS
, "executing opt_media_change"));
1939 DEBUG((DEBUG_VFS
, "dev: %s; disk_changed = %d\n",
1940 disk
->disk_name
, disk_changed
));
1949 /* Driver initialisation */
1952 /* Returns 1 if a drive is detected with a version string
1953 starting with "DOLPHIN". Otherwise 0. */
1954 static int __init
version_ok(void)
1957 int count
, i
, ch
, status
;
1959 status
= exec_cmd(COMVERSION
);
1961 DEBUG((DEBUG_VFS
, "exec_cmd COMVERSION: %02x", -status
));
1964 if ((count
= get_data(1)) < 0) {
1965 DEBUG((DEBUG_VFS
, "get_data(1): %02x", -count
));
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
));
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'));
1991 static struct block_device_operations opt_fops
= {
1992 .owner
= THIS_MODULE
,
1994 .release
= opt_release
,
1996 .media_changed
= opt_media_change
,
2000 /* Get kernel parameter when used as a kernel driver */
2001 static int optcd_setup(char *str
)
2004 (void)get_options(str
, ARRAY_SIZE(ints
), ints
);
2007 optcd_port
= ints
[1];
2012 __setup("optcd=", optcd_setup
);
2016 /* Test for presence of drive and initialize it. Called at boot time
2017 or during module initialisation. */
2018 static int __init
optcd_init(void)
2022 if (optcd_port
<= 0) {
2024 "optcd: no Optics Storage CDROM Initialization\n");
2027 optcd_disk
= alloc_disk(1);
2029 printk(KERN_ERR
"optcd: can't allocate disk\n");
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");
2037 if (!request_region(optcd_port
, 4, "optcd")) {
2038 printk(KERN_ERR
"optcd: conflict, I/O port 0x%x already used\n",
2040 put_disk(optcd_disk
);
2044 if (!reset_drive()) {
2045 printk(KERN_ERR
"optcd: drive at 0x%x not ready\n", optcd_port
);
2046 release_region(optcd_port
, 4);
2047 put_disk(optcd_disk
);
2050 if (!version_ok()) {
2051 printk(KERN_ERR
"optcd: unknown drive detected; aborting\n");
2052 release_region(optcd_port
, 4);
2053 put_disk(optcd_disk
);
2056 status
= exec_cmd(COMINITDOUBLE
);
2058 printk(KERN_ERR
"optcd: cannot init double speed mode\n");
2059 release_region(optcd_port
, 4);
2060 DEBUG((DEBUG_VFS
, "exec_cmd COMINITDOUBLE: %02x", -status
));
2061 put_disk(optcd_disk
);
2064 if (register_blkdev(MAJOR_NR
, "optcd")) {
2065 release_region(optcd_port
, 4);
2066 put_disk(optcd_disk
);
2071 opt_queue
= blk_init_queue(do_optcd_request
, &optcd_lock
);
2073 unregister_blkdev(MAJOR_NR
, "optcd");
2074 release_region(optcd_port
, 4);
2075 put_disk(optcd_disk
);
2079 blk_queue_hardsect_size(opt_queue
, 2048);
2080 optcd_disk
->queue
= opt_queue
;
2081 add_disk(optcd_disk
);
2083 printk(KERN_INFO
"optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port
);
2088 static void __exit
optcd_exit(void)
2090 del_gendisk(optcd_disk
);
2091 put_disk(optcd_disk
);
2092 if (unregister_blkdev(MAJOR_NR
, "optcd") == -EINVAL
) {
2093 printk(KERN_ERR
"optcd: what's that: can't unregister\n");
2096 blk_cleanup_queue(opt_queue
);
2097 release_region(optcd_port
, 4);
2098 printk(KERN_INFO
"optcd: module released.\n");
2101 module_init(optcd_init
);
2102 module_exit(optcd_exit
);
2104 MODULE_LICENSE("GPL");
2105 MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR
);