Import 2.1.118
[davej-history.git] / drivers / cdrom / optcd.c
blob76103945be2e2ec047fa296a12507a2236837055
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)
13 any later version.
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.
25 /* Revision history
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 \
34 bs=2048 count=4096".
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
43 has its own major nr.
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
50 inclusion in 1.3.21
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.
62 /* Includes */
65 #include <linux/module.h>
66 #include <linux/mm.h>
67 #include <linux/ioport.h>
68 #include <linux/init.h>
69 #include <asm/io.h>
71 #define MAJOR_NR OPTICS_CDROM_MAJOR
72 #include <linux/blk.h>
74 #include <linux/cdrom.h>
75 #include "optcd.h"
77 #include <asm/uaccess.h>
80 /* Debug support */
83 /* Don't forget to add new debug flags here. */
84 #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
85 DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
86 #define DEBUG(x) debug x
87 static void debug(int debug_this, const char* fmt, ...)
89 char s[1024];
90 va_list args;
92 if (!debug_this)
93 return;
95 va_start(args, fmt);
96 vsprintf(s, fmt, args);
97 printk(KERN_DEBUG "optcd: %s\n", s);
98 va_end(args);
100 #else
101 #define DEBUG(x)
102 #endif
104 /* Drive hardware/firmware characteristics
105 Identifiers in accordance with Optics Storage documentation */
108 #define optcd_port optcd /* Needed for the modutils. */
109 static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */
110 MODULE_PARM(optcd_port, "h");
111 /* Drive registers, read */
112 #define DATA_PORT optcd_port /* Read data/status */
113 #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */
115 /* Drive registers, write */
116 #define COMIN_PORT optcd_port /* For passing command/parameter */
117 #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */
118 #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */
121 /* Command completion/status read from DATA register */
122 #define ST_DRVERR 0x80
123 #define ST_DOOR_OPEN 0x40
124 #define ST_MIXEDMODE_DISK 0x20
125 #define ST_MODE_BITS 0x1c
126 #define ST_M_STOP 0x00
127 #define ST_M_READ 0x04
128 #define ST_M_AUDIO 0x04
129 #define ST_M_PAUSE 0x08
130 #define ST_M_INITIAL 0x0c
131 #define ST_M_ERROR 0x10
132 #define ST_M_OTHERS 0x14
133 #define ST_MODE2TRACK 0x02
134 #define ST_DSK_CHG 0x01
135 #define ST_L_LOCK 0x01
136 #define ST_CMD_OK 0x00
137 #define ST_OP_OK 0x01
138 #define ST_PA_OK 0x02
139 #define ST_OP_ERROR 0x05
140 #define ST_PA_ERROR 0x06
143 /* Error codes (appear as command completion code from DATA register) */
144 /* Player related errors */
145 #define ERR_ILLCMD 0x11 /* Illegal command to player module */
146 #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */
147 #define ERR_SLEDGE 0x13
148 #define ERR_FOCUS 0x14
149 #define ERR_MOTOR 0x15
150 #define ERR_RADIAL 0x16
151 #define ERR_PLL 0x17 /* PLL lock error */
152 #define ERR_SUB_TIM 0x18 /* Subcode timeout error */
153 #define ERR_SUB_NF 0x19 /* Subcode not found error */
154 #define ERR_TRAY 0x1a
155 #define ERR_TOC 0x1b /* Table of Contents read error */
156 #define ERR_JUMP 0x1c
157 /* Data errors */
158 #define ERR_MODE 0x21
159 #define ERR_FORM 0x22
160 #define ERR_HEADADDR 0x23 /* Header Address not found */
161 #define ERR_CRC 0x24
162 #define ERR_ECC 0x25 /* Uncorrectable ECC error */
163 #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */
164 #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */
165 #define ERR_VDST 0x28 /* VDST not found */
166 /* Timeout errors */
167 #define ERR_READ_TIM 0x31 /* Read timeout error */
168 #define ERR_DEC_STP 0x32 /* Decoder stopped */
169 #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */
170 /* Function abort codes */
171 #define ERR_KEY 0x41 /* Key -Detected abort */
172 #define ERR_READ_FINISH 0x42 /* Read Finish */
173 /* Second Byte diagnostic codes */
174 #define ERR_NOBSYNC 0x01 /* No block sync */
175 #define ERR_SHORTB 0x02 /* Short block */
176 #define ERR_LONGB 0x03 /* Long block */
177 #define ERR_SHORTDSP 0x04 /* Short DSP word */
178 #define ERR_LONGDSP 0x05 /* Long DSP word */
181 /* Status availability flags read from STATUS register */
182 #define FL_EJECT 0x20
183 #define FL_WAIT 0x10 /* active low */
184 #define FL_EOP 0x08 /* active low */
185 #define FL_STEN 0x04 /* Status available when low */
186 #define FL_DTEN 0x02 /* Data available when low */
187 #define FL_DRQ 0x01 /* active low */
188 #define FL_RESET 0xde /* These bits are high after a reset */
189 #define FL_STDT (FL_STEN|FL_DTEN)
192 /* Transfer mode, written to HCON register */
193 #define HCON_DTS 0x08
194 #define HCON_SDRQB 0x04
195 #define HCON_LOHI 0x02
196 #define HCON_DMA16 0x01
199 /* Drive command set, written to COMIN register */
200 /* Quick response commands */
201 #define COMDRVST 0x20 /* Drive Status Read */
202 #define COMERRST 0x21 /* Error Status Read */
203 #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */
204 #define COMINITSINGLE 0x28 /* Initialize Single Speed */
205 #define COMINITDOUBLE 0x29 /* Initialize Double Speed */
206 #define COMUNLOCK 0x30 /* Unlock */
207 #define COMLOCK 0x31 /* Lock */
208 #define COMLOCKST 0x32 /* Lock/Unlock Status */
209 #define COMVERSION 0x40 /* Get Firmware Revision */
210 #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */
211 /* Read commands */
212 #define COMFETCH 0x60 /* Prefetch Data */
213 #define COMREAD 0x61 /* Read */
214 #define COMREADRAW 0x62 /* Read Raw Data */
215 #define COMREADALL 0x63 /* Read All 2646 Bytes */
216 /* Player control commands */
217 #define COMLEADIN 0x70 /* Seek To Lead-in */
218 #define COMSEEK 0x71 /* Seek */
219 #define COMPAUSEON 0x80 /* Pause On */
220 #define COMPAUSEOFF 0x81 /* Pause Off */
221 #define COMSTOP 0x82 /* Stop */
222 #define COMOPEN 0x90 /* Open Tray Door */
223 #define COMCLOSE 0x91 /* Close Tray Door */
224 #define COMPLAY 0xa0 /* Audio Play */
225 #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */
226 #define COMSUBQ 0xb0 /* Read Sub-q Code */
227 #define COMLOCATION 0xb1 /* Read Head Position */
228 /* Audio control commands */
229 #define COMCHCTRL 0xc0 /* Audio Channel Control */
230 /* Miscellaneous (test) commands */
231 #define COMDRVTEST 0xd0 /* Write Test Bytes */
232 #define COMTEST 0xd1 /* Diagnostic Test */
234 /* Low level drive interface. Only here we do actual I/O
235 Waiting for status / data available */
238 /* Busy wait until FLAG goes low. Return 0 on timeout. */
239 inline static int flag_low(int flag, unsigned long timeout)
241 int flag_high;
242 unsigned long count = 0;
244 while ((flag_high = (inb(STATUS_PORT) & flag)))
245 if (++count >= timeout)
246 break;
248 DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
249 flag, count, flag_high ? " timeout" : ""));
250 return !flag_high;
254 /* Timed waiting for status or data */
255 static int sleep_timeout; /* max # of ticks to sleep */
256 static struct wait_queue *waitq = NULL;
257 static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
259 #define SET_TIMER(func, jifs) \
260 delay_timer.expires = jiffies+(jifs); \
261 delay_timer.function = (void *) (func); \
262 add_timer(&delay_timer);
263 #define CLEAR_TIMER del_timer(&delay_timer)
266 /* Timer routine: wake up when desired flag goes low,
267 or when timeout expires. */
268 static void sleep_timer(void)
270 int flags = inb(STATUS_PORT) & FL_STDT;
272 if (flags == FL_STDT && --sleep_timeout > 0) {
273 SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */
274 } else
275 wake_up(&waitq);
279 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
280 static int sleep_flag_low(int flag, unsigned long timeout)
282 int flag_high;
284 DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
286 sleep_timeout = timeout;
287 flag_high = inb(STATUS_PORT) & flag;
288 if (flag_high && sleep_timeout > 0) {
289 SET_TIMER(sleep_timer, HZ/100);
290 sleep_on(&waitq);
291 flag_high = inb(STATUS_PORT) & flag;
294 DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
295 flag, timeout, flag_high ? " timeout" : ""));
296 return !flag_high;
299 /* Low level drive interface. Only here we do actual I/O
300 Sending commands and parameters */
303 /* Errors in the command protocol */
304 #define ERR_IF_CMD_TIMEOUT 0x100
305 #define ERR_IF_ERR_TIMEOUT 0x101
306 #define ERR_IF_RESP_TIMEOUT 0x102
307 #define ERR_IF_DATA_TIMEOUT 0x103
308 #define ERR_IF_NOSTAT 0x104
311 /* Send command code. Return <0 indicates error */
312 static int send_cmd(int cmd)
314 unsigned char ack;
316 DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
318 outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */
319 outb(cmd, COMIN_PORT); /* Send command code */
320 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
321 return -ERR_IF_CMD_TIMEOUT;
322 ack = inb(DATA_PORT); /* read command acknowledge */
323 outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
324 return ack==ST_OP_OK ? 0 : -ack;
328 /* Send command parameters. Return <0 indicates error */
329 static int send_params(struct cdrom_msf *params)
331 unsigned char ack;
333 DEBUG((DEBUG_DRIVE_IF, "sending parameters"
334 " %02x:%02x:%02x"
335 " %02x:%02x:%02x",
336 params->cdmsf_min0,
337 params->cdmsf_sec0,
338 params->cdmsf_frame0,
339 params->cdmsf_min1,
340 params->cdmsf_sec1,
341 params->cdmsf_frame1));
343 outb(params->cdmsf_min0, COMIN_PORT);
344 outb(params->cdmsf_sec0, COMIN_PORT);
345 outb(params->cdmsf_frame0, COMIN_PORT);
346 outb(params->cdmsf_min1, COMIN_PORT);
347 outb(params->cdmsf_sec1, COMIN_PORT);
348 outb(params->cdmsf_frame1, COMIN_PORT);
349 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
350 return -ERR_IF_CMD_TIMEOUT;
351 ack = inb(DATA_PORT); /* read command acknowledge */
352 return ack==ST_PA_OK ? 0 : -ack;
356 /* Send parameters for SEEK command. Return <0 indicates error */
357 static int send_seek_params(struct cdrom_msf *params)
359 unsigned char ack;
361 DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
362 " %02x:%02x:%02x",
363 params->cdmsf_min0,
364 params->cdmsf_sec0,
365 params->cdmsf_frame0));
367 outb(params->cdmsf_min0, COMIN_PORT);
368 outb(params->cdmsf_sec0, COMIN_PORT);
369 outb(params->cdmsf_frame0, COMIN_PORT);
370 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
371 return -ERR_IF_CMD_TIMEOUT;
372 ack = inb(DATA_PORT); /* read command acknowledge */
373 return ack==ST_PA_OK ? 0 : -ack;
377 /* Wait for command execution status. Choice between busy waiting
378 and sleeping. Return value <0 indicates timeout. */
379 inline static int get_exec_status(int busy_waiting)
381 unsigned char exec_status;
383 if (busy_waiting
384 ? !flag_low(FL_STEN, BUSY_TIMEOUT)
385 : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
386 return -ERR_IF_CMD_TIMEOUT;
388 exec_status = inb(DATA_PORT);
389 DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
390 return exec_status;
394 /* Wait busy for extra byte of data that a command returns.
395 Return value <0 indicates timeout. */
396 inline static int get_data(int short_timeout)
398 unsigned char data;
400 if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
401 return -ERR_IF_DATA_TIMEOUT;
403 data = inb(DATA_PORT);
404 DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
405 return data;
409 /* Returns 0 if failed */
410 static int reset_drive(void)
412 unsigned long count = 0;
413 int flags;
415 DEBUG((DEBUG_DRIVE_IF, "reset drive"));
417 outb(0, RESET_PORT);
418 while (++count < RESET_WAIT)
419 inb(DATA_PORT);
421 count = 0;
422 while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
423 if (++count >= BUSY_TIMEOUT)
424 break;
426 DEBUG((DEBUG_DRIVE_IF, "reset %s",
427 flags == FL_RESET ? "succeeded" : "failed"));
429 if (flags != FL_RESET)
430 return 0; /* Reset failed */
431 outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
432 return 1; /* Reset succeeded */
436 /* Facilities for asynchronous operation */
438 /* Read status/data availability flags FL_STEN and FL_DTEN */
439 inline static int stdt_flags(void)
441 return inb(STATUS_PORT) & FL_STDT;
445 /* Fetch status that has previously been waited for. <0 means not available */
446 inline static int fetch_status(void)
448 unsigned char status;
450 if (inb(STATUS_PORT) & FL_STEN)
451 return -ERR_IF_NOSTAT;
453 status = inb(DATA_PORT);
454 DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
455 return status;
459 /* Fetch data that has previously been waited for. */
460 inline static void fetch_data(char *buf, int n)
462 insb(DATA_PORT, buf, n);
463 DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
467 /* Flush status and data fifos */
468 inline static void flush_data(void)
470 while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
471 inb(DATA_PORT);
472 DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
475 /* Command protocol */
478 /* Send a simple command and wait for response. Command codes < COMFETCH
479 are quick response commands */
480 inline static int exec_cmd(int cmd)
482 int ack = send_cmd(cmd);
483 if (ack < 0)
484 return ack;
485 return get_exec_status(cmd < COMFETCH);
489 /* Send a command with parameters. Don't wait for the response,
490 * which consists of data blocks read from the CD. */
491 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
493 int ack = send_cmd(cmd);
494 if (ack < 0)
495 return ack;
496 return send_params(params);
500 /* Send a seek command with parameters and wait for response */
501 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
503 int ack = send_cmd(cmd);
504 if (ack < 0)
505 return ack;
506 ack = send_seek_params(params);
507 if (ack < 0)
508 return ack;
509 return 0;
513 /* Send a command with parameters and wait for response */
514 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
516 int ack = exec_read_cmd(cmd, params);
517 if (ack < 0)
518 return ack;
519 return get_exec_status(0);
522 /* Address conversion routines */
525 /* Binary to BCD (2 digits) */
526 inline static void single_bin2bcd(u_char *p)
528 DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
529 *p = (*p % 10) | ((*p / 10) << 4);
533 /* Convert entire msf struct */
534 static void bin2bcd(struct cdrom_msf *msf)
536 single_bin2bcd(&msf->cdmsf_min0);
537 single_bin2bcd(&msf->cdmsf_sec0);
538 single_bin2bcd(&msf->cdmsf_frame0);
539 single_bin2bcd(&msf->cdmsf_min1);
540 single_bin2bcd(&msf->cdmsf_sec1);
541 single_bin2bcd(&msf->cdmsf_frame1);
545 /* Linear block address to minute, second, frame form */
546 #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */
548 static void lba2msf(int lba, struct cdrom_msf *msf)
550 DEBUG((DEBUG_CONV, "lba2msf %d", lba));
551 lba += CD_MSF_OFFSET;
552 msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
553 msf->cdmsf_sec0 = lba / CD_FRAMES;
554 msf->cdmsf_frame0 = lba % CD_FRAMES;
555 msf->cdmsf_min1 = 0;
556 msf->cdmsf_sec1 = 0;
557 msf->cdmsf_frame1 = 0;
558 bin2bcd(msf);
562 /* Two BCD digits to binary */
563 inline static u_char bcd2bin(u_char bcd)
565 DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
566 return (bcd >> 4) * 10 + (bcd & 0x0f);
570 static void msf2lba(union cdrom_addr *addr)
572 addr->lba = addr->msf.minute * CD_FPM
573 + addr->msf.second * CD_FRAMES
574 + addr->msf.frame - CD_MSF_OFFSET;
578 /* Minute, second, frame address BCD to binary or to linear address,
579 depending on MODE */
580 static void msf_bcd2bin(union cdrom_addr *addr)
582 addr->msf.minute = bcd2bin(addr->msf.minute);
583 addr->msf.second = bcd2bin(addr->msf.second);
584 addr->msf.frame = bcd2bin(addr->msf.frame);
587 /* High level drive commands */
590 static int audio_status = CDROM_AUDIO_NO_STATUS;
591 static char toc_uptodate = 0;
592 static char disk_changed = 1;
594 /* Get drive status, flagging completion of audio play and disk changes. */
595 static int drive_status(void)
597 int status;
599 status = exec_cmd(COMIOCTLISTAT);
600 DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
601 if (status < 0)
602 return status;
603 if (status == 0xff) /* No status available */
604 return -ERR_IF_NOSTAT;
606 if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
607 (audio_status == CDROM_AUDIO_PLAY)) {
608 audio_status = CDROM_AUDIO_COMPLETED;
611 if (status & ST_DSK_CHG) {
612 toc_uptodate = 0;
613 disk_changed = 1;
614 audio_status = CDROM_AUDIO_NO_STATUS;
617 return status;
621 /* Read the current Q-channel info. Also used for reading the
622 table of contents. qp->cdsc_format must be set on entry to
623 indicate the desired address format */
624 static int get_q_channel(struct cdrom_subchnl *qp)
626 int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
628 status = drive_status();
629 if (status < 0)
630 return status;
631 qp->cdsc_audiostatus = audio_status;
633 status = exec_cmd(COMSUBQ);
634 if (status < 0)
635 return status;
637 d1 = get_data(0);
638 if (d1 < 0)
639 return d1;
640 qp->cdsc_adr = d1;
641 qp->cdsc_ctrl = d1 >> 4;
643 d2 = get_data(0);
644 if (d2 < 0)
645 return d2;
646 qp->cdsc_trk = bcd2bin(d2);
648 d3 = get_data(0);
649 if (d3 < 0)
650 return d3;
651 qp->cdsc_ind = bcd2bin(d3);
653 d4 = get_data(0);
654 if (d4 < 0)
655 return d4;
656 qp->cdsc_reladdr.msf.minute = d4;
658 d5 = get_data(0);
659 if (d5 < 0)
660 return d5;
661 qp->cdsc_reladdr.msf.second = d5;
663 d6 = get_data(0);
664 if (d6 < 0)
665 return d6;
666 qp->cdsc_reladdr.msf.frame = d6;
668 d7 = get_data(0);
669 if (d7 < 0)
670 return d7;
671 /* byte not used */
673 d8 = get_data(0);
674 if (d8 < 0)
675 return d8;
676 qp->cdsc_absaddr.msf.minute = d8;
678 d9 = get_data(0);
679 if (d9 < 0)
680 return d9;
681 qp->cdsc_absaddr.msf.second = d9;
683 d10 = get_data(0);
684 if (d10 < 0)
685 return d10;
686 qp->cdsc_absaddr.msf.frame = d10;
688 DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
689 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
691 msf_bcd2bin(&qp->cdsc_absaddr);
692 msf_bcd2bin(&qp->cdsc_reladdr);
693 if (qp->cdsc_format == CDROM_LBA) {
694 msf2lba(&qp->cdsc_absaddr);
695 msf2lba(&qp->cdsc_reladdr);
698 return 0;
701 /* Table of contents handling */
704 /* Errors in table of contents */
705 #define ERR_TOC_MISSINGINFO 0x120
706 #define ERR_TOC_MISSINGENTRY 0x121
709 struct cdrom_disk_info {
710 unsigned char first;
711 unsigned char last;
712 struct cdrom_msf0 disk_length;
713 struct cdrom_msf0 first_track;
714 /* Multisession info: */
715 unsigned char next;
716 struct cdrom_msf0 next_session;
717 struct cdrom_msf0 last_session;
718 unsigned char multi;
719 unsigned char xa;
720 unsigned char audio;
722 static struct cdrom_disk_info disk_info;
724 #define MAX_TRACKS 111
725 static struct cdrom_subchnl toc[MAX_TRACKS];
727 #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */
728 #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */
729 #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */
730 #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */
732 #define I_FIRSTTRACK 0x01
733 #define I_LASTTRACK 0x02
734 #define I_DISKLENGTH 0x04
735 #define I_NEXTSESSION 0x08
736 #define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
739 #if DEBUG_TOC
740 void toc_debug_info(int i)
742 printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
743 " %2d:%02d.%02d %2d:%02d.%02d\n",
744 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
745 toc[i].cdsc_trk, toc[i].cdsc_ind,
746 toc[i].cdsc_reladdr.msf.minute,
747 toc[i].cdsc_reladdr.msf.second,
748 toc[i].cdsc_reladdr.msf.frame,
749 toc[i].cdsc_absaddr.msf.minute,
750 toc[i].cdsc_absaddr.msf.second,
751 toc[i].cdsc_absaddr.msf.frame);
753 #endif
756 static int read_toc(void)
758 int status, limit, count;
759 unsigned char got_info = 0;
760 struct cdrom_subchnl q_info;
761 #if DEBUG_TOC
762 int i;
763 #endif
765 DEBUG((DEBUG_TOC, "starting read_toc"));
767 count = 0;
768 for (limit = 60; limit > 0; limit--) {
769 int index;
771 q_info.cdsc_format = CDROM_MSF;
772 status = get_q_channel(&q_info);
773 if (status < 0)
774 return status;
776 index = q_info.cdsc_ind;
777 if (index > 0 && index < MAX_TRACKS
778 && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
779 toc[index] = q_info;
780 DEBUG((DEBUG_TOC, "got %d", index));
781 if (index < 100)
782 count++;
784 switch (q_info.cdsc_ind) {
785 case QINFO_FIRSTTRACK:
786 got_info |= I_FIRSTTRACK;
787 break;
788 case QINFO_LASTTRACK:
789 got_info |= I_LASTTRACK;
790 break;
791 case QINFO_DISKLENGTH:
792 got_info |= I_DISKLENGTH;
793 break;
794 case QINFO_NEXTSESSION:
795 got_info |= I_NEXTSESSION;
796 break;
800 if ((got_info & I_ALL) == I_ALL
801 && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
802 >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
803 break;
806 /* Construct disk_info from TOC */
807 if (disk_info.first == 0) {
808 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
809 disk_info.first_track.minute =
810 toc[disk_info.first].cdsc_absaddr.msf.minute;
811 disk_info.first_track.second =
812 toc[disk_info.first].cdsc_absaddr.msf.second;
813 disk_info.first_track.frame =
814 toc[disk_info.first].cdsc_absaddr.msf.frame;
816 disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
817 disk_info.disk_length.minute =
818 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
819 disk_info.disk_length.second =
820 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
821 disk_info.disk_length.frame =
822 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
823 disk_info.next_session.minute =
824 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
825 disk_info.next_session.second =
826 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
827 disk_info.next_session.frame =
828 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
829 disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
830 disk_info.last_session.minute =
831 toc[disk_info.next].cdsc_absaddr.msf.minute;
832 disk_info.last_session.second =
833 toc[disk_info.next].cdsc_absaddr.msf.second;
834 disk_info.last_session.frame =
835 toc[disk_info.next].cdsc_absaddr.msf.frame;
836 toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
837 disk_info.disk_length.minute;
838 toc[disk_info.last + 1].cdsc_absaddr.msf.second =
839 disk_info.disk_length.second;
840 toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
841 disk_info.disk_length.frame;
842 #if DEBUG_TOC
843 for (i = 1; i <= disk_info.last + 1; i++)
844 toc_debug_info(i);
845 toc_debug_info(QINFO_FIRSTTRACK);
846 toc_debug_info(QINFO_LASTTRACK);
847 toc_debug_info(QINFO_DISKLENGTH);
848 toc_debug_info(QINFO_NEXTSESSION);
849 #endif
851 DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
852 got_info, count));
853 if ((got_info & I_ALL) != I_ALL
854 || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
855 < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
856 return -ERR_TOC_MISSINGINFO;
857 return 0;
861 #ifdef MULTISESSION
862 static int get_multi_disk_info(void)
864 int sessions, status;
865 struct cdrom_msf multi_index;
868 for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
869 int count;
871 for (count = 100; count < MAX_TRACKS; count++)
872 toc[count].cdsc_ind = 0;
874 multi_index.cdmsf_min0 = disk_info.next_session.minute;
875 multi_index.cdmsf_sec0 = disk_info.next_session.second;
876 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
877 if (multi_index.cdmsf_sec0 >= 20)
878 multi_index.cdmsf_sec0 -= 20;
879 else {
880 multi_index.cdmsf_sec0 += 40;
881 multi_index.cdmsf_min0--;
883 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
884 multi_index.cdmsf_min0,
885 multi_index.cdmsf_sec0,
886 multi_index.cdmsf_frame0));
887 bin2bcd(&multi_index);
888 multi_index.cdmsf_min1 = 0;
889 multi_index.cdmsf_sec1 = 0;
890 multi_index.cdmsf_frame1 = 1;
892 status = exec_read_cmd(COMREAD, &multi_index);
893 if (status < 0) {
894 DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
895 -status));
896 break;
898 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
899 0 : -ERR_TOC_MISSINGINFO;
900 flush_data();
901 if (status < 0) {
902 DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
903 break;
906 status = read_toc();
907 if (status < 0) {
908 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
909 break;
912 disk_info.multi = 1;
915 exec_cmd(COMSTOP);
917 if (status < 0)
918 return -EIO;
919 return 0;
921 #endif MULTISESSION
924 static int update_toc(void)
926 int status, count;
928 if (toc_uptodate)
929 return 0;
931 DEBUG((DEBUG_TOC, "starting update_toc"));
933 disk_info.first = 0;
934 for (count = 0; count < MAX_TRACKS; count++)
935 toc[count].cdsc_ind = 0;
937 status = exec_cmd(COMLEADIN);
938 if (status < 0)
939 return -EIO;
941 status = read_toc();
942 if (status < 0) {
943 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
944 return -EIO;
947 /* Audio disk detection. Look at first track. */
948 disk_info.audio =
949 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
951 /* XA detection */
952 disk_info.xa = drive_status() & ST_MODE2TRACK;
954 /* Multisession detection: if we want this, define MULTISESSION */
955 disk_info.multi = 0;
956 #ifdef MULTISESSION
957 if (disk_info.xa)
958 get_multi_disk_info(); /* Here disk_info.multi is set */
959 #endif MULTISESSION
960 if (disk_info.multi)
961 printk(KERN_WARNING "optcd: Multisession support experimental, "
962 "see linux/Documentation/cdrom/optcd\n");
964 DEBUG((DEBUG_TOC, "exiting update_toc"));
966 toc_uptodate = 1;
967 return 0;
970 /* Request handling */
973 #define CURRENT_VALID \
974 (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
975 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
978 /* Buffers for block size conversion. */
979 #define NOBUF -1
981 static char buf[CD_FRAMESIZE * N_BUFS];
982 static volatile int buf_bn[N_BUFS], next_bn;
983 static volatile int buf_in = 0, buf_out = NOBUF;
985 inline static void opt_invalidate_buffers(void)
987 int i;
989 DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
991 for (i = 0; i < N_BUFS; i++)
992 buf_bn[i] = NOBUF;
993 buf_out = NOBUF;
997 /* Take care of the different block sizes between cdrom and Linux.
998 When Linux gets variable block sizes this will probably go away. */
999 static void transfer(void)
1001 #if DEBUG_BUFFERS | DEBUG_REQUEST
1002 printk(KERN_DEBUG "optcd: executing transfer\n");
1003 #endif
1005 if (!CURRENT_VALID)
1006 return;
1007 while (CURRENT -> nr_sectors) {
1008 int bn = CURRENT -> sector / 4;
1009 int i, offs, nr_sectors;
1010 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1012 DEBUG((DEBUG_REQUEST, "found %d", i));
1014 if (i >= N_BUFS) {
1015 buf_out = NOBUF;
1016 break;
1019 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1020 nr_sectors = 4 - (CURRENT -> sector & 3);
1022 if (buf_out != i) {
1023 buf_out = i;
1024 if (buf_bn[i] != bn) {
1025 buf_out = NOBUF;
1026 continue;
1030 if (nr_sectors > CURRENT -> nr_sectors)
1031 nr_sectors = CURRENT -> nr_sectors;
1032 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1033 CURRENT -> nr_sectors -= nr_sectors;
1034 CURRENT -> sector += nr_sectors;
1035 CURRENT -> buffer += nr_sectors * 512;
1040 /* State machine for reading disk blocks */
1042 enum state_e {
1043 S_IDLE, /* 0 */
1044 S_START, /* 1 */
1045 S_READ, /* 2 */
1046 S_DATA, /* 3 */
1047 S_STOP, /* 4 */
1048 S_STOPPING /* 5 */
1051 static volatile enum state_e state = S_IDLE;
1052 #if DEBUG_STATE
1053 static volatile enum state_e state_old = S_STOP;
1054 static volatile int flags_old = 0;
1055 static volatile long state_n = 0;
1056 #endif
1059 /* Used as mutex to keep do_optcd_request (and other processes calling
1060 ioctl) out while some process is inside a VFS call.
1061 Reverse is accomplished by checking if state = S_IDLE upon entry
1062 of opt_ioctl and opt_media_change. */
1063 static int in_vfs = 0;
1066 static volatile int transfer_is_active = 0;
1067 static volatile int error = 0; /* %% do something with this?? */
1068 static int tries; /* ibid?? */
1069 static int timeout = 0;
1071 static struct timer_list req_timer = {NULL, NULL, 0, 0, NULL};
1073 #define SET_REQ_TIMER(func, jifs) \
1074 req_timer.expires = jiffies+(jifs); \
1075 req_timer.function = (void *) (func); \
1076 add_timer(&req_timer);
1077 #define CLEAR_REQ_TIMER del_timer(&req_timer)
1079 static void poll(void)
1081 static volatile int read_count = 1;
1082 int flags;
1083 int loop_again = 1;
1084 int status = 0;
1085 int skip = 0;
1087 if (error) {
1088 printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
1089 opt_invalidate_buffers();
1090 if (!tries--) {
1091 printk(KERN_ERR "optcd: read block %d failed;"
1092 " Giving up\n", next_bn);
1093 if (transfer_is_active)
1094 loop_again = 0;
1095 if (CURRENT_VALID)
1096 end_request(0);
1097 tries = 5;
1099 error = 0;
1100 state = S_STOP;
1103 while (loop_again)
1105 loop_again = 0; /* each case must flip this back to 1 if we want
1106 to come back up here */
1108 #if DEBUG_STATE
1109 if (state == state_old)
1110 state_n++;
1111 else {
1112 state_old = state;
1113 if (++state_n > 1)
1114 printk(KERN_DEBUG "optcd: %ld times "
1115 "in previous state\n", state_n);
1116 printk(KERN_DEBUG "optcd: state %d\n", state);
1117 state_n = 0;
1119 #endif
1121 switch (state) {
1122 case S_IDLE:
1123 return;
1124 case S_START:
1125 if (in_vfs)
1126 break;
1127 if (send_cmd(COMDRVST)) {
1128 state = S_IDLE;
1129 while (CURRENT_VALID)
1130 end_request(0);
1131 return;
1133 state = S_READ;
1134 timeout = READ_TIMEOUT;
1135 break;
1136 case S_READ: {
1137 struct cdrom_msf msf;
1138 if (!skip) {
1139 status = fetch_status();
1140 if (status < 0)
1141 break;
1142 if (status & ST_DSK_CHG) {
1143 toc_uptodate = 0;
1144 opt_invalidate_buffers();
1147 skip = 0;
1148 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1149 toc_uptodate = 0;
1150 opt_invalidate_buffers();
1151 printk(KERN_WARNING "optcd: %s\n",
1152 (status & ST_DOOR_OPEN)
1153 ? "door open"
1154 : "disk removed");
1155 state = S_IDLE;
1156 while (CURRENT_VALID)
1157 end_request(0);
1158 return;
1160 if (!CURRENT_VALID) {
1161 state = S_STOP;
1162 loop_again = 1;
1163 break;
1165 next_bn = CURRENT -> sector / 4;
1166 lba2msf(next_bn, &msf);
1167 read_count = N_BUFS;
1168 msf.cdmsf_frame1 = read_count; /* Not BCD! */
1170 DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1171 msf.cdmsf_min0,
1172 msf.cdmsf_sec0,
1173 msf.cdmsf_frame0,
1174 msf.cdmsf_min1,
1175 msf.cdmsf_sec1,
1176 msf.cdmsf_frame1));
1177 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1178 " buf_out:%d buf_bn:%d",
1179 next_bn,
1180 buf_in,
1181 buf_out,
1182 buf_bn[buf_in]));
1184 exec_read_cmd(COMREAD, &msf);
1185 state = S_DATA;
1186 timeout = READ_TIMEOUT;
1187 break;
1189 case S_DATA:
1190 flags = stdt_flags() & (FL_STEN|FL_DTEN);
1192 #if DEBUG_STATE
1193 if (flags != flags_old) {
1194 flags_old = flags;
1195 printk(KERN_DEBUG "optcd: flags:%x\n", flags);
1197 if (flags == FL_STEN)
1198 printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
1199 #endif
1201 switch (flags) {
1202 case FL_DTEN: /* only STEN low */
1203 if (!tries--) {
1204 printk(KERN_ERR
1205 "optcd: read block %d failed; "
1206 "Giving up\n", next_bn);
1207 if (transfer_is_active) {
1208 tries = 0;
1209 break;
1211 if (CURRENT_VALID)
1212 end_request(0);
1213 tries = 5;
1215 state = S_START;
1216 timeout = READ_TIMEOUT;
1217 loop_again = 1;
1218 case (FL_STEN|FL_DTEN): /* both high */
1219 break;
1220 default: /* DTEN low */
1221 tries = 5;
1222 if (!CURRENT_VALID && buf_in == buf_out) {
1223 state = S_STOP;
1224 loop_again = 1;
1225 break;
1227 if (read_count<=0)
1228 printk(KERN_WARNING
1229 "optcd: warning - try to read"
1230 " 0 frames\n");
1231 while (read_count) {
1232 buf_bn[buf_in] = NOBUF;
1233 if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1234 /* should be no waiting here!?? */
1235 printk(KERN_ERR
1236 "read_count:%d "
1237 "CURRENT->nr_sectors:%ld "
1238 "buf_in:%d\n",
1239 read_count,
1240 CURRENT->nr_sectors,
1241 buf_in);
1242 printk(KERN_ERR
1243 "transfer active: %x\n",
1244 transfer_is_active);
1245 read_count = 0;
1246 state = S_STOP;
1247 loop_again = 1;
1248 end_request(0);
1249 break;
1251 fetch_data(buf+
1252 CD_FRAMESIZE*buf_in,
1253 CD_FRAMESIZE);
1254 read_count--;
1256 DEBUG((DEBUG_REQUEST,
1257 "S_DATA; ---I've read data- "
1258 "read_count: %d",
1259 read_count));
1260 DEBUG((DEBUG_REQUEST,
1261 "next_bn:%d buf_in:%d "
1262 "buf_out:%d buf_bn:%d",
1263 next_bn,
1264 buf_in,
1265 buf_out,
1266 buf_bn[buf_in]));
1268 buf_bn[buf_in] = next_bn++;
1269 if (buf_out == NOBUF)
1270 buf_out = buf_in;
1271 buf_in = buf_in + 1 ==
1272 N_BUFS ? 0 : buf_in + 1;
1274 if (!transfer_is_active) {
1275 while (CURRENT_VALID) {
1276 transfer();
1277 if (CURRENT -> nr_sectors == 0)
1278 end_request(1);
1279 else
1280 break;
1284 if (CURRENT_VALID
1285 && (CURRENT -> sector / 4 < next_bn ||
1286 CURRENT -> sector / 4 >
1287 next_bn + N_BUFS)) {
1288 state = S_STOP;
1289 loop_again = 1;
1290 break;
1292 timeout = READ_TIMEOUT;
1293 if (read_count == 0) {
1294 state = S_STOP;
1295 loop_again = 1;
1296 break;
1299 break;
1300 case S_STOP:
1301 if (read_count != 0)
1302 printk(KERN_ERR
1303 "optcd: discard data=%x frames\n",
1304 read_count);
1305 flush_data();
1306 if (send_cmd(COMDRVST)) {
1307 state = S_IDLE;
1308 while (CURRENT_VALID)
1309 end_request(0);
1310 return;
1312 state = S_STOPPING;
1313 timeout = STOP_TIMEOUT;
1314 break;
1315 case S_STOPPING:
1316 status = fetch_status();
1317 if (status < 0 && timeout)
1318 break;
1319 if ((status >= 0) && (status & ST_DSK_CHG)) {
1320 toc_uptodate = 0;
1321 opt_invalidate_buffers();
1323 if (CURRENT_VALID) {
1324 if (status >= 0) {
1325 state = S_READ;
1326 loop_again = 1;
1327 skip = 1;
1328 break;
1329 } else {
1330 state = S_START;
1331 timeout = 1;
1333 } else {
1334 state = S_IDLE;
1335 return;
1337 break;
1338 default:
1339 printk(KERN_ERR "optcd: invalid state %d\n", state);
1340 return;
1341 } /* case */
1342 } /* while */
1344 if (!timeout--) {
1345 printk(KERN_ERR "optcd: timeout in state %d\n", state);
1346 state = S_STOP;
1347 if (exec_cmd(COMSTOP) < 0) {
1348 state = S_IDLE;
1349 while (CURRENT_VALID)
1350 end_request(0);
1351 return;
1355 SET_REQ_TIMER(poll, HZ/100);
1359 static void do_optcd_request(void)
1361 DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1362 CURRENT -> sector, CURRENT -> nr_sectors));
1364 if (disk_info.audio) {
1365 printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");
1366 end_request(0);
1367 return;
1370 transfer_is_active = 1;
1371 while (CURRENT_VALID) {
1372 if (CURRENT->bh) {
1373 if (!buffer_locked(CURRENT->bh))
1374 panic(DEVICE_NAME ": block not locked");
1376 transfer(); /* First try to transfer block from buffers */
1377 if (CURRENT -> nr_sectors == 0) {
1378 end_request(1);
1379 } else { /* Want to read a block not in buffer */
1380 buf_out = NOBUF;
1381 if (state == S_IDLE) {
1382 /* %% Should this block the request queue?? */
1383 if (update_toc() < 0) {
1384 while (CURRENT_VALID)
1385 end_request(0);
1386 break;
1388 /* Start state machine */
1389 state = S_START;
1390 timeout = READ_TIMEOUT;
1391 tries = 5;
1392 /* %% why not start right away?? */
1393 SET_REQ_TIMER(poll, HZ/100);
1395 break;
1398 transfer_is_active = 0;
1400 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d",
1401 next_bn, buf_in, buf_out, buf_bn[buf_in]));
1402 DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1405 /* IOCTLs */
1408 static char auto_eject = 0;
1410 static int cdrompause(void)
1412 int status;
1414 if (audio_status != CDROM_AUDIO_PLAY)
1415 return -EINVAL;
1417 status = exec_cmd(COMPAUSEON);
1418 if (status < 0) {
1419 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1420 return -EIO;
1422 audio_status = CDROM_AUDIO_PAUSED;
1423 return 0;
1427 static int cdromresume(void)
1429 int status;
1431 if (audio_status != CDROM_AUDIO_PAUSED)
1432 return -EINVAL;
1434 status = exec_cmd(COMPAUSEOFF);
1435 if (status < 0) {
1436 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1437 audio_status = CDROM_AUDIO_ERROR;
1438 return -EIO;
1440 audio_status = CDROM_AUDIO_PLAY;
1441 return 0;
1445 static int cdromplaymsf(unsigned long arg)
1447 int status;
1448 struct cdrom_msf msf;
1450 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1451 if (status)
1452 return status;
1453 copy_from_user(&msf, (void *) arg, sizeof msf);
1455 bin2bcd(&msf);
1456 status = exec_long_cmd(COMPLAY, &msf);
1457 if (status < 0) {
1458 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1459 audio_status = CDROM_AUDIO_ERROR;
1460 return -EIO;
1463 audio_status = CDROM_AUDIO_PLAY;
1464 return 0;
1468 static int cdromplaytrkind(unsigned long arg)
1470 int status;
1471 struct cdrom_ti ti;
1472 struct cdrom_msf msf;
1474 status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1475 if (status)
1476 return status;
1477 copy_from_user(&ti, (void *) arg, sizeof ti);
1479 if (ti.cdti_trk0 < disk_info.first
1480 || ti.cdti_trk0 > disk_info.last
1481 || ti.cdti_trk1 < ti.cdti_trk0)
1482 return -EINVAL;
1483 if (ti.cdti_trk1 > disk_info.last)
1484 ti.cdti_trk1 = disk_info.last;
1486 msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1487 msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1488 msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1489 msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1490 msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1491 msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1493 DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1494 msf.cdmsf_min0,
1495 msf.cdmsf_sec0,
1496 msf.cdmsf_frame0,
1497 msf.cdmsf_min1,
1498 msf.cdmsf_sec1,
1499 msf.cdmsf_frame1));
1501 bin2bcd(&msf);
1502 status = exec_long_cmd(COMPLAY, &msf);
1503 if (status < 0) {
1504 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1505 audio_status = CDROM_AUDIO_ERROR;
1506 return -EIO;
1509 audio_status = CDROM_AUDIO_PLAY;
1510 return 0;
1514 static int cdromreadtochdr(unsigned long arg)
1516 int status;
1517 struct cdrom_tochdr tochdr;
1519 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1520 if (status)
1521 return status;
1523 tochdr.cdth_trk0 = disk_info.first;
1524 tochdr.cdth_trk1 = disk_info.last;
1526 copy_to_user((void *) arg, &tochdr, sizeof tochdr);
1527 return 0;
1531 static int cdromreadtocentry(unsigned long arg)
1533 int status;
1534 struct cdrom_tocentry entry;
1535 struct cdrom_subchnl *tocptr;
1537 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1538 if (status)
1539 return status;
1540 copy_from_user(&entry, (void *) arg, sizeof entry);
1542 if (entry.cdte_track == CDROM_LEADOUT)
1543 tocptr = &toc[disk_info.last + 1];
1544 else if (entry.cdte_track > disk_info.last
1545 || entry.cdte_track < disk_info.first)
1546 return -EINVAL;
1547 else
1548 tocptr = &toc[entry.cdte_track];
1550 entry.cdte_adr = tocptr->cdsc_adr;
1551 entry.cdte_ctrl = tocptr->cdsc_ctrl;
1552 entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1553 entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1554 entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1555 /* %% What should go into entry.cdte_datamode? */
1557 if (entry.cdte_format == CDROM_LBA)
1558 msf2lba(&entry.cdte_addr);
1559 else if (entry.cdte_format != CDROM_MSF)
1560 return -EINVAL;
1562 copy_to_user((void *) arg, &entry, sizeof entry);
1563 return 0;
1567 static int cdromvolctrl(unsigned long arg)
1569 int status;
1570 struct cdrom_volctrl volctrl;
1571 struct cdrom_msf msf;
1573 status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1574 if (status)
1575 return status;
1576 copy_from_user(&volctrl, (char *) arg, sizeof volctrl);
1578 msf.cdmsf_min0 = 0x10;
1579 msf.cdmsf_sec0 = 0x32;
1580 msf.cdmsf_frame0 = volctrl.channel0;
1581 msf.cdmsf_min1 = volctrl.channel1;
1582 msf.cdmsf_sec1 = volctrl.channel2;
1583 msf.cdmsf_frame1 = volctrl.channel3;
1585 status = exec_long_cmd(COMCHCTRL, &msf);
1586 if (status < 0) {
1587 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1588 return -EIO;
1590 return 0;
1594 static int cdromsubchnl(unsigned long arg)
1596 int status;
1597 struct cdrom_subchnl subchnl;
1599 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1600 if (status)
1601 return status;
1602 copy_from_user(&subchnl, (void *) arg, sizeof subchnl);
1604 if (subchnl.cdsc_format != CDROM_LBA
1605 && subchnl.cdsc_format != CDROM_MSF)
1606 return -EINVAL;
1608 status = get_q_channel(&subchnl);
1609 if (status < 0) {
1610 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1611 return -EIO;
1614 copy_to_user((void *) arg, &subchnl, sizeof subchnl);
1615 return 0;
1619 static int cdromread(unsigned long arg, int blocksize, int cmd)
1621 int status;
1622 struct cdrom_msf msf;
1623 char buf[CD_FRAMESIZE_RAWER];
1625 status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1626 if (status)
1627 return status;
1628 copy_from_user(&msf, (void *) arg, sizeof msf);
1630 bin2bcd(&msf);
1631 msf.cdmsf_min1 = 0;
1632 msf.cdmsf_sec1 = 0;
1633 msf.cdmsf_frame1 = 1; /* read only one frame */
1634 status = exec_read_cmd(cmd, &msf);
1636 DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1638 if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1639 return -EIO;
1640 fetch_data(buf, blocksize);
1642 copy_to_user((void *) arg, &buf, blocksize);
1643 return 0;
1647 static int cdromseek(unsigned long arg)
1649 int status;
1650 struct cdrom_msf msf;
1652 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1653 if (status)
1654 return status;
1655 copy_from_user(&msf, (void *) arg, sizeof msf);
1657 bin2bcd(&msf);
1658 status = exec_seek_cmd(COMSEEK, &msf);
1660 DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1662 if (status < 0)
1663 return -EIO;
1664 return 0;
1668 #ifdef MULTISESSION
1669 static int cdrommultisession(unsigned long arg)
1671 int status;
1672 struct cdrom_multisession ms;
1674 status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1675 if (status)
1676 return status;
1677 copy_from_user(&ms, (void*) arg, sizeof ms);
1679 ms.addr.msf.minute = disk_info.last_session.minute;
1680 ms.addr.msf.second = disk_info.last_session.second;
1681 ms.addr.msf.frame = disk_info.last_session.frame;
1683 if (ms.addr_format != CDROM_LBA
1684 && ms.addr_format != CDROM_MSF)
1685 return -EINVAL;
1686 if (ms.addr_format == CDROM_LBA)
1687 msf2lba(&ms.addr);
1689 ms.xa_flag = disk_info.xa;
1691 copy_to_user((void*) arg, &ms,
1692 sizeof(struct cdrom_multisession));
1694 #if DEBUG_MULTIS
1695 if (ms.addr_format == CDROM_MSF)
1696 printk(KERN_DEBUG
1697 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1698 ms.xa_flag,
1699 ms.addr.msf.minute,
1700 ms.addr.msf.second,
1701 ms.addr.msf.frame);
1702 else
1703 printk(KERN_DEBUG
1704 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1705 ms.xa_flag,
1706 ms.addr.lba,
1707 disk_info.last_session.minute,
1708 disk_info.last_session.second,
1709 disk_info.last_session.frame);
1710 #endif DEBUG_MULTIS
1712 return 0;
1714 #endif MULTISESSION
1717 static int cdromreset(void)
1719 if (state != S_IDLE) {
1720 error = 1;
1721 tries = 0;
1724 toc_uptodate = 0;
1725 disk_changed = 1;
1726 opt_invalidate_buffers();
1727 audio_status = CDROM_AUDIO_NO_STATUS;
1729 if (!reset_drive())
1730 return -EIO;
1731 return 0;
1734 /* VFS calls */
1737 static int opt_ioctl(struct inode *ip, struct file *fp,
1738 unsigned int cmd, unsigned long arg)
1740 int status, err, retval = 0;
1742 DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1744 if (!ip)
1745 return -EINVAL;
1747 if (cmd == CDROMRESET)
1748 return cdromreset();
1750 /* is do_optcd_request or another ioctl busy? */
1751 if (state != S_IDLE || in_vfs)
1752 return -EBUSY;
1754 in_vfs = 1;
1756 status = drive_status();
1757 if (status < 0) {
1758 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1759 in_vfs = 0;
1760 return -EIO;
1763 if (status & ST_DOOR_OPEN)
1764 switch (cmd) { /* Actions that can be taken with door open */
1765 case CDROMCLOSETRAY:
1766 /* We do this before trying to read the toc. */
1767 err = exec_cmd(COMCLOSE);
1768 if (err < 0) {
1769 DEBUG((DEBUG_VFS,
1770 "exec_cmd COMCLOSE: %02x", -err));
1771 in_vfs = 0;
1772 return -EIO;
1774 break;
1775 default: in_vfs = 0;
1776 return -EBUSY;
1779 err = update_toc();
1780 if (err < 0) {
1781 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1782 in_vfs = 0;
1783 return -EIO;
1786 DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1788 switch (cmd) {
1789 case CDROMPAUSE: retval = cdrompause(); break;
1790 case CDROMRESUME: retval = cdromresume(); break;
1791 case CDROMPLAYMSF: retval = cdromplaymsf(arg); break;
1792 case CDROMPLAYTRKIND: retval = cdromplaytrkind(arg); break;
1793 case CDROMREADTOCHDR: retval = cdromreadtochdr(arg); break;
1794 case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break;
1796 case CDROMSTOP: err = exec_cmd(COMSTOP);
1797 if (err < 0) {
1798 DEBUG((DEBUG_VFS,
1799 "exec_cmd COMSTOP: %02x",
1800 -err));
1801 retval = -EIO;
1802 } else
1803 audio_status = CDROM_AUDIO_NO_STATUS;
1804 break;
1805 case CDROMSTART: break; /* This is a no-op */
1806 case CDROMEJECT: err = exec_cmd(COMUNLOCK);
1807 if (err < 0) {
1808 DEBUG((DEBUG_VFS,
1809 "exec_cmd COMUNLOCK: %02x",
1810 -err));
1811 retval = -EIO;
1812 break;
1814 err = exec_cmd(COMOPEN);
1815 if (err < 0) {
1816 DEBUG((DEBUG_VFS,
1817 "exec_cmd COMOPEN: %02x",
1818 -err));
1819 retval = -EIO;
1821 break;
1823 case CDROMVOLCTRL: retval = cdromvolctrl(arg); break;
1824 case CDROMSUBCHNL: retval = cdromsubchnl(arg); break;
1826 /* The drive detects the mode and automatically delivers the
1827 correct 2048 bytes, so we don't need these IOCTLs */
1828 case CDROMREADMODE2: retval = -EINVAL; break;
1829 case CDROMREADMODE1: retval = -EINVAL; break;
1831 /* Drive doesn't support reading audio */
1832 case CDROMREADAUDIO: retval = -EINVAL; break;
1834 case CDROMEJECT_SW: auto_eject = (char) arg;
1835 break;
1837 #ifdef MULTISESSION
1838 case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1839 #endif
1841 case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */
1842 case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */
1844 case CDROMREADRAW:
1845 /* this drive delivers 2340 bytes in raw mode */
1846 retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);
1847 break;
1848 case CDROMREADCOOKED:
1849 retval = cdromread(arg, CD_FRAMESIZE, COMREAD);
1850 break;
1851 case CDROMREADALL:
1852 retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);
1853 break;
1855 case CDROMSEEK: retval = cdromseek(arg); break;
1856 case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */
1857 case CDROMCLOSETRAY: break; /* The action was taken earlier */
1858 default: retval = -EINVAL;
1860 in_vfs = 0;
1861 return retval;
1865 static int open_count = 0;
1867 /* Open device special file; check that a disk is in. */
1868 static int opt_open(struct inode *ip, struct file *fp)
1870 DEBUG((DEBUG_VFS, "starting opt_open"));
1872 if (!open_count && state == S_IDLE) {
1873 int status;
1875 toc_uptodate = 0;
1876 opt_invalidate_buffers();
1878 status = exec_cmd(COMCLOSE); /* close door */
1879 if (status < 0) {
1880 DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1883 status = drive_status();
1884 if (status < 0) {
1885 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1886 return -EIO;
1888 DEBUG((DEBUG_VFS, "status: %02x", status));
1889 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1890 printk(KERN_INFO "optcd: no disk or door open\n");
1891 return -EIO;
1893 status = exec_cmd(COMLOCK); /* Lock door */
1894 if (status < 0) {
1895 DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1897 status = update_toc(); /* Read table of contents */
1898 if (status < 0) {
1899 DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1900 status = exec_cmd(COMUNLOCK); /* Unlock door */
1901 if (status < 0) {
1902 DEBUG((DEBUG_VFS,
1903 "exec_cmd COMUNLOCK: %02x", -status));
1905 return -EIO;
1907 open_count++;
1909 MOD_INC_USE_COUNT;
1911 DEBUG((DEBUG_VFS, "exiting opt_open"));
1913 return 0;
1917 /* Release device special file; flush all blocks from the buffer cache */
1918 static int opt_release(struct inode *ip, struct file *fp)
1920 int status;
1922 DEBUG((DEBUG_VFS, "executing opt_release"));
1923 DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1924 ip, ip -> i_rdev, fp));
1926 if (!--open_count) {
1927 toc_uptodate = 0;
1928 opt_invalidate_buffers();
1929 sync_dev(ip -> i_rdev);
1930 invalidate_buffers(ip -> i_rdev);
1931 status = exec_cmd(COMUNLOCK); /* Unlock door */
1932 if (status < 0) {
1933 DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1935 if (auto_eject) {
1936 status = exec_cmd(COMOPEN);
1937 DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1939 CLEAR_TIMER;
1940 CLEAR_REQ_TIMER;
1942 MOD_DEC_USE_COUNT;
1943 return 0;
1947 /* Check if disk has been changed */
1948 static int opt_media_change(kdev_t dev)
1950 DEBUG((DEBUG_VFS, "executing opt_media_change"));
1951 DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1953 if (disk_changed) {
1954 disk_changed = 0;
1955 return 1;
1957 return 0;
1960 /* Driver initialisation */
1963 /* Returns 1 if a drive is detected with a version string
1964 starting with "DOLPHIN". Otherwise 0. */
1965 __initfunc(static int version_ok(void))
1967 char devname[100];
1968 int count, i, ch, status;
1970 status = exec_cmd(COMVERSION);
1971 if (status < 0) {
1972 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1973 return 0;
1975 if ((count = get_data(1)) < 0) {
1976 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1977 return 0;
1979 for (i = 0, ch = -1; count > 0; count--) {
1980 if ((ch = get_data(1)) < 0) {
1981 DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1982 break;
1984 if (i < 99)
1985 devname[i++] = ch;
1987 devname[i] = '\0';
1988 if (ch < 0)
1989 return 0;
1991 printk(KERN_INFO "optcd: Device %s detected\n", devname);
1992 return ((devname[0] == 'D')
1993 && (devname[1] == 'O')
1994 && (devname[2] == 'L')
1995 && (devname[3] == 'P')
1996 && (devname[4] == 'H')
1997 && (devname[5] == 'I')
1998 && (devname[6] == 'N'));
2002 static struct file_operations opt_fops = {
2003 NULL, /* lseek - default */
2004 block_read, /* read - general block-dev read */
2005 block_write, /* write - general block-dev write */
2006 NULL, /* readdir - bad */
2007 NULL, /* poll */
2008 opt_ioctl, /* ioctl */
2009 NULL, /* mmap */
2010 opt_open, /* open */
2011 NULL, /* flush */
2012 opt_release, /* release */
2013 NULL, /* fsync */
2014 NULL, /* fasync */
2015 opt_media_change, /* media change */
2016 NULL /* revalidate */
2020 /* Get kernel parameter when used as a kernel driver */
2021 __initfunc(void optcd_setup(char *str, int *ints))
2023 if (ints[0] > 0)
2024 optcd_port = ints[1];
2027 /* Test for presence of drive and initialize it. Called at boot time
2028 or during module initialisation. */
2029 __initfunc(int optcd_init(void))
2031 int status;
2033 if (optcd_port <= 0) {
2034 printk(KERN_INFO
2035 "optcd: no Optics Storage CDROM Initialization\n");
2036 return -EIO;
2038 if (check_region(optcd_port, 4)) {
2039 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2040 optcd_port);
2041 return -EIO;
2044 if (!reset_drive()) {
2045 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2046 return -EIO;
2048 if (!version_ok()) {
2049 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2050 return -EIO;
2052 status = exec_cmd(COMINITDOUBLE);
2053 if (status < 0) {
2054 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2055 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2056 return -EIO;
2058 if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2060 printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2061 return -EIO;
2064 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
2065 read_ahead[MAJOR_NR] = 4;
2066 request_region(optcd_port, 4, "optcd");
2068 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2069 return 0;
2073 #ifdef MODULE
2074 int init_module(void)
2076 return optcd_init();
2080 void cleanup_module(void)
2082 if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2083 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2084 return;
2086 release_region(optcd_port, 4);
2087 printk(KERN_INFO "optcd: module released.\n");
2089 #endif MODULE