added mtd driver
[linux-2.4.git] / drivers / cdrom / optcd.c
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 \f
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 \f
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 \f
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
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 \f
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 \f
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. */
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. */
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. */
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 \f
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 */
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 */
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 */
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. */
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. */
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 */
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 */
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 */
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. */
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 */
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 \f
481 /* Command protocol */
482
483
484 /* Send a simple command and wait for response. Command codes < COMFETCH
485    are quick response commands */
486 inline static int exec_cmd(int cmd)
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. */
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 */
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 */
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 \f
528 /* Address conversion routines */
529
530
531 /* Binary to BCD (2 digits) */
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 */
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
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 */
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
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 */
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 \f
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. */
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 */
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 \f
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
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
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
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
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 \f
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
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. */
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
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
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 \f
1407 /* IOCTLs */
1408
1409
1410 static char auto_eject = 0;
1411
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
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
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
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
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
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
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
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
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
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
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
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 \f
1736 /* VFS calls */
1737
1738
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. */
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 */
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 */
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 \f
1961 /* Driver initialisation */
1962
1963
1964 /* Returns 1 if a drive is detected with a version string
1965    starting with "DOLPHIN". Otherwise 0. */
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 */
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. */
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
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");