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