Revert last change. Bug noticed by Linus.
[linux-2.6/linux-mips.git] / drivers / cdrom / optcd.c
blobf851cd074edd3dd1050be4bdec8c9894bb2ca199
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.
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>
67 /* Includes */
70 #include <linux/module.h>
71 #include <linux/mm.h>
72 #include <linux/ioport.h>
73 #include <linux/init.h>
74 #include <linux/devfs_fs_kernel.h>
76 #include <asm/io.h>
78 #define MAJOR_NR OPTICS_CDROM_MAJOR
79 #include <linux/blk.h>
81 #include <linux/cdrom.h>
82 #include "optcd.h"
84 #include <asm/uaccess.h>
87 /* Debug support */
90 /* Don't forget to add new debug flags here. */
91 #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
92 DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
93 #define DEBUG(x) debug x
94 static void debug(int debug_this, const char* fmt, ...)
96 char s[1024];
97 va_list args;
99 if (!debug_this)
100 return;
102 va_start(args, fmt);
103 vsprintf(s, fmt, args);
104 printk(KERN_DEBUG "optcd: %s\n", s);
105 va_end(args);
107 #else
108 #define DEBUG(x)
109 #endif
111 static int blksize = 2048;
112 static int hsecsize = 2048;
115 /* Drive hardware/firmware characteristics
116 Identifiers in accordance with Optics Storage documentation */
119 #define optcd_port optcd /* Needed for the modutils. */
120 static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */
121 MODULE_PARM(optcd_port, "h");
122 /* Drive registers, read */
123 #define DATA_PORT optcd_port /* Read data/status */
124 #define STATUS_PORT optcd_port+1 /* Indicate data/status availability */
126 /* Drive registers, write */
127 #define COMIN_PORT optcd_port /* For passing command/parameter */
128 #define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */
129 #define HCON_PORT optcd_port+2 /* Host Xfer Configuration */
132 /* Command completion/status read from DATA register */
133 #define ST_DRVERR 0x80
134 #define ST_DOOR_OPEN 0x40
135 #define ST_MIXEDMODE_DISK 0x20
136 #define ST_MODE_BITS 0x1c
137 #define ST_M_STOP 0x00
138 #define ST_M_READ 0x04
139 #define ST_M_AUDIO 0x04
140 #define ST_M_PAUSE 0x08
141 #define ST_M_INITIAL 0x0c
142 #define ST_M_ERROR 0x10
143 #define ST_M_OTHERS 0x14
144 #define ST_MODE2TRACK 0x02
145 #define ST_DSK_CHG 0x01
146 #define ST_L_LOCK 0x01
147 #define ST_CMD_OK 0x00
148 #define ST_OP_OK 0x01
149 #define ST_PA_OK 0x02
150 #define ST_OP_ERROR 0x05
151 #define ST_PA_ERROR 0x06
154 /* Error codes (appear as command completion code from DATA register) */
155 /* Player related errors */
156 #define ERR_ILLCMD 0x11 /* Illegal command to player module */
157 #define ERR_ILLPARM 0x12 /* Illegal parameter to player module */
158 #define ERR_SLEDGE 0x13
159 #define ERR_FOCUS 0x14
160 #define ERR_MOTOR 0x15
161 #define ERR_RADIAL 0x16
162 #define ERR_PLL 0x17 /* PLL lock error */
163 #define ERR_SUB_TIM 0x18 /* Subcode timeout error */
164 #define ERR_SUB_NF 0x19 /* Subcode not found error */
165 #define ERR_TRAY 0x1a
166 #define ERR_TOC 0x1b /* Table of Contents read error */
167 #define ERR_JUMP 0x1c
168 /* Data errors */
169 #define ERR_MODE 0x21
170 #define ERR_FORM 0x22
171 #define ERR_HEADADDR 0x23 /* Header Address not found */
172 #define ERR_CRC 0x24
173 #define ERR_ECC 0x25 /* Uncorrectable ECC error */
174 #define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */
175 #define ERR_ILLBSYNC 0x27 /* Illegal block sync error */
176 #define ERR_VDST 0x28 /* VDST not found */
177 /* Timeout errors */
178 #define ERR_READ_TIM 0x31 /* Read timeout error */
179 #define ERR_DEC_STP 0x32 /* Decoder stopped */
180 #define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */
181 /* Function abort codes */
182 #define ERR_KEY 0x41 /* Key -Detected abort */
183 #define ERR_READ_FINISH 0x42 /* Read Finish */
184 /* Second Byte diagnostic codes */
185 #define ERR_NOBSYNC 0x01 /* No block sync */
186 #define ERR_SHORTB 0x02 /* Short block */
187 #define ERR_LONGB 0x03 /* Long block */
188 #define ERR_SHORTDSP 0x04 /* Short DSP word */
189 #define ERR_LONGDSP 0x05 /* Long DSP word */
192 /* Status availability flags read from STATUS register */
193 #define FL_EJECT 0x20
194 #define FL_WAIT 0x10 /* active low */
195 #define FL_EOP 0x08 /* active low */
196 #define FL_STEN 0x04 /* Status available when low */
197 #define FL_DTEN 0x02 /* Data available when low */
198 #define FL_DRQ 0x01 /* active low */
199 #define FL_RESET 0xde /* These bits are high after a reset */
200 #define FL_STDT (FL_STEN|FL_DTEN)
203 /* Transfer mode, written to HCON register */
204 #define HCON_DTS 0x08
205 #define HCON_SDRQB 0x04
206 #define HCON_LOHI 0x02
207 #define HCON_DMA16 0x01
210 /* Drive command set, written to COMIN register */
211 /* Quick response commands */
212 #define COMDRVST 0x20 /* Drive Status Read */
213 #define COMERRST 0x21 /* Error Status Read */
214 #define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */
215 #define COMINITSINGLE 0x28 /* Initialize Single Speed */
216 #define COMINITDOUBLE 0x29 /* Initialize Double Speed */
217 #define COMUNLOCK 0x30 /* Unlock */
218 #define COMLOCK 0x31 /* Lock */
219 #define COMLOCKST 0x32 /* Lock/Unlock Status */
220 #define COMVERSION 0x40 /* Get Firmware Revision */
221 #define COMVOIDREADMODE 0x50 /* Void Data Read Mode */
222 /* Read commands */
223 #define COMFETCH 0x60 /* Prefetch Data */
224 #define COMREAD 0x61 /* Read */
225 #define COMREADRAW 0x62 /* Read Raw Data */
226 #define COMREADALL 0x63 /* Read All 2646 Bytes */
227 /* Player control commands */
228 #define COMLEADIN 0x70 /* Seek To Lead-in */
229 #define COMSEEK 0x71 /* Seek */
230 #define COMPAUSEON 0x80 /* Pause On */
231 #define COMPAUSEOFF 0x81 /* Pause Off */
232 #define COMSTOP 0x82 /* Stop */
233 #define COMOPEN 0x90 /* Open Tray Door */
234 #define COMCLOSE 0x91 /* Close Tray Door */
235 #define COMPLAY 0xa0 /* Audio Play */
236 #define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */
237 #define COMSUBQ 0xb0 /* Read Sub-q Code */
238 #define COMLOCATION 0xb1 /* Read Head Position */
239 /* Audio control commands */
240 #define COMCHCTRL 0xc0 /* Audio Channel Control */
241 /* Miscellaneous (test) commands */
242 #define COMDRVTEST 0xd0 /* Write Test Bytes */
243 #define COMTEST 0xd1 /* Diagnostic Test */
245 /* Low level drive interface. Only here we do actual I/O
246 Waiting for status / data available */
249 /* Busy wait until FLAG goes low. Return 0 on timeout. */
250 inline static int flag_low(int flag, unsigned long timeout)
252 int flag_high;
253 unsigned long count = 0;
255 while ((flag_high = (inb(STATUS_PORT) & flag)))
256 if (++count >= timeout)
257 break;
259 DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
260 flag, count, flag_high ? " timeout" : ""));
261 return !flag_high;
265 /* Timed waiting for status or data */
266 static int sleep_timeout; /* max # of ticks to sleep */
267 static DECLARE_WAIT_QUEUE_HEAD(waitq);
268 static void sleep_timer(unsigned long data);
269 static struct timer_list delay_timer = {function: sleep_timer};
272 /* Timer routine: wake up when desired flag goes low,
273 or when timeout expires. */
274 static void sleep_timer(unsigned long data)
276 int flags = inb(STATUS_PORT) & FL_STDT;
278 if (flags == FL_STDT && --sleep_timeout > 0) {
279 mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */
280 } else
281 wake_up(&waitq);
285 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
286 static int sleep_flag_low(int flag, unsigned long timeout)
288 int flag_high;
290 DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
292 sleep_timeout = timeout;
293 flag_high = inb(STATUS_PORT) & flag;
294 if (flag_high && sleep_timeout > 0) {
295 mod_timer(&delay_timer, jiffies + HZ/100);
296 sleep_on(&waitq);
297 flag_high = inb(STATUS_PORT) & flag;
300 DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
301 flag, timeout, flag_high ? " timeout" : ""));
302 return !flag_high;
305 /* Low level drive interface. Only here we do actual I/O
306 Sending commands and parameters */
309 /* Errors in the command protocol */
310 #define ERR_IF_CMD_TIMEOUT 0x100
311 #define ERR_IF_ERR_TIMEOUT 0x101
312 #define ERR_IF_RESP_TIMEOUT 0x102
313 #define ERR_IF_DATA_TIMEOUT 0x103
314 #define ERR_IF_NOSTAT 0x104
317 /* Send command code. Return <0 indicates error */
318 static int send_cmd(int cmd)
320 unsigned char ack;
322 DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
324 outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */
325 outb(cmd, COMIN_PORT); /* Send command code */
326 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
327 return -ERR_IF_CMD_TIMEOUT;
328 ack = inb(DATA_PORT); /* read command acknowledge */
329 outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
330 return ack==ST_OP_OK ? 0 : -ack;
334 /* Send command parameters. Return <0 indicates error */
335 static int send_params(struct cdrom_msf *params)
337 unsigned char ack;
339 DEBUG((DEBUG_DRIVE_IF, "sending parameters"
340 " %02x:%02x:%02x"
341 " %02x:%02x:%02x",
342 params->cdmsf_min0,
343 params->cdmsf_sec0,
344 params->cdmsf_frame0,
345 params->cdmsf_min1,
346 params->cdmsf_sec1,
347 params->cdmsf_frame1));
349 outb(params->cdmsf_min0, COMIN_PORT);
350 outb(params->cdmsf_sec0, COMIN_PORT);
351 outb(params->cdmsf_frame0, COMIN_PORT);
352 outb(params->cdmsf_min1, COMIN_PORT);
353 outb(params->cdmsf_sec1, COMIN_PORT);
354 outb(params->cdmsf_frame1, COMIN_PORT);
355 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
356 return -ERR_IF_CMD_TIMEOUT;
357 ack = inb(DATA_PORT); /* read command acknowledge */
358 return ack==ST_PA_OK ? 0 : -ack;
362 /* Send parameters for SEEK command. Return <0 indicates error */
363 static int send_seek_params(struct cdrom_msf *params)
365 unsigned char ack;
367 DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
368 " %02x:%02x:%02x",
369 params->cdmsf_min0,
370 params->cdmsf_sec0,
371 params->cdmsf_frame0));
373 outb(params->cdmsf_min0, COMIN_PORT);
374 outb(params->cdmsf_sec0, COMIN_PORT);
375 outb(params->cdmsf_frame0, COMIN_PORT);
376 if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */
377 return -ERR_IF_CMD_TIMEOUT;
378 ack = inb(DATA_PORT); /* read command acknowledge */
379 return ack==ST_PA_OK ? 0 : -ack;
383 /* Wait for command execution status. Choice between busy waiting
384 and sleeping. Return value <0 indicates timeout. */
385 inline static int get_exec_status(int busy_waiting)
387 unsigned char exec_status;
389 if (busy_waiting
390 ? !flag_low(FL_STEN, BUSY_TIMEOUT)
391 : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
392 return -ERR_IF_CMD_TIMEOUT;
394 exec_status = inb(DATA_PORT);
395 DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
396 return exec_status;
400 /* Wait busy for extra byte of data that a command returns.
401 Return value <0 indicates timeout. */
402 inline static int get_data(int short_timeout)
404 unsigned char data;
406 if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
407 return -ERR_IF_DATA_TIMEOUT;
409 data = inb(DATA_PORT);
410 DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
411 return data;
415 /* Returns 0 if failed */
416 static int reset_drive(void)
418 unsigned long count = 0;
419 int flags;
421 DEBUG((DEBUG_DRIVE_IF, "reset drive"));
423 outb(0, RESET_PORT);
424 while (++count < RESET_WAIT)
425 inb(DATA_PORT);
427 count = 0;
428 while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
429 if (++count >= BUSY_TIMEOUT)
430 break;
432 DEBUG((DEBUG_DRIVE_IF, "reset %s",
433 flags == FL_RESET ? "succeeded" : "failed"));
435 if (flags != FL_RESET)
436 return 0; /* Reset failed */
437 outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */
438 return 1; /* Reset succeeded */
442 /* Facilities for asynchronous operation */
444 /* Read status/data availability flags FL_STEN and FL_DTEN */
445 inline static int stdt_flags(void)
447 return inb(STATUS_PORT) & FL_STDT;
451 /* Fetch status that has previously been waited for. <0 means not available */
452 inline static int fetch_status(void)
454 unsigned char status;
456 if (inb(STATUS_PORT) & FL_STEN)
457 return -ERR_IF_NOSTAT;
459 status = inb(DATA_PORT);
460 DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
461 return status;
465 /* Fetch data that has previously been waited for. */
466 inline static void fetch_data(char *buf, int n)
468 insb(DATA_PORT, buf, n);
469 DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
473 /* Flush status and data fifos */
474 inline static void flush_data(void)
476 while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
477 inb(DATA_PORT);
478 DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
481 /* Command protocol */
484 /* Send a simple command and wait for response. Command codes < COMFETCH
485 are quick response commands */
486 inline static int exec_cmd(int cmd)
488 int ack = send_cmd(cmd);
489 if (ack < 0)
490 return ack;
491 return get_exec_status(cmd < COMFETCH);
495 /* Send a command with parameters. Don't wait for the response,
496 * which consists of data blocks read from the CD. */
497 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
499 int ack = send_cmd(cmd);
500 if (ack < 0)
501 return ack;
502 return send_params(params);
506 /* Send a seek command with parameters and wait for response */
507 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
509 int ack = send_cmd(cmd);
510 if (ack < 0)
511 return ack;
512 ack = send_seek_params(params);
513 if (ack < 0)
514 return ack;
515 return 0;
519 /* Send a command with parameters and wait for response */
520 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
522 int ack = exec_read_cmd(cmd, params);
523 if (ack < 0)
524 return ack;
525 return get_exec_status(0);
528 /* Address conversion routines */
531 /* Binary to BCD (2 digits) */
532 inline static void single_bin2bcd(u_char *p)
534 DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
535 *p = (*p % 10) | ((*p / 10) << 4);
539 /* Convert entire msf struct */
540 static void bin2bcd(struct cdrom_msf *msf)
542 single_bin2bcd(&msf->cdmsf_min0);
543 single_bin2bcd(&msf->cdmsf_sec0);
544 single_bin2bcd(&msf->cdmsf_frame0);
545 single_bin2bcd(&msf->cdmsf_min1);
546 single_bin2bcd(&msf->cdmsf_sec1);
547 single_bin2bcd(&msf->cdmsf_frame1);
551 /* Linear block address to minute, second, frame form */
552 #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */
554 static void lba2msf(int lba, struct cdrom_msf *msf)
556 DEBUG((DEBUG_CONV, "lba2msf %d", lba));
557 lba += CD_MSF_OFFSET;
558 msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
559 msf->cdmsf_sec0 = lba / CD_FRAMES;
560 msf->cdmsf_frame0 = lba % CD_FRAMES;
561 msf->cdmsf_min1 = 0;
562 msf->cdmsf_sec1 = 0;
563 msf->cdmsf_frame1 = 0;
564 bin2bcd(msf);
568 /* Two BCD digits to binary */
569 inline static u_char bcd2bin(u_char bcd)
571 DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
572 return (bcd >> 4) * 10 + (bcd & 0x0f);
576 static void msf2lba(union cdrom_addr *addr)
578 addr->lba = addr->msf.minute * CD_FPM
579 + addr->msf.second * CD_FRAMES
580 + addr->msf.frame - CD_MSF_OFFSET;
584 /* Minute, second, frame address BCD to binary or to linear address,
585 depending on MODE */
586 static void msf_bcd2bin(union cdrom_addr *addr)
588 addr->msf.minute = bcd2bin(addr->msf.minute);
589 addr->msf.second = bcd2bin(addr->msf.second);
590 addr->msf.frame = bcd2bin(addr->msf.frame);
593 /* High level drive commands */
596 static int audio_status = CDROM_AUDIO_NO_STATUS;
597 static char toc_uptodate = 0;
598 static char disk_changed = 1;
600 /* Get drive status, flagging completion of audio play and disk changes. */
601 static int drive_status(void)
603 int status;
605 status = exec_cmd(COMIOCTLISTAT);
606 DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
607 if (status < 0)
608 return status;
609 if (status == 0xff) /* No status available */
610 return -ERR_IF_NOSTAT;
612 if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
613 (audio_status == CDROM_AUDIO_PLAY)) {
614 audio_status = CDROM_AUDIO_COMPLETED;
617 if (status & ST_DSK_CHG) {
618 toc_uptodate = 0;
619 disk_changed = 1;
620 audio_status = CDROM_AUDIO_NO_STATUS;
623 return status;
627 /* Read the current Q-channel info. Also used for reading the
628 table of contents. qp->cdsc_format must be set on entry to
629 indicate the desired address format */
630 static int get_q_channel(struct cdrom_subchnl *qp)
632 int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
634 status = drive_status();
635 if (status < 0)
636 return status;
637 qp->cdsc_audiostatus = audio_status;
639 status = exec_cmd(COMSUBQ);
640 if (status < 0)
641 return status;
643 d1 = get_data(0);
644 if (d1 < 0)
645 return d1;
646 qp->cdsc_adr = d1;
647 qp->cdsc_ctrl = d1 >> 4;
649 d2 = get_data(0);
650 if (d2 < 0)
651 return d2;
652 qp->cdsc_trk = bcd2bin(d2);
654 d3 = get_data(0);
655 if (d3 < 0)
656 return d3;
657 qp->cdsc_ind = bcd2bin(d3);
659 d4 = get_data(0);
660 if (d4 < 0)
661 return d4;
662 qp->cdsc_reladdr.msf.minute = d4;
664 d5 = get_data(0);
665 if (d5 < 0)
666 return d5;
667 qp->cdsc_reladdr.msf.second = d5;
669 d6 = get_data(0);
670 if (d6 < 0)
671 return d6;
672 qp->cdsc_reladdr.msf.frame = d6;
674 d7 = get_data(0);
675 if (d7 < 0)
676 return d7;
677 /* byte not used */
679 d8 = get_data(0);
680 if (d8 < 0)
681 return d8;
682 qp->cdsc_absaddr.msf.minute = d8;
684 d9 = get_data(0);
685 if (d9 < 0)
686 return d9;
687 qp->cdsc_absaddr.msf.second = d9;
689 d10 = get_data(0);
690 if (d10 < 0)
691 return d10;
692 qp->cdsc_absaddr.msf.frame = d10;
694 DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
695 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
697 msf_bcd2bin(&qp->cdsc_absaddr);
698 msf_bcd2bin(&qp->cdsc_reladdr);
699 if (qp->cdsc_format == CDROM_LBA) {
700 msf2lba(&qp->cdsc_absaddr);
701 msf2lba(&qp->cdsc_reladdr);
704 return 0;
707 /* Table of contents handling */
710 /* Errors in table of contents */
711 #define ERR_TOC_MISSINGINFO 0x120
712 #define ERR_TOC_MISSINGENTRY 0x121
715 struct cdrom_disk_info {
716 unsigned char first;
717 unsigned char last;
718 struct cdrom_msf0 disk_length;
719 struct cdrom_msf0 first_track;
720 /* Multisession info: */
721 unsigned char next;
722 struct cdrom_msf0 next_session;
723 struct cdrom_msf0 last_session;
724 unsigned char multi;
725 unsigned char xa;
726 unsigned char audio;
728 static struct cdrom_disk_info disk_info;
730 #define MAX_TRACKS 111
731 static struct cdrom_subchnl toc[MAX_TRACKS];
733 #define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */
734 #define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */
735 #define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */
736 #define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */
738 #define I_FIRSTTRACK 0x01
739 #define I_LASTTRACK 0x02
740 #define I_DISKLENGTH 0x04
741 #define I_NEXTSESSION 0x08
742 #define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
745 #if DEBUG_TOC
746 void toc_debug_info(int i)
748 printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
749 " %2d:%02d.%02d %2d:%02d.%02d\n",
750 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
751 toc[i].cdsc_trk, toc[i].cdsc_ind,
752 toc[i].cdsc_reladdr.msf.minute,
753 toc[i].cdsc_reladdr.msf.second,
754 toc[i].cdsc_reladdr.msf.frame,
755 toc[i].cdsc_absaddr.msf.minute,
756 toc[i].cdsc_absaddr.msf.second,
757 toc[i].cdsc_absaddr.msf.frame);
759 #endif
762 static int read_toc(void)
764 int status, limit, count;
765 unsigned char got_info = 0;
766 struct cdrom_subchnl q_info;
767 #if DEBUG_TOC
768 int i;
769 #endif
771 DEBUG((DEBUG_TOC, "starting read_toc"));
773 count = 0;
774 for (limit = 60; limit > 0; limit--) {
775 int index;
777 q_info.cdsc_format = CDROM_MSF;
778 status = get_q_channel(&q_info);
779 if (status < 0)
780 return status;
782 index = q_info.cdsc_ind;
783 if (index > 0 && index < MAX_TRACKS
784 && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
785 toc[index] = q_info;
786 DEBUG((DEBUG_TOC, "got %d", index));
787 if (index < 100)
788 count++;
790 switch (q_info.cdsc_ind) {
791 case QINFO_FIRSTTRACK:
792 got_info |= I_FIRSTTRACK;
793 break;
794 case QINFO_LASTTRACK:
795 got_info |= I_LASTTRACK;
796 break;
797 case QINFO_DISKLENGTH:
798 got_info |= I_DISKLENGTH;
799 break;
800 case QINFO_NEXTSESSION:
801 got_info |= I_NEXTSESSION;
802 break;
806 if ((got_info & I_ALL) == I_ALL
807 && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
808 >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
809 break;
812 /* Construct disk_info from TOC */
813 if (disk_info.first == 0) {
814 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
815 disk_info.first_track.minute =
816 toc[disk_info.first].cdsc_absaddr.msf.minute;
817 disk_info.first_track.second =
818 toc[disk_info.first].cdsc_absaddr.msf.second;
819 disk_info.first_track.frame =
820 toc[disk_info.first].cdsc_absaddr.msf.frame;
822 disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
823 disk_info.disk_length.minute =
824 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
825 disk_info.disk_length.second =
826 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
827 disk_info.disk_length.frame =
828 toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
829 disk_info.next_session.minute =
830 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
831 disk_info.next_session.second =
832 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
833 disk_info.next_session.frame =
834 toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
835 disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
836 disk_info.last_session.minute =
837 toc[disk_info.next].cdsc_absaddr.msf.minute;
838 disk_info.last_session.second =
839 toc[disk_info.next].cdsc_absaddr.msf.second;
840 disk_info.last_session.frame =
841 toc[disk_info.next].cdsc_absaddr.msf.frame;
842 toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
843 disk_info.disk_length.minute;
844 toc[disk_info.last + 1].cdsc_absaddr.msf.second =
845 disk_info.disk_length.second;
846 toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
847 disk_info.disk_length.frame;
848 #if DEBUG_TOC
849 for (i = 1; i <= disk_info.last + 1; i++)
850 toc_debug_info(i);
851 toc_debug_info(QINFO_FIRSTTRACK);
852 toc_debug_info(QINFO_LASTTRACK);
853 toc_debug_info(QINFO_DISKLENGTH);
854 toc_debug_info(QINFO_NEXTSESSION);
855 #endif
857 DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
858 got_info, count));
859 if ((got_info & I_ALL) != I_ALL
860 || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
861 < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
862 return -ERR_TOC_MISSINGINFO;
863 return 0;
867 #ifdef MULTISESSION
868 static int get_multi_disk_info(void)
870 int sessions, status;
871 struct cdrom_msf multi_index;
874 for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
875 int count;
877 for (count = 100; count < MAX_TRACKS; count++)
878 toc[count].cdsc_ind = 0;
880 multi_index.cdmsf_min0 = disk_info.next_session.minute;
881 multi_index.cdmsf_sec0 = disk_info.next_session.second;
882 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
883 if (multi_index.cdmsf_sec0 >= 20)
884 multi_index.cdmsf_sec0 -= 20;
885 else {
886 multi_index.cdmsf_sec0 += 40;
887 multi_index.cdmsf_min0--;
889 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
890 multi_index.cdmsf_min0,
891 multi_index.cdmsf_sec0,
892 multi_index.cdmsf_frame0));
893 bin2bcd(&multi_index);
894 multi_index.cdmsf_min1 = 0;
895 multi_index.cdmsf_sec1 = 0;
896 multi_index.cdmsf_frame1 = 1;
898 status = exec_read_cmd(COMREAD, &multi_index);
899 if (status < 0) {
900 DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
901 -status));
902 break;
904 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
905 0 : -ERR_TOC_MISSINGINFO;
906 flush_data();
907 if (status < 0) {
908 DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
909 break;
912 status = read_toc();
913 if (status < 0) {
914 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
915 break;
918 disk_info.multi = 1;
921 exec_cmd(COMSTOP);
923 if (status < 0)
924 return -EIO;
925 return 0;
927 #endif MULTISESSION
930 static int update_toc(void)
932 int status, count;
934 if (toc_uptodate)
935 return 0;
937 DEBUG((DEBUG_TOC, "starting update_toc"));
939 disk_info.first = 0;
940 for (count = 0; count < MAX_TRACKS; count++)
941 toc[count].cdsc_ind = 0;
943 status = exec_cmd(COMLEADIN);
944 if (status < 0)
945 return -EIO;
947 status = read_toc();
948 if (status < 0) {
949 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
950 return -EIO;
953 /* Audio disk detection. Look at first track. */
954 disk_info.audio =
955 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
957 /* XA detection */
958 disk_info.xa = drive_status() & ST_MODE2TRACK;
960 /* Multisession detection: if we want this, define MULTISESSION */
961 disk_info.multi = 0;
962 #ifdef MULTISESSION
963 if (disk_info.xa)
964 get_multi_disk_info(); /* Here disk_info.multi is set */
965 #endif MULTISESSION
966 if (disk_info.multi)
967 printk(KERN_WARNING "optcd: Multisession support experimental, "
968 "see linux/Documentation/cdrom/optcd\n");
970 DEBUG((DEBUG_TOC, "exiting update_toc"));
972 toc_uptodate = 1;
973 return 0;
976 /* Request handling */
979 #define CURRENT_VALID \
980 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
981 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
984 /* Buffers for block size conversion. */
985 #define NOBUF -1
987 static char buf[CD_FRAMESIZE * N_BUFS];
988 static volatile int buf_bn[N_BUFS], next_bn;
989 static volatile int buf_in = 0, buf_out = NOBUF;
991 inline static void opt_invalidate_buffers(void)
993 int i;
995 DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
997 for (i = 0; i < N_BUFS; i++)
998 buf_bn[i] = NOBUF;
999 buf_out = NOBUF;
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");
1009 #endif
1011 if (!CURRENT_VALID)
1012 return;
1013 while (CURRENT -> nr_sectors) {
1014 int bn = CURRENT -> sector / 4;
1015 int i, offs, nr_sectors;
1016 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1018 DEBUG((DEBUG_REQUEST, "found %d", i));
1020 if (i >= N_BUFS) {
1021 buf_out = NOBUF;
1022 break;
1025 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1026 nr_sectors = 4 - (CURRENT -> sector & 3);
1028 if (buf_out != i) {
1029 buf_out = i;
1030 if (buf_bn[i] != bn) {
1031 buf_out = NOBUF;
1032 continue;
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 */
1048 enum state_e {
1049 S_IDLE, /* 0 */
1050 S_START, /* 1 */
1051 S_READ, /* 2 */
1052 S_DATA, /* 3 */
1053 S_STOP, /* 4 */
1054 S_STOPPING /* 5 */
1057 static volatile enum state_e state = S_IDLE;
1058 #if DEBUG_STATE
1059 static volatile enum state_e state_old = S_STOP;
1060 static volatile int flags_old = 0;
1061 static volatile long state_n = 0;
1062 #endif
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;
1084 int flags;
1085 int loop_again = 1;
1086 int status = 0;
1087 int skip = 0;
1089 if (error) {
1090 printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
1091 opt_invalidate_buffers();
1092 if (!tries--) {
1093 printk(KERN_ERR "optcd: read block %d failed;"
1094 " Giving up\n", next_bn);
1095 if (transfer_is_active)
1096 loop_again = 0;
1097 if (CURRENT_VALID)
1098 end_request(0);
1099 tries = 5;
1101 error = 0;
1102 state = S_STOP;
1105 while (loop_again)
1107 loop_again = 0; /* each case must flip this back to 1 if we want
1108 to come back up here */
1110 #if DEBUG_STATE
1111 if (state == state_old)
1112 state_n++;
1113 else {
1114 state_old = state;
1115 if (++state_n > 1)
1116 printk(KERN_DEBUG "optcd: %ld times "
1117 "in previous state\n", state_n);
1118 printk(KERN_DEBUG "optcd: state %d\n", state);
1119 state_n = 0;
1121 #endif
1123 switch (state) {
1124 case S_IDLE:
1125 return;
1126 case S_START:
1127 if (in_vfs)
1128 break;
1129 if (send_cmd(COMDRVST)) {
1130 state = S_IDLE;
1131 while (CURRENT_VALID)
1132 end_request(0);
1133 return;
1135 state = S_READ;
1136 timeout = READ_TIMEOUT;
1137 break;
1138 case S_READ: {
1139 struct cdrom_msf msf;
1140 if (!skip) {
1141 status = fetch_status();
1142 if (status < 0)
1143 break;
1144 if (status & ST_DSK_CHG) {
1145 toc_uptodate = 0;
1146 opt_invalidate_buffers();
1149 skip = 0;
1150 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1151 toc_uptodate = 0;
1152 opt_invalidate_buffers();
1153 printk(KERN_WARNING "optcd: %s\n",
1154 (status & ST_DOOR_OPEN)
1155 ? "door open"
1156 : "disk removed");
1157 state = S_IDLE;
1158 while (CURRENT_VALID)
1159 end_request(0);
1160 return;
1162 if (!CURRENT_VALID) {
1163 state = S_STOP;
1164 loop_again = 1;
1165 break;
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",
1173 msf.cdmsf_min0,
1174 msf.cdmsf_sec0,
1175 msf.cdmsf_frame0,
1176 msf.cdmsf_min1,
1177 msf.cdmsf_sec1,
1178 msf.cdmsf_frame1));
1179 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1180 " buf_out:%d buf_bn:%d",
1181 next_bn,
1182 buf_in,
1183 buf_out,
1184 buf_bn[buf_in]));
1186 exec_read_cmd(COMREAD, &msf);
1187 state = S_DATA;
1188 timeout = READ_TIMEOUT;
1189 break;
1191 case S_DATA:
1192 flags = stdt_flags() & (FL_STEN|FL_DTEN);
1194 #if DEBUG_STATE
1195 if (flags != flags_old) {
1196 flags_old = flags;
1197 printk(KERN_DEBUG "optcd: flags:%x\n", flags);
1199 if (flags == FL_STEN)
1200 printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
1201 #endif
1203 switch (flags) {
1204 case FL_DTEN: /* only STEN low */
1205 if (!tries--) {
1206 printk(KERN_ERR
1207 "optcd: read block %d failed; "
1208 "Giving up\n", next_bn);
1209 if (transfer_is_active) {
1210 tries = 0;
1211 break;
1213 if (CURRENT_VALID)
1214 end_request(0);
1215 tries = 5;
1217 state = S_START;
1218 timeout = READ_TIMEOUT;
1219 loop_again = 1;
1220 case (FL_STEN|FL_DTEN): /* both high */
1221 break;
1222 default: /* DTEN low */
1223 tries = 5;
1224 if (!CURRENT_VALID && buf_in == buf_out) {
1225 state = S_STOP;
1226 loop_again = 1;
1227 break;
1229 if (read_count<=0)
1230 printk(KERN_WARNING
1231 "optcd: warning - try to read"
1232 " 0 frames\n");
1233 while (read_count) {
1234 buf_bn[buf_in] = NOBUF;
1235 if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1236 /* should be no waiting here!?? */
1237 printk(KERN_ERR
1238 "read_count:%d "
1239 "CURRENT->nr_sectors:%ld "
1240 "buf_in:%d\n",
1241 read_count,
1242 CURRENT->nr_sectors,
1243 buf_in);
1244 printk(KERN_ERR
1245 "transfer active: %x\n",
1246 transfer_is_active);
1247 read_count = 0;
1248 state = S_STOP;
1249 loop_again = 1;
1250 end_request(0);
1251 break;
1253 fetch_data(buf+
1254 CD_FRAMESIZE*buf_in,
1255 CD_FRAMESIZE);
1256 read_count--;
1258 DEBUG((DEBUG_REQUEST,
1259 "S_DATA; ---I've read data- "
1260 "read_count: %d",
1261 read_count));
1262 DEBUG((DEBUG_REQUEST,
1263 "next_bn:%d buf_in:%d "
1264 "buf_out:%d buf_bn:%d",
1265 next_bn,
1266 buf_in,
1267 buf_out,
1268 buf_bn[buf_in]));
1270 buf_bn[buf_in] = next_bn++;
1271 if (buf_out == NOBUF)
1272 buf_out = buf_in;
1273 buf_in = buf_in + 1 ==
1274 N_BUFS ? 0 : buf_in + 1;
1276 if (!transfer_is_active) {
1277 while (CURRENT_VALID) {
1278 transfer();
1279 if (CURRENT -> nr_sectors == 0)
1280 end_request(1);
1281 else
1282 break;
1286 if (CURRENT_VALID
1287 && (CURRENT -> sector / 4 < next_bn ||
1288 CURRENT -> sector / 4 >
1289 next_bn + N_BUFS)) {
1290 state = S_STOP;
1291 loop_again = 1;
1292 break;
1294 timeout = READ_TIMEOUT;
1295 if (read_count == 0) {
1296 state = S_STOP;
1297 loop_again = 1;
1298 break;
1301 break;
1302 case S_STOP:
1303 if (read_count != 0)
1304 printk(KERN_ERR
1305 "optcd: discard data=%x frames\n",
1306 read_count);
1307 flush_data();
1308 if (send_cmd(COMDRVST)) {
1309 state = S_IDLE;
1310 while (CURRENT_VALID)
1311 end_request(0);
1312 return;
1314 state = S_STOPPING;
1315 timeout = STOP_TIMEOUT;
1316 break;
1317 case S_STOPPING:
1318 status = fetch_status();
1319 if (status < 0 && timeout)
1320 break;
1321 if ((status >= 0) && (status & ST_DSK_CHG)) {
1322 toc_uptodate = 0;
1323 opt_invalidate_buffers();
1325 if (CURRENT_VALID) {
1326 if (status >= 0) {
1327 state = S_READ;
1328 loop_again = 1;
1329 skip = 1;
1330 break;
1331 } else {
1332 state = S_START;
1333 timeout = 1;
1335 } else {
1336 state = S_IDLE;
1337 return;
1339 break;
1340 default:
1341 printk(KERN_ERR "optcd: invalid state %d\n", state);
1342 return;
1343 } /* case */
1344 } /* while */
1346 if (!timeout--) {
1347 printk(KERN_ERR "optcd: timeout in state %d\n", state);
1348 state = S_STOP;
1349 if (exec_cmd(COMSTOP) < 0) {
1350 state = S_IDLE;
1351 while (CURRENT_VALID)
1352 end_request(0);
1353 return;
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(0);
1369 return;
1372 transfer_is_active = 1;
1373 while (CURRENT_VALID) {
1374 if (CURRENT->bh) {
1375 if (!buffer_locked(CURRENT->bh))
1376 panic(DEVICE_NAME ": block not locked");
1378 transfer(); /* First try to transfer block from buffers */
1379 if (CURRENT -> nr_sectors == 0) {
1380 end_request(1);
1381 } else { /* Want to read a block not in buffer */
1382 buf_out = NOBUF;
1383 if (state == S_IDLE) {
1384 /* %% Should this block the request queue?? */
1385 if (update_toc() < 0) {
1386 while (CURRENT_VALID)
1387 end_request(0);
1388 break;
1390 /* Start state machine */
1391 state = S_START;
1392 timeout = READ_TIMEOUT;
1393 tries = 5;
1394 /* %% why not start right away?? */
1395 mod_timer(&req_timer, jiffies + HZ/100);
1397 break;
1400 transfer_is_active = 0;
1402 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d",
1403 next_bn, buf_in, buf_out, buf_bn[buf_in]));
1404 DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1407 /* IOCTLs */
1410 static char auto_eject = 0;
1412 static int cdrompause(void)
1414 int status;
1416 if (audio_status != CDROM_AUDIO_PLAY)
1417 return -EINVAL;
1419 status = exec_cmd(COMPAUSEON);
1420 if (status < 0) {
1421 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1422 return -EIO;
1424 audio_status = CDROM_AUDIO_PAUSED;
1425 return 0;
1429 static int cdromresume(void)
1431 int status;
1433 if (audio_status != CDROM_AUDIO_PAUSED)
1434 return -EINVAL;
1436 status = exec_cmd(COMPAUSEOFF);
1437 if (status < 0) {
1438 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1439 audio_status = CDROM_AUDIO_ERROR;
1440 return -EIO;
1442 audio_status = CDROM_AUDIO_PLAY;
1443 return 0;
1447 static int cdromplaymsf(unsigned long arg)
1449 int status;
1450 struct cdrom_msf msf;
1452 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1453 if (status)
1454 return status;
1455 copy_from_user(&msf, (void *) arg, sizeof msf);
1457 bin2bcd(&msf);
1458 status = exec_long_cmd(COMPLAY, &msf);
1459 if (status < 0) {
1460 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1461 audio_status = CDROM_AUDIO_ERROR;
1462 return -EIO;
1465 audio_status = CDROM_AUDIO_PLAY;
1466 return 0;
1470 static int cdromplaytrkind(unsigned long arg)
1472 int status;
1473 struct cdrom_ti ti;
1474 struct cdrom_msf msf;
1476 status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1477 if (status)
1478 return status;
1479 copy_from_user(&ti, (void *) arg, sizeof ti);
1481 if (ti.cdti_trk0 < disk_info.first
1482 || ti.cdti_trk0 > disk_info.last
1483 || ti.cdti_trk1 < ti.cdti_trk0)
1484 return -EINVAL;
1485 if (ti.cdti_trk1 > disk_info.last)
1486 ti.cdti_trk1 = disk_info.last;
1488 msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1489 msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1490 msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1491 msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1492 msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1493 msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1495 DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1496 msf.cdmsf_min0,
1497 msf.cdmsf_sec0,
1498 msf.cdmsf_frame0,
1499 msf.cdmsf_min1,
1500 msf.cdmsf_sec1,
1501 msf.cdmsf_frame1));
1503 bin2bcd(&msf);
1504 status = exec_long_cmd(COMPLAY, &msf);
1505 if (status < 0) {
1506 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1507 audio_status = CDROM_AUDIO_ERROR;
1508 return -EIO;
1511 audio_status = CDROM_AUDIO_PLAY;
1512 return 0;
1516 static int cdromreadtochdr(unsigned long arg)
1518 int status;
1519 struct cdrom_tochdr tochdr;
1521 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1522 if (status)
1523 return status;
1525 tochdr.cdth_trk0 = disk_info.first;
1526 tochdr.cdth_trk1 = disk_info.last;
1528 copy_to_user((void *) arg, &tochdr, sizeof tochdr);
1529 return 0;
1533 static int cdromreadtocentry(unsigned long arg)
1535 int status;
1536 struct cdrom_tocentry entry;
1537 struct cdrom_subchnl *tocptr;
1539 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1540 if (status)
1541 return status;
1542 copy_from_user(&entry, (void *) arg, sizeof entry);
1544 if (entry.cdte_track == CDROM_LEADOUT)
1545 tocptr = &toc[disk_info.last + 1];
1546 else if (entry.cdte_track > disk_info.last
1547 || entry.cdte_track < disk_info.first)
1548 return -EINVAL;
1549 else
1550 tocptr = &toc[entry.cdte_track];
1552 entry.cdte_adr = tocptr->cdsc_adr;
1553 entry.cdte_ctrl = tocptr->cdsc_ctrl;
1554 entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1555 entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1556 entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1557 /* %% What should go into entry.cdte_datamode? */
1559 if (entry.cdte_format == CDROM_LBA)
1560 msf2lba(&entry.cdte_addr);
1561 else if (entry.cdte_format != CDROM_MSF)
1562 return -EINVAL;
1564 copy_to_user((void *) arg, &entry, sizeof entry);
1565 return 0;
1569 static int cdromvolctrl(unsigned long arg)
1571 int status;
1572 struct cdrom_volctrl volctrl;
1573 struct cdrom_msf msf;
1575 status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1576 if (status)
1577 return status;
1578 copy_from_user(&volctrl, (char *) arg, sizeof volctrl);
1580 msf.cdmsf_min0 = 0x10;
1581 msf.cdmsf_sec0 = 0x32;
1582 msf.cdmsf_frame0 = volctrl.channel0;
1583 msf.cdmsf_min1 = volctrl.channel1;
1584 msf.cdmsf_sec1 = volctrl.channel2;
1585 msf.cdmsf_frame1 = volctrl.channel3;
1587 status = exec_long_cmd(COMCHCTRL, &msf);
1588 if (status < 0) {
1589 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1590 return -EIO;
1592 return 0;
1596 static int cdromsubchnl(unsigned long arg)
1598 int status;
1599 struct cdrom_subchnl subchnl;
1601 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1602 if (status)
1603 return status;
1604 copy_from_user(&subchnl, (void *) arg, sizeof subchnl);
1606 if (subchnl.cdsc_format != CDROM_LBA
1607 && subchnl.cdsc_format != CDROM_MSF)
1608 return -EINVAL;
1610 status = get_q_channel(&subchnl);
1611 if (status < 0) {
1612 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1613 return -EIO;
1616 copy_to_user((void *) arg, &subchnl, sizeof subchnl);
1617 return 0;
1621 static int cdromread(unsigned long arg, int blocksize, int cmd)
1623 int status;
1624 struct cdrom_msf msf;
1625 char buf[CD_FRAMESIZE_RAWER];
1627 status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1628 if (status)
1629 return status;
1630 copy_from_user(&msf, (void *) arg, sizeof msf);
1632 bin2bcd(&msf);
1633 msf.cdmsf_min1 = 0;
1634 msf.cdmsf_sec1 = 0;
1635 msf.cdmsf_frame1 = 1; /* read only one frame */
1636 status = exec_read_cmd(cmd, &msf);
1638 DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1640 if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1641 return -EIO;
1642 fetch_data(buf, blocksize);
1644 copy_to_user((void *) arg, &buf, blocksize);
1645 return 0;
1649 static int cdromseek(unsigned long arg)
1651 int status;
1652 struct cdrom_msf msf;
1654 status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1655 if (status)
1656 return status;
1657 copy_from_user(&msf, (void *) arg, sizeof msf);
1659 bin2bcd(&msf);
1660 status = exec_seek_cmd(COMSEEK, &msf);
1662 DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1664 if (status < 0)
1665 return -EIO;
1666 return 0;
1670 #ifdef MULTISESSION
1671 static int cdrommultisession(unsigned long arg)
1673 int status;
1674 struct cdrom_multisession ms;
1676 status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1677 if (status)
1678 return status;
1679 copy_from_user(&ms, (void*) arg, sizeof ms);
1681 ms.addr.msf.minute = disk_info.last_session.minute;
1682 ms.addr.msf.second = disk_info.last_session.second;
1683 ms.addr.msf.frame = disk_info.last_session.frame;
1685 if (ms.addr_format != CDROM_LBA
1686 && ms.addr_format != CDROM_MSF)
1687 return -EINVAL;
1688 if (ms.addr_format == CDROM_LBA)
1689 msf2lba(&ms.addr);
1691 ms.xa_flag = disk_info.xa;
1693 copy_to_user((void*) arg, &ms,
1694 sizeof(struct cdrom_multisession));
1696 #if DEBUG_MULTIS
1697 if (ms.addr_format == CDROM_MSF)
1698 printk(KERN_DEBUG
1699 "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1700 ms.xa_flag,
1701 ms.addr.msf.minute,
1702 ms.addr.msf.second,
1703 ms.addr.msf.frame);
1704 else
1705 printk(KERN_DEBUG
1706 "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1707 ms.xa_flag,
1708 ms.addr.lba,
1709 disk_info.last_session.minute,
1710 disk_info.last_session.second,
1711 disk_info.last_session.frame);
1712 #endif DEBUG_MULTIS
1714 return 0;
1716 #endif MULTISESSION
1719 static int cdromreset(void)
1721 if (state != S_IDLE) {
1722 error = 1;
1723 tries = 0;
1726 toc_uptodate = 0;
1727 disk_changed = 1;
1728 opt_invalidate_buffers();
1729 audio_status = CDROM_AUDIO_NO_STATUS;
1731 if (!reset_drive())
1732 return -EIO;
1733 return 0;
1736 /* VFS calls */
1739 static int opt_ioctl(struct inode *ip, struct file *fp,
1740 unsigned int cmd, unsigned long arg)
1742 int status, err, retval = 0;
1744 DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1746 if (!ip)
1747 return -EINVAL;
1749 if (cmd == CDROMRESET)
1750 return cdromreset();
1752 /* is do_optcd_request or another ioctl busy? */
1753 if (state != S_IDLE || in_vfs)
1754 return -EBUSY;
1756 in_vfs = 1;
1758 status = drive_status();
1759 if (status < 0) {
1760 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1761 in_vfs = 0;
1762 return -EIO;
1765 if (status & ST_DOOR_OPEN)
1766 switch (cmd) { /* Actions that can be taken with door open */
1767 case CDROMCLOSETRAY:
1768 /* We do this before trying to read the toc. */
1769 err = exec_cmd(COMCLOSE);
1770 if (err < 0) {
1771 DEBUG((DEBUG_VFS,
1772 "exec_cmd COMCLOSE: %02x", -err));
1773 in_vfs = 0;
1774 return -EIO;
1776 break;
1777 default: in_vfs = 0;
1778 return -EBUSY;
1781 err = update_toc();
1782 if (err < 0) {
1783 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1784 in_vfs = 0;
1785 return -EIO;
1788 DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1790 switch (cmd) {
1791 case CDROMPAUSE: retval = cdrompause(); break;
1792 case CDROMRESUME: retval = cdromresume(); break;
1793 case CDROMPLAYMSF: retval = cdromplaymsf(arg); break;
1794 case CDROMPLAYTRKIND: retval = cdromplaytrkind(arg); break;
1795 case CDROMREADTOCHDR: retval = cdromreadtochdr(arg); break;
1796 case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break;
1798 case CDROMSTOP: err = exec_cmd(COMSTOP);
1799 if (err < 0) {
1800 DEBUG((DEBUG_VFS,
1801 "exec_cmd COMSTOP: %02x",
1802 -err));
1803 retval = -EIO;
1804 } else
1805 audio_status = CDROM_AUDIO_NO_STATUS;
1806 break;
1807 case CDROMSTART: break; /* This is a no-op */
1808 case CDROMEJECT: err = exec_cmd(COMUNLOCK);
1809 if (err < 0) {
1810 DEBUG((DEBUG_VFS,
1811 "exec_cmd COMUNLOCK: %02x",
1812 -err));
1813 retval = -EIO;
1814 break;
1816 err = exec_cmd(COMOPEN);
1817 if (err < 0) {
1818 DEBUG((DEBUG_VFS,
1819 "exec_cmd COMOPEN: %02x",
1820 -err));
1821 retval = -EIO;
1823 break;
1825 case CDROMVOLCTRL: retval = cdromvolctrl(arg); break;
1826 case CDROMSUBCHNL: retval = cdromsubchnl(arg); break;
1828 /* The drive detects the mode and automatically delivers the
1829 correct 2048 bytes, so we don't need these IOCTLs */
1830 case CDROMREADMODE2: retval = -EINVAL; break;
1831 case CDROMREADMODE1: retval = -EINVAL; break;
1833 /* Drive doesn't support reading audio */
1834 case CDROMREADAUDIO: retval = -EINVAL; break;
1836 case CDROMEJECT_SW: auto_eject = (char) arg;
1837 break;
1839 #ifdef MULTISESSION
1840 case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1841 #endif
1843 case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */
1844 case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */
1846 case CDROMREADRAW:
1847 /* this drive delivers 2340 bytes in raw mode */
1848 retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);
1849 break;
1850 case CDROMREADCOOKED:
1851 retval = cdromread(arg, CD_FRAMESIZE, COMREAD);
1852 break;
1853 case CDROMREADALL:
1854 retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);
1855 break;
1857 case CDROMSEEK: retval = cdromseek(arg); break;
1858 case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */
1859 case CDROMCLOSETRAY: break; /* The action was taken earlier */
1860 default: retval = -EINVAL;
1862 in_vfs = 0;
1863 return retval;
1867 static int open_count = 0;
1869 /* Open device special file; check that a disk is in. */
1870 static int opt_open(struct inode *ip, struct file *fp)
1872 DEBUG((DEBUG_VFS, "starting opt_open"));
1874 MOD_INC_USE_COUNT;
1876 if (!open_count && state == S_IDLE) {
1877 int status;
1879 toc_uptodate = 0;
1880 opt_invalidate_buffers();
1882 status = exec_cmd(COMCLOSE); /* close door */
1883 if (status < 0) {
1884 DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1887 status = drive_status();
1888 if (status < 0) {
1889 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1890 goto err_out;
1892 DEBUG((DEBUG_VFS, "status: %02x", status));
1893 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1894 printk(KERN_INFO "optcd: no disk or door open\n");
1895 goto err_out;
1897 status = exec_cmd(COMLOCK); /* Lock door */
1898 if (status < 0) {
1899 DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1901 status = update_toc(); /* Read table of contents */
1902 if (status < 0) {
1903 DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1904 status = exec_cmd(COMUNLOCK); /* Unlock door */
1905 if (status < 0) {
1906 DEBUG((DEBUG_VFS,
1907 "exec_cmd COMUNLOCK: %02x", -status));
1909 goto err_out;
1911 open_count++;
1914 DEBUG((DEBUG_VFS, "exiting opt_open"));
1916 return 0;
1918 err_out:
1919 MOD_DEC_USE_COUNT;
1920 return -EIO;
1924 /* Release device special file; flush all blocks from the buffer cache */
1925 static int opt_release(struct inode *ip, struct file *fp)
1927 int status;
1929 DEBUG((DEBUG_VFS, "executing opt_release"));
1930 DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1931 ip, ip -> i_rdev, fp));
1933 if (!--open_count) {
1934 toc_uptodate = 0;
1935 opt_invalidate_buffers();
1936 status = exec_cmd(COMUNLOCK); /* Unlock door */
1937 if (status < 0) {
1938 DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1940 if (auto_eject) {
1941 status = exec_cmd(COMOPEN);
1942 DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1944 del_timer(&delay_timer);
1945 del_timer(&req_timer);
1947 MOD_DEC_USE_COUNT;
1948 return 0;
1952 /* Check if disk has been changed */
1953 static int opt_media_change(kdev_t dev)
1955 DEBUG((DEBUG_VFS, "executing opt_media_change"));
1956 DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1958 if (disk_changed) {
1959 disk_changed = 0;
1960 return 1;
1962 return 0;
1965 /* Driver initialisation */
1968 /* Returns 1 if a drive is detected with a version string
1969 starting with "DOLPHIN". Otherwise 0. */
1970 static int __init version_ok(void)
1972 char devname[100];
1973 int count, i, ch, status;
1975 status = exec_cmd(COMVERSION);
1976 if (status < 0) {
1977 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1978 return 0;
1980 if ((count = get_data(1)) < 0) {
1981 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1982 return 0;
1984 for (i = 0, ch = -1; count > 0; count--) {
1985 if ((ch = get_data(1)) < 0) {
1986 DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1987 break;
1989 if (i < 99)
1990 devname[i++] = ch;
1992 devname[i] = '\0';
1993 if (ch < 0)
1994 return 0;
1996 printk(KERN_INFO "optcd: Device %s detected\n", devname);
1997 return ((devname[0] == 'D')
1998 && (devname[1] == 'O')
1999 && (devname[2] == 'L')
2000 && (devname[3] == 'P')
2001 && (devname[4] == 'H')
2002 && (devname[5] == 'I')
2003 && (devname[6] == 'N'));
2007 static struct block_device_operations opt_fops = {
2008 open: opt_open,
2009 release: opt_release,
2010 ioctl: opt_ioctl,
2011 check_media_change: opt_media_change,
2014 #ifndef MODULE
2015 /* Get kernel parameter when used as a kernel driver */
2016 static int optcd_setup(char *str)
2018 int ints[4];
2019 (void)get_options(str, ARRAY_SIZE(ints), ints);
2021 if (ints[0] > 0)
2022 optcd_port = ints[1];
2024 return 1;
2027 __setup("optcd=", optcd_setup);
2029 #endif MODULE
2031 /* Test for presence of drive and initialize it. Called at boot time
2032 or during module initialisation. */
2033 int __init optcd_init(void)
2035 int status;
2037 if (optcd_port <= 0) {
2038 printk(KERN_INFO
2039 "optcd: no Optics Storage CDROM Initialization\n");
2040 return -EIO;
2042 if (check_region(optcd_port, 4)) {
2043 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2044 optcd_port);
2045 return -EIO;
2048 if (!reset_drive()) {
2049 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2050 return -EIO;
2052 if (!version_ok()) {
2053 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2054 return -EIO;
2056 status = exec_cmd(COMINITDOUBLE);
2057 if (status < 0) {
2058 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2059 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2060 return -EIO;
2062 if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2064 printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2065 return -EIO;
2067 devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
2068 S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
2069 hardsect_size[MAJOR_NR] = &hsecsize;
2070 blksize_size[MAJOR_NR] = &blksize;
2071 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
2072 read_ahead[MAJOR_NR] = 4;
2073 request_region(optcd_port, 4, "optcd");
2074 register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);
2076 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2077 return 0;
2081 void __exit optcd_exit(void)
2083 devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,
2084 DEVFS_SPECIAL_BLK, 0));
2085 if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2086 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2087 return;
2089 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
2090 release_region(optcd_port, 4);
2091 printk(KERN_INFO "optcd: module released.\n");
2094 #ifdef MODULE
2095 module_init(optcd_init);
2096 #endif
2097 module_exit(optcd_exit);