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 $
3
4 Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
5
6
7 Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
8 by Eberhard Moenkeberg (emoenke@gwdg.de).
9
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.
14
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.
19
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.
23 */
24
25 /* Revision history
26
27
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.
60
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>
65 */
66
67 /* Includes */
68
69
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>
75
76 #include <asm/io.h>
77
78 #define MAJOR_NR OPTICS_CDROM_MAJOR
79 #include <linux/blk.h>
80
81 #include <linux/cdrom.h>
82 #include "optcd.h"
83
84 #include <asm/uaccess.h>
85
86
87 /* Debug support */
88
89
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
debug(int debug_this,const char * fmt,...)94 static void debug(int debug_this, const char* fmt, ...)
95 {
96 char s[1024];
97 va_list args;
98
99 if (!debug_this)
100 return;
101
102 va_start(args, fmt);
103 vsprintf(s, fmt, args);
104 printk(KERN_DEBUG "optcd: %s\n", s);
105 va_end(args);
106 }
107 #else
108 #define DEBUG(x)
109 #endif
110
111 static int blksize = 2048;
112 static int hsecsize = 2048;
113
114
115 /* Drive hardware/firmware characteristics
116 Identifiers in accordance with Optics Storage documentation */
117
118
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 */
125
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 */
130
131
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
152
153
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 */
190
191
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)
201
202
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
208
209
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 */
244
245 /* Low level drive interface. Only here we do actual I/O
246 Waiting for status / data available */
247
248
249 /* Busy wait until FLAG goes low. Return 0 on timeout. */
flag_low(int flag,unsigned long timeout)250 inline static int flag_low(int flag, unsigned long timeout)
251 {
252 int flag_high;
253 unsigned long count = 0;
254
255 while ((flag_high = (inb(STATUS_PORT) & flag)))
256 if (++count >= timeout)
257 break;
258
259 DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
260 flag, count, flag_high ? " timeout" : ""));
261 return !flag_high;
262 }
263
264
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};
270
271
272 /* Timer routine: wake up when desired flag goes low,
273 or when timeout expires. */
sleep_timer(unsigned long data)274 static void sleep_timer(unsigned long data)
275 {
276 int flags = inb(STATUS_PORT) & FL_STDT;
277
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);
282 }
283
284
285 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
sleep_flag_low(int flag,unsigned long timeout)286 static int sleep_flag_low(int flag, unsigned long timeout)
287 {
288 int flag_high;
289
290 DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
291
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;
298 }
299
300 DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
301 flag, timeout, flag_high ? " timeout" : ""));
302 return !flag_high;
303 }
304
305 /* Low level drive interface. Only here we do actual I/O
306 Sending commands and parameters */
307
308
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
315
316
317 /* Send command code. Return <0 indicates error */
send_cmd(int cmd)318 static int send_cmd(int cmd)
319 {
320 unsigned char ack;
321
322 DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
323
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;
331 }
332
333
334 /* Send command parameters. Return <0 indicates error */
send_params(struct cdrom_msf * params)335 static int send_params(struct cdrom_msf *params)
336 {
337 unsigned char ack;
338
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));
348
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;
359 }
360
361
362 /* Send parameters for SEEK command. Return <0 indicates error */
send_seek_params(struct cdrom_msf * params)363 static int send_seek_params(struct cdrom_msf *params)
364 {
365 unsigned char ack;
366
367 DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
368 " %02x:%02x:%02x",
369 params->cdmsf_min0,
370 params->cdmsf_sec0,
371 params->cdmsf_frame0));
372
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;
380 }
381
382
383 /* Wait for command execution status. Choice between busy waiting
384 and sleeping. Return value <0 indicates timeout. */
get_exec_status(int busy_waiting)385 inline static int get_exec_status(int busy_waiting)
386 {
387 unsigned char exec_status;
388
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;
393
394 exec_status = inb(DATA_PORT);
395 DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
396 return exec_status;
397 }
398
399
400 /* Wait busy for extra byte of data that a command returns.
401 Return value <0 indicates timeout. */
get_data(int short_timeout)402 inline static int get_data(int short_timeout)
403 {
404 unsigned char data;
405
406 if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
407 return -ERR_IF_DATA_TIMEOUT;
408
409 data = inb(DATA_PORT);
410 DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
411 return data;
412 }
413
414
415 /* Returns 0 if failed */
reset_drive(void)416 static int reset_drive(void)
417 {
418 unsigned long count = 0;
419 int flags;
420
421 DEBUG((DEBUG_DRIVE_IF, "reset drive"));
422
423 outb(0, RESET_PORT);
424 while (++count < RESET_WAIT)
425 inb(DATA_PORT);
426
427 count = 0;
428 while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
429 if (++count >= BUSY_TIMEOUT)
430 break;
431
432 DEBUG((DEBUG_DRIVE_IF, "reset %s",
433 flags == FL_RESET ? "succeeded" : "failed"));
434
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 */
439 }
440
441
442 /* Facilities for asynchronous operation */
443
444 /* Read status/data availability flags FL_STEN and FL_DTEN */
stdt_flags(void)445 inline static int stdt_flags(void)
446 {
447 return inb(STATUS_PORT) & FL_STDT;
448 }
449
450
451 /* Fetch status that has previously been waited for. <0 means not available */
fetch_status(void)452 inline static int fetch_status(void)
453 {
454 unsigned char status;
455
456 if (inb(STATUS_PORT) & FL_STEN)
457 return -ERR_IF_NOSTAT;
458
459 status = inb(DATA_PORT);
460 DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
461 return status;
462 }
463
464
465 /* Fetch data that has previously been waited for. */
fetch_data(char * buf,int n)466 inline static void fetch_data(char *buf, int n)
467 {
468 insb(DATA_PORT, buf, n);
469 DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
470 }
471
472
473 /* Flush status and data fifos */
flush_data(void)474 inline static void flush_data(void)
475 {
476 while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
477 inb(DATA_PORT);
478 DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
479 }
480
481 /* Command protocol */
482
483
484 /* Send a simple command and wait for response. Command codes < COMFETCH
485 are quick response commands */
exec_cmd(int cmd)486 inline static int exec_cmd(int cmd)
487 {
488 int ack = send_cmd(cmd);
489 if (ack < 0)
490 return ack;
491 return get_exec_status(cmd < COMFETCH);
492 }
493
494
495 /* Send a command with parameters. Don't wait for the response,
496 * which consists of data blocks read from the CD. */
exec_read_cmd(int cmd,struct cdrom_msf * params)497 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
498 {
499 int ack = send_cmd(cmd);
500 if (ack < 0)
501 return ack;
502 return send_params(params);
503 }
504
505
506 /* Send a seek command with parameters and wait for response */
exec_seek_cmd(int cmd,struct cdrom_msf * params)507 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
508 {
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;
516 }
517
518
519 /* Send a command with parameters and wait for response */
exec_long_cmd(int cmd,struct cdrom_msf * params)520 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
521 {
522 int ack = exec_read_cmd(cmd, params);
523 if (ack < 0)
524 return ack;
525 return get_exec_status(0);
526 }
527
528 /* Address conversion routines */
529
530
531 /* Binary to BCD (2 digits) */
single_bin2bcd(u_char * p)532 inline static void single_bin2bcd(u_char *p)
533 {
534 DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
535 *p = (*p % 10) | ((*p / 10) << 4);
536 }
537
538
539 /* Convert entire msf struct */
bin2bcd(struct cdrom_msf * msf)540 static void bin2bcd(struct cdrom_msf *msf)
541 {
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);
548 }
549
550
551 /* Linear block address to minute, second, frame form */
552 #define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */
553
lba2msf(int lba,struct cdrom_msf * msf)554 static void lba2msf(int lba, struct cdrom_msf *msf)
555 {
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);
565 }
566
567
568 /* Two BCD digits to binary */
bcd2bin(u_char bcd)569 inline static u_char bcd2bin(u_char bcd)
570 {
571 DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
572 return (bcd >> 4) * 10 + (bcd & 0x0f);
573 }
574
575
msf2lba(union cdrom_addr * addr)576 static void msf2lba(union cdrom_addr *addr)
577 {
578 addr->lba = addr->msf.minute * CD_FPM
579 + addr->msf.second * CD_FRAMES
580 + addr->msf.frame - CD_MSF_OFFSET;
581 }
582
583
584 /* Minute, second, frame address BCD to binary or to linear address,
585 depending on MODE */
msf_bcd2bin(union cdrom_addr * addr)586 static void msf_bcd2bin(union cdrom_addr *addr)
587 {
588 addr->msf.minute = bcd2bin(addr->msf.minute);
589 addr->msf.second = bcd2bin(addr->msf.second);
590 addr->msf.frame = bcd2bin(addr->msf.frame);
591 }
592
593 /* High level drive commands */
594
595
596 static int audio_status = CDROM_AUDIO_NO_STATUS;
597 static char toc_uptodate = 0;
598 static char disk_changed = 1;
599
600 /* Get drive status, flagging completion of audio play and disk changes. */
drive_status(void)601 static int drive_status(void)
602 {
603 int status;
604
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;
611
612 if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
613 (audio_status == CDROM_AUDIO_PLAY)) {
614 audio_status = CDROM_AUDIO_COMPLETED;
615 }
616
617 if (status & ST_DSK_CHG) {
618 toc_uptodate = 0;
619 disk_changed = 1;
620 audio_status = CDROM_AUDIO_NO_STATUS;
621 }
622
623 return status;
624 }
625
626
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 */
get_q_channel(struct cdrom_subchnl * qp)630 static int get_q_channel(struct cdrom_subchnl *qp)
631 {
632 int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
633
634 status = drive_status();
635 if (status < 0)
636 return status;
637 qp->cdsc_audiostatus = audio_status;
638
639 status = exec_cmd(COMSUBQ);
640 if (status < 0)
641 return status;
642
643 d1 = get_data(0);
644 if (d1 < 0)
645 return d1;
646 qp->cdsc_adr = d1;
647 qp->cdsc_ctrl = d1 >> 4;
648
649 d2 = get_data(0);
650 if (d2 < 0)
651 return d2;
652 qp->cdsc_trk = bcd2bin(d2);
653
654 d3 = get_data(0);
655 if (d3 < 0)
656 return d3;
657 qp->cdsc_ind = bcd2bin(d3);
658
659 d4 = get_data(0);
660 if (d4 < 0)
661 return d4;
662 qp->cdsc_reladdr.msf.minute = d4;
663
664 d5 = get_data(0);
665 if (d5 < 0)
666 return d5;
667 qp->cdsc_reladdr.msf.second = d5;
668
669 d6 = get_data(0);
670 if (d6 < 0)
671 return d6;
672 qp->cdsc_reladdr.msf.frame = d6;
673
674 d7 = get_data(0);
675 if (d7 < 0)
676 return d7;
677 /* byte not used */
678
679 d8 = get_data(0);
680 if (d8 < 0)
681 return d8;
682 qp->cdsc_absaddr.msf.minute = d8;
683
684 d9 = get_data(0);
685 if (d9 < 0)
686 return d9;
687 qp->cdsc_absaddr.msf.second = d9;
688
689 d10 = get_data(0);
690 if (d10 < 0)
691 return d10;
692 qp->cdsc_absaddr.msf.frame = d10;
693
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));
696
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);
702 }
703
704 return 0;
705 }
706
707 /* Table of contents handling */
708
709
710 /* Errors in table of contents */
711 #define ERR_TOC_MISSINGINFO 0x120
712 #define ERR_TOC_MISSINGENTRY 0x121
713
714
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;
727 };
728 static struct cdrom_disk_info disk_info;
729
730 #define MAX_TRACKS 111
731 static struct cdrom_subchnl toc[MAX_TRACKS];
732
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) */
737
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)
743
744
745 #if DEBUG_TOC
toc_debug_info(int i)746 void toc_debug_info(int i)
747 {
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);
758 }
759 #endif
760
761
read_toc(void)762 static int read_toc(void)
763 {
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
770
771 DEBUG((DEBUG_TOC, "starting read_toc"));
772
773 count = 0;
774 for (limit = 60; limit > 0; limit--) {
775 int index;
776
777 q_info.cdsc_format = CDROM_MSF;
778 status = get_q_channel(&q_info);
779 if (status < 0)
780 return status;
781
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++;
789
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;
803 }
804 }
805
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;
810 }
811
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;
821 }
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
856
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;
864 }
865
866
867 #ifdef MULTISESSION
get_multi_disk_info(void)868 static int get_multi_disk_info(void)
869 {
870 int sessions, status;
871 struct cdrom_msf multi_index;
872
873
874 for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
875 int count;
876
877 for (count = 100; count < MAX_TRACKS; count++)
878 toc[count].cdsc_ind = 0;
879
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--;
888 }
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;
897
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;
903 }
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;
910 }
911
912 status = read_toc();
913 if (status < 0) {
914 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
915 break;
916 }
917
918 disk_info.multi = 1;
919 }
920
921 exec_cmd(COMSTOP);
922
923 if (status < 0)
924 return -EIO;
925 return 0;
926 }
927 #endif /* MULTISESSION */
928
929
update_toc(void)930 static int update_toc(void)
931 {
932 int status, count;
933
934 if (toc_uptodate)
935 return 0;
936
937 DEBUG((DEBUG_TOC, "starting update_toc"));
938
939 disk_info.first = 0;
940 for (count = 0; count < MAX_TRACKS; count++)
941 toc[count].cdsc_ind = 0;
942
943 status = exec_cmd(COMLEADIN);
944 if (status < 0)
945 return -EIO;
946
947 status = read_toc();
948 if (status < 0) {
949 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
950 return -EIO;
951 }
952
953 /* Audio disk detection. Look at first track. */
954 disk_info.audio =
955 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
956
957 /* XA detection */
958 disk_info.xa = drive_status() & ST_MODE2TRACK;
959
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");
969
970 DEBUG((DEBUG_TOC, "exiting update_toc"));
971
972 toc_uptodate = 1;
973 return 0;
974 }
975
976 /* Request handling */
977
978
979 #define CURRENT_VALID \
980 (!QUEUE_EMPTY && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
981 && CURRENT -> cmd == READ && CURRENT -> sector != -1)
982
983
984 /* Buffers for block size conversion. */
985 #define NOBUF -1
986
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;
990
opt_invalidate_buffers(void)991 inline static void opt_invalidate_buffers(void)
992 {
993 int i;
994
995 DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
996
997 for (i = 0; i < N_BUFS; i++)
998 buf_bn[i] = NOBUF;
999 buf_out = NOBUF;
1000 }
1001
1002
1003 /* Take care of the different block sizes between cdrom and Linux.
1004 When Linux gets variable block sizes this will probably go away. */
transfer(void)1005 static void transfer(void)
1006 {
1007 #if DEBUG_BUFFERS | DEBUG_REQUEST
1008 printk(KERN_DEBUG "optcd: executing transfer\n");
1009 #endif
1010
1011 if (!CURRENT_VALID)
1012 return;
1013 while (CURRENT -> nr_sectors) {
1014 int bn = CURRENT -> sector / 4;
1015 int i, offs, nr_sectors;
1016 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1017
1018 DEBUG((DEBUG_REQUEST, "found %d", i));
1019
1020 if (i >= N_BUFS) {
1021 buf_out = NOBUF;
1022 break;
1023 }
1024
1025 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1026 nr_sectors = 4 - (CURRENT -> sector & 3);
1027
1028 if (buf_out != i) {
1029 buf_out = i;
1030 if (buf_bn[i] != bn) {
1031 buf_out = NOBUF;
1032 continue;
1033 }
1034 }
1035
1036 if (nr_sectors > CURRENT -> nr_sectors)
1037 nr_sectors = CURRENT -> nr_sectors;
1038 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1039 CURRENT -> nr_sectors -= nr_sectors;
1040 CURRENT -> sector += nr_sectors;
1041 CURRENT -> buffer += nr_sectors * 512;
1042 }
1043 }
1044
1045
1046 /* State machine for reading disk blocks */
1047
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 */
1055 };
1056
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
1063
1064
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;
1070
1071
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;
1076
1077 static void poll(unsigned long data);
1078 static struct timer_list req_timer = {function: poll};
1079
1080
poll(unsigned long data)1081 static void poll(unsigned long data)
1082 {
1083 static volatile int read_count = 1;
1084 int flags;
1085 int loop_again = 1;
1086 int status = 0;
1087 int skip = 0;
1088
1089 if (error) {
1090 printk(KERN_ERR "optcd: I/O error 0x%02x\n", error);
1091 opt_invalidate_buffers();
1092 if (!tries--) {
1093 printk(KERN_ERR "optcd: read block %d failed;"
1094 " Giving up\n", next_bn);
1095 if (transfer_is_active)
1096 loop_again = 0;
1097 if (CURRENT_VALID)
1098 end_request(0);
1099 tries = 5;
1100 }
1101 error = 0;
1102 state = S_STOP;
1103 }
1104
1105 while (loop_again)
1106 {
1107 loop_again = 0; /* each case must flip this back to 1 if we want
1108 to come back up here */
1109
1110 #if DEBUG_STATE
1111 if (state == state_old)
1112 state_n++;
1113 else {
1114 state_old = state;
1115 if (++state_n > 1)
1116 printk(KERN_DEBUG "optcd: %ld times "
1117 "in previous state\n", state_n);
1118 printk(KERN_DEBUG "optcd: state %d\n", state);
1119 state_n = 0;
1120 }
1121 #endif
1122
1123 switch (state) {
1124 case S_IDLE:
1125 return;
1126 case S_START:
1127 if (in_vfs)
1128 break;
1129 if (send_cmd(COMDRVST)) {
1130 state = S_IDLE;
1131 while (CURRENT_VALID)
1132 end_request(0);
1133 return;
1134 }
1135 state = S_READ;
1136 timeout = READ_TIMEOUT;
1137 break;
1138 case S_READ: {
1139 struct cdrom_msf msf;
1140 if (!skip) {
1141 status = fetch_status();
1142 if (status < 0)
1143 break;
1144 if (status & ST_DSK_CHG) {
1145 toc_uptodate = 0;
1146 opt_invalidate_buffers();
1147 }
1148 }
1149 skip = 0;
1150 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1151 toc_uptodate = 0;
1152 opt_invalidate_buffers();
1153 printk(KERN_WARNING "optcd: %s\n",
1154 (status & ST_DOOR_OPEN)
1155 ? "door open"
1156 : "disk removed");
1157 state = S_IDLE;
1158 while (CURRENT_VALID)
1159 end_request(0);
1160 return;
1161 }
1162 if (!CURRENT_VALID) {
1163 state = S_STOP;
1164 loop_again = 1;
1165 break;
1166 }
1167 next_bn = CURRENT -> sector / 4;
1168 lba2msf(next_bn, &msf);
1169 read_count = N_BUFS;
1170 msf.cdmsf_frame1 = read_count; /* Not BCD! */
1171
1172 DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1173 msf.cdmsf_min0,
1174 msf.cdmsf_sec0,
1175 msf.cdmsf_frame0,
1176 msf.cdmsf_min1,
1177 msf.cdmsf_sec1,
1178 msf.cdmsf_frame1));
1179 DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1180 " buf_out:%d buf_bn:%d",
1181 next_bn,
1182 buf_in,
1183 buf_out,
1184 buf_bn[buf_in]));
1185
1186 exec_read_cmd(COMREAD, &msf);
1187 state = S_DATA;
1188 timeout = READ_TIMEOUT;
1189 break;
1190 }
1191 case S_DATA:
1192 flags = stdt_flags() & (FL_STEN|FL_DTEN);
1193
1194 #if DEBUG_STATE
1195 if (flags != flags_old) {
1196 flags_old = flags;
1197 printk(KERN_DEBUG "optcd: flags:%x\n", flags);
1198 }
1199 if (flags == FL_STEN)
1200 printk(KERN_DEBUG "timeout cnt: %d\n", timeout);
1201 #endif
1202
1203 switch (flags) {
1204 case FL_DTEN: /* 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;
1212 }
1213 if (CURRENT_VALID)
1214 end_request(0);
1215 tries = 5;
1216 }
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;
1228 }
1229 if (read_count<=0)
1230 printk(KERN_WARNING
1231 "optcd: warning - try to read"
1232 " 0 frames\n");
1233 while (read_count) {
1234 buf_bn[buf_in] = NOBUF;
1235 if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1236 /* 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;
1252 }
1253 fetch_data(buf+
1254 CD_FRAMESIZE*buf_in,
1255 CD_FRAMESIZE);
1256 read_count--;
1257
1258 DEBUG((DEBUG_REQUEST,
1259 "S_DATA; ---I've read data- "
1260 "read_count: %d",
1261 read_count));
1262 DEBUG((DEBUG_REQUEST,
1263 "next_bn:%d buf_in:%d "
1264 "buf_out:%d buf_bn:%d",
1265 next_bn,
1266 buf_in,
1267 buf_out,
1268 buf_bn[buf_in]));
1269
1270 buf_bn[buf_in] = next_bn++;
1271 if (buf_out == NOBUF)
1272 buf_out = buf_in;
1273 buf_in = buf_in + 1 ==
1274 N_BUFS ? 0 : buf_in + 1;
1275 }
1276 if (!transfer_is_active) {
1277 while (CURRENT_VALID) {
1278 transfer();
1279 if (CURRENT -> nr_sectors == 0)
1280 end_request(1);
1281 else
1282 break;
1283 }
1284 }
1285
1286 if (CURRENT_VALID
1287 && (CURRENT -> sector / 4 < next_bn ||
1288 CURRENT -> sector / 4 >
1289 next_bn + N_BUFS)) {
1290 state = S_STOP;
1291 loop_again = 1;
1292 break;
1293 }
1294 timeout = READ_TIMEOUT;
1295 if (read_count == 0) {
1296 state = S_STOP;
1297 loop_again = 1;
1298 break;
1299 }
1300 }
1301 break;
1302 case S_STOP:
1303 if (read_count != 0)
1304 printk(KERN_ERR
1305 "optcd: discard data=%x frames\n",
1306 read_count);
1307 flush_data();
1308 if (send_cmd(COMDRVST)) {
1309 state = S_IDLE;
1310 while (CURRENT_VALID)
1311 end_request(0);
1312 return;
1313 }
1314 state = S_STOPPING;
1315 timeout = STOP_TIMEOUT;
1316 break;
1317 case S_STOPPING:
1318 status = fetch_status();
1319 if (status < 0 && timeout)
1320 break;
1321 if ((status >= 0) && (status & ST_DSK_CHG)) {
1322 toc_uptodate = 0;
1323 opt_invalidate_buffers();
1324 }
1325 if (CURRENT_VALID) {
1326 if (status >= 0) {
1327 state = S_READ;
1328 loop_again = 1;
1329 skip = 1;
1330 break;
1331 } else {
1332 state = S_START;
1333 timeout = 1;
1334 }
1335 } else {
1336 state = S_IDLE;
1337 return;
1338 }
1339 break;
1340 default:
1341 printk(KERN_ERR "optcd: invalid state %d\n", state);
1342 return;
1343 } /* case */
1344 } /* while */
1345
1346 if (!timeout--) {
1347 printk(KERN_ERR "optcd: timeout in state %d\n", state);
1348 state = S_STOP;
1349 if (exec_cmd(COMSTOP) < 0) {
1350 state = S_IDLE;
1351 while (CURRENT_VALID)
1352 end_request(0);
1353 return;
1354 }
1355 }
1356
1357 mod_timer(&req_timer, jiffies + HZ/100);
1358 }
1359
1360
do_optcd_request(request_queue_t * q)1361 static void do_optcd_request(request_queue_t * q)
1362 {
1363 DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1364 CURRENT -> sector, CURRENT -> nr_sectors));
1365
1366 if (disk_info.audio) {
1367 printk(KERN_WARNING "optcd: tried to mount an Audio CD\n");
1368 end_request(0);
1369 return;
1370 }
1371
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");
1377 }
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;
1389 }
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);
1396 }
1397 break;
1398 }
1399 }
1400 transfer_is_active = 0;
1401
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"));
1405 }
1406
1407 /* IOCTLs */
1408
1409
1410 static char auto_eject = 0;
1411
cdrompause(void)1412 static int cdrompause(void)
1413 {
1414 int status;
1415
1416 if (audio_status != CDROM_AUDIO_PLAY)
1417 return -EINVAL;
1418
1419 status = exec_cmd(COMPAUSEON);
1420 if (status < 0) {
1421 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1422 return -EIO;
1423 }
1424 audio_status = CDROM_AUDIO_PAUSED;
1425 return 0;
1426 }
1427
1428
cdromresume(void)1429 static int cdromresume(void)
1430 {
1431 int status;
1432
1433 if (audio_status != CDROM_AUDIO_PAUSED)
1434 return -EINVAL;
1435
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;
1441 }
1442 audio_status = CDROM_AUDIO_PLAY;
1443 return 0;
1444 }
1445
1446
cdromplaymsf(unsigned long arg)1447 static int cdromplaymsf(unsigned long arg)
1448 {
1449 int status;
1450 struct cdrom_msf msf;
1451
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);
1456
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;
1463 }
1464
1465 audio_status = CDROM_AUDIO_PLAY;
1466 return 0;
1467 }
1468
1469
cdromplaytrkind(unsigned long arg)1470 static int cdromplaytrkind(unsigned long arg)
1471 {
1472 int status;
1473 struct cdrom_ti ti;
1474 struct cdrom_msf msf;
1475
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);
1480
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;
1487
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;
1494
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));
1502
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;
1509 }
1510
1511 audio_status = CDROM_AUDIO_PLAY;
1512 return 0;
1513 }
1514
1515
cdromreadtochdr(unsigned long arg)1516 static int cdromreadtochdr(unsigned long arg)
1517 {
1518 int status;
1519 struct cdrom_tochdr tochdr;
1520
1521 status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1522 if (status)
1523 return status;
1524
1525 tochdr.cdth_trk0 = disk_info.first;
1526 tochdr.cdth_trk1 = disk_info.last;
1527
1528 copy_to_user((void *) arg, &tochdr, sizeof tochdr);
1529 return 0;
1530 }
1531
1532
cdromreadtocentry(unsigned long arg)1533 static int cdromreadtocentry(unsigned long arg)
1534 {
1535 int status;
1536 struct cdrom_tocentry entry;
1537 struct cdrom_subchnl *tocptr;
1538
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);
1543
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];
1551
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? */
1558
1559 if (entry.cdte_format == CDROM_LBA)
1560 msf2lba(&entry.cdte_addr);
1561 else if (entry.cdte_format != CDROM_MSF)
1562 return -EINVAL;
1563
1564 copy_to_user((void *) arg, &entry, sizeof entry);
1565 return 0;
1566 }
1567
1568
cdromvolctrl(unsigned long arg)1569 static int cdromvolctrl(unsigned long arg)
1570 {
1571 int status;
1572 struct cdrom_volctrl volctrl;
1573 struct cdrom_msf msf;
1574
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);
1579
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;
1586
1587 status = exec_long_cmd(COMCHCTRL, &msf);
1588 if (status < 0) {
1589 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1590 return -EIO;
1591 }
1592 return 0;
1593 }
1594
1595
cdromsubchnl(unsigned long arg)1596 static int cdromsubchnl(unsigned long arg)
1597 {
1598 int status;
1599 struct cdrom_subchnl subchnl;
1600
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);
1605
1606 if (subchnl.cdsc_format != CDROM_LBA
1607 && subchnl.cdsc_format != CDROM_MSF)
1608 return -EINVAL;
1609
1610 status = get_q_channel(&subchnl);
1611 if (status < 0) {
1612 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1613 return -EIO;
1614 }
1615
1616 copy_to_user((void *) arg, &subchnl, sizeof subchnl);
1617 return 0;
1618 }
1619
1620
cdromread(unsigned long arg,int blocksize,int cmd)1621 static int cdromread(unsigned long arg, int blocksize, int cmd)
1622 {
1623 int status;
1624 struct cdrom_msf msf;
1625 char buf[CD_FRAMESIZE_RAWER];
1626
1627 status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1628 if (status)
1629 return status;
1630 copy_from_user(&msf, (void *) arg, sizeof msf);
1631
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);
1637
1638 DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1639
1640 if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1641 return -EIO;
1642 fetch_data(buf, blocksize);
1643
1644 copy_to_user((void *) arg, &buf, blocksize);
1645 return 0;
1646 }
1647
1648
cdromseek(unsigned long arg)1649 static int cdromseek(unsigned long arg)
1650 {
1651 int status;
1652 struct cdrom_msf msf;
1653
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);
1658
1659 bin2bcd(&msf);
1660 status = exec_seek_cmd(COMSEEK, &msf);
1661
1662 DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1663
1664 if (status < 0)
1665 return -EIO;
1666 return 0;
1667 }
1668
1669
1670 #ifdef MULTISESSION
cdrommultisession(unsigned long arg)1671 static int cdrommultisession(unsigned long arg)
1672 {
1673 int status;
1674 struct cdrom_multisession ms;
1675
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);
1680
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;
1684
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);
1690
1691 ms.xa_flag = disk_info.xa;
1692
1693 copy_to_user((void*) arg, &ms,
1694 sizeof(struct cdrom_multisession));
1695
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 */
1713
1714 return 0;
1715 }
1716 #endif /* MULTISESSION */
1717
1718
cdromreset(void)1719 static int cdromreset(void)
1720 {
1721 if (state != S_IDLE) {
1722 error = 1;
1723 tries = 0;
1724 }
1725
1726 toc_uptodate = 0;
1727 disk_changed = 1;
1728 opt_invalidate_buffers();
1729 audio_status = CDROM_AUDIO_NO_STATUS;
1730
1731 if (!reset_drive())
1732 return -EIO;
1733 return 0;
1734 }
1735
1736 /* VFS calls */
1737
1738
opt_ioctl(struct inode * ip,struct file * fp,unsigned int cmd,unsigned long arg)1739 static int opt_ioctl(struct inode *ip, struct file *fp,
1740 unsigned int cmd, unsigned long arg)
1741 {
1742 int status, err, retval = 0;
1743
1744 DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1745
1746 if (!ip)
1747 return -EINVAL;
1748
1749 if (cmd == CDROMRESET)
1750 return cdromreset();
1751
1752 /* is do_optcd_request or another ioctl busy? */
1753 if (state != S_IDLE || in_vfs)
1754 return -EBUSY;
1755
1756 in_vfs = 1;
1757
1758 status = drive_status();
1759 if (status < 0) {
1760 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1761 in_vfs = 0;
1762 return -EIO;
1763 }
1764
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;
1775 }
1776 break;
1777 default: in_vfs = 0;
1778 return -EBUSY;
1779 }
1780
1781 err = update_toc();
1782 if (err < 0) {
1783 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1784 in_vfs = 0;
1785 return -EIO;
1786 }
1787
1788 DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1789
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;
1797
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;
1815 }
1816 err = exec_cmd(COMOPEN);
1817 if (err < 0) {
1818 DEBUG((DEBUG_VFS,
1819 "exec_cmd COMOPEN: %02x",
1820 -err));
1821 retval = -EIO;
1822 }
1823 break;
1824
1825 case CDROMVOLCTRL: retval = cdromvolctrl(arg); break;
1826 case CDROMSUBCHNL: retval = cdromsubchnl(arg); break;
1827
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;
1832
1833 /* Drive doesn't support reading audio */
1834 case CDROMREADAUDIO: retval = -EINVAL; break;
1835
1836 case CDROMEJECT_SW: auto_eject = (char) arg;
1837 break;
1838
1839 #ifdef MULTISESSION
1840 case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1841 #endif
1842
1843 case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */
1844 case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */
1845
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;
1856
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;
1861 }
1862 in_vfs = 0;
1863 return retval;
1864 }
1865
1866
1867 static int open_count = 0;
1868
1869 /* Open device special file; check that a disk is in. */
opt_open(struct inode * ip,struct file * fp)1870 static int opt_open(struct inode *ip, struct file *fp)
1871 {
1872 DEBUG((DEBUG_VFS, "starting opt_open"));
1873
1874 if (!open_count && state == S_IDLE) {
1875 int status;
1876
1877 toc_uptodate = 0;
1878 opt_invalidate_buffers();
1879
1880 status = exec_cmd(COMCLOSE); /* close door */
1881 if (status < 0) {
1882 DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1883 }
1884
1885 status = drive_status();
1886 if (status < 0) {
1887 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1888 goto err_out;
1889 }
1890 DEBUG((DEBUG_VFS, "status: %02x", status));
1891 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1892 printk(KERN_INFO "optcd: no disk or door open\n");
1893 goto err_out;
1894 }
1895 status = exec_cmd(COMLOCK); /* Lock door */
1896 if (status < 0) {
1897 DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1898 }
1899 status = update_toc(); /* Read table of contents */
1900 if (status < 0) {
1901 DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1902 status = exec_cmd(COMUNLOCK); /* Unlock door */
1903 if (status < 0) {
1904 DEBUG((DEBUG_VFS,
1905 "exec_cmd COMUNLOCK: %02x", -status));
1906 }
1907 goto err_out;
1908 }
1909 open_count++;
1910 }
1911
1912 DEBUG((DEBUG_VFS, "exiting opt_open"));
1913
1914 return 0;
1915
1916 err_out:
1917 return -EIO;
1918 }
1919
1920
1921 /* Release device special file; flush all blocks from the buffer cache */
opt_release(struct inode * ip,struct file * fp)1922 static int opt_release(struct inode *ip, struct file *fp)
1923 {
1924 int status;
1925
1926 DEBUG((DEBUG_VFS, "executing opt_release"));
1927 DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1928 ip, ip -> i_rdev, fp));
1929
1930 if (!--open_count) {
1931 toc_uptodate = 0;
1932 opt_invalidate_buffers();
1933 status = exec_cmd(COMUNLOCK); /* Unlock door */
1934 if (status < 0) {
1935 DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1936 }
1937 if (auto_eject) {
1938 status = exec_cmd(COMOPEN);
1939 DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1940 }
1941 del_timer(&delay_timer);
1942 del_timer(&req_timer);
1943 }
1944 return 0;
1945 }
1946
1947
1948 /* Check if disk has been changed */
opt_media_change(kdev_t dev)1949 static int opt_media_change(kdev_t dev)
1950 {
1951 DEBUG((DEBUG_VFS, "executing opt_media_change"));
1952 DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1953
1954 if (disk_changed) {
1955 disk_changed = 0;
1956 return 1;
1957 }
1958 return 0;
1959 }
1960
1961 /* Driver initialisation */
1962
1963
1964 /* Returns 1 if a drive is detected with a version string
1965 starting with "DOLPHIN". Otherwise 0. */
version_ok(void)1966 static int __init version_ok(void)
1967 {
1968 char devname[100];
1969 int count, i, ch, status;
1970
1971 status = exec_cmd(COMVERSION);
1972 if (status < 0) {
1973 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1974 return 0;
1975 }
1976 if ((count = get_data(1)) < 0) {
1977 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1978 return 0;
1979 }
1980 for (i = 0, ch = -1; count > 0; count--) {
1981 if ((ch = get_data(1)) < 0) {
1982 DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1983 break;
1984 }
1985 if (i < 99)
1986 devname[i++] = ch;
1987 }
1988 devname[i] = '\0';
1989 if (ch < 0)
1990 return 0;
1991
1992 printk(KERN_INFO "optcd: Device %s detected\n", devname);
1993 return ((devname[0] == 'D')
1994 && (devname[1] == 'O')
1995 && (devname[2] == 'L')
1996 && (devname[3] == 'P')
1997 && (devname[4] == 'H')
1998 && (devname[5] == 'I')
1999 && (devname[6] == 'N'));
2000 }
2001
2002
2003 static struct block_device_operations opt_fops = {
2004 owner: THIS_MODULE,
2005 open: opt_open,
2006 release: opt_release,
2007 ioctl: opt_ioctl,
2008 check_media_change: opt_media_change,
2009 };
2010
2011 #ifndef MODULE
2012 /* Get kernel parameter when used as a kernel driver */
optcd_setup(char * str)2013 static int optcd_setup(char *str)
2014 {
2015 int ints[4];
2016 (void)get_options(str, ARRAY_SIZE(ints), ints);
2017
2018 if (ints[0] > 0)
2019 optcd_port = ints[1];
2020
2021 return 1;
2022 }
2023
2024 __setup("optcd=", optcd_setup);
2025
2026 #endif /* MODULE */
2027
2028 /* Test for presence of drive and initialize it. Called at boot time
2029 or during module initialisation. */
optcd_init(void)2030 int __init optcd_init(void)
2031 {
2032 int status;
2033
2034 if (optcd_port <= 0) {
2035 printk(KERN_INFO
2036 "optcd: no Optics Storage CDROM Initialization\n");
2037 return -EIO;
2038 }
2039 if (check_region(optcd_port, 4)) {
2040 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2041 optcd_port);
2042 return -EIO;
2043 }
2044
2045 if (!reset_drive()) {
2046 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2047 return -EIO;
2048 }
2049 if (!version_ok()) {
2050 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2051 return -EIO;
2052 }
2053 status = exec_cmd(COMINITDOUBLE);
2054 if (status < 0) {
2055 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2056 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2057 return -EIO;
2058 }
2059 if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2060 {
2061 printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2062 return -EIO;
2063 }
2064 devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
2065 S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
2066 hardsect_size[MAJOR_NR] = &hsecsize;
2067 blksize_size[MAJOR_NR] = &blksize;
2068 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
2069 read_ahead[MAJOR_NR] = 4;
2070 request_region(optcd_port, 4, "optcd");
2071 register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);
2072
2073 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2074 return 0;
2075 }
2076
2077
optcd_exit(void)2078 void __exit optcd_exit(void)
2079 {
2080 devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,
2081 DEVFS_SPECIAL_BLK, 0));
2082 if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2083 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2084 return;
2085 }
2086 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
2087 release_region(optcd_port, 4);
2088 printk(KERN_INFO "optcd: module released.\n");
2089 }
2090
2091 #ifdef MODULE
2092 module_init(optcd_init);
2093 #endif
2094 module_exit(optcd_exit);
2095
2096
2097 MODULE_LICENSE("GPL");
2098