~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/cdrom/optcd.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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
 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. */
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 
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 
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 
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 
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 
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 
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 
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 
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         MOD_INC_USE_COUNT;
1875 
1876         if (!open_count && state == S_IDLE) {
1877                 int status;
1878 
1879                 toc_uptodate = 0;
1880                 opt_invalidate_buffers();
1881 
1882                 status = exec_cmd(COMCLOSE);    /* close door */
1883                 if (status < 0) {
1884                         DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1885                 }
1886 
1887                 status = drive_status();
1888                 if (status < 0) {
1889                         DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1890                         goto err_out;
1891                 }
1892                 DEBUG((DEBUG_VFS, "status: %02x", status));
1893                 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1894                         printk(KERN_INFO "optcd: no disk or door open\n");
1895                         goto err_out;
1896                 }
1897                 status = exec_cmd(COMLOCK);             /* Lock door */
1898                 if (status < 0) {
1899                         DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1900                 }
1901                 status = update_toc();  /* Read table of contents */
1902                 if (status < 0) {
1903                         DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1904                         status = exec_cmd(COMUNLOCK);   /* Unlock door */
1905                         if (status < 0) {
1906                                 DEBUG((DEBUG_VFS,
1907                                        "exec_cmd COMUNLOCK: %02x", -status));
1908                         }
1909                         goto err_out;
1910                 }
1911                 open_count++;
1912         }
1913 
1914         DEBUG((DEBUG_VFS, "exiting opt_open"));
1915 
1916         return 0;
1917 
1918 err_out:
1919     MOD_DEC_USE_COUNT;
1920         return -EIO;
1921 }
1922 
1923 
1924 /* Release device special file; flush all blocks from the buffer cache */
1925 static int opt_release(struct inode *ip, struct file *fp)
1926 {
1927         int status;
1928 
1929         DEBUG((DEBUG_VFS, "executing opt_release"));
1930         DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1931                 ip, ip -> i_rdev, fp));
1932 
1933         if (!--open_count) {
1934                 toc_uptodate = 0;
1935                 opt_invalidate_buffers();
1936                 status = exec_cmd(COMUNLOCK);   /* Unlock door */
1937                 if (status < 0) {
1938                         DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1939                 }
1940                 if (auto_eject) {
1941                         status = exec_cmd(COMOPEN);
1942                         DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1943                 }
1944                 del_timer(&delay_timer);
1945                 del_timer(&req_timer);
1946         }
1947         MOD_DEC_USE_COUNT;
1948         return 0;
1949 }
1950 
1951 
1952 /* Check if disk has been changed */
1953 static int opt_media_change(kdev_t dev)
1954 {
1955         DEBUG((DEBUG_VFS, "executing opt_media_change"));
1956         DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1957 
1958         if (disk_changed) {
1959                 disk_changed = 0;
1960                 return 1;
1961         }
1962         return 0;
1963 }
1964 
1965 /* Driver initialisation */
1966 
1967 
1968 /* Returns 1 if a drive is detected with a version string
1969    starting with "DOLPHIN". Otherwise 0. */
1970 static int __init version_ok(void)
1971 {
1972         char devname[100];
1973         int count, i, ch, status;
1974 
1975         status = exec_cmd(COMVERSION);
1976         if (status < 0) {
1977                 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1978                 return 0;
1979         }
1980         if ((count = get_data(1)) < 0) {
1981                 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1982                 return 0;
1983         }
1984         for (i = 0, ch = -1; count > 0; count--) {
1985                 if ((ch = get_data(1)) < 0) {
1986                         DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1987                         break;
1988                 }
1989                 if (i < 99)
1990                         devname[i++] = ch;
1991         }
1992         devname[i] = '\0';
1993         if (ch < 0)
1994                 return 0;
1995 
1996         printk(KERN_INFO "optcd: Device %s detected\n", devname);
1997         return ((devname[0] == 'D')
1998              && (devname[1] == 'O')
1999              && (devname[2] == 'L')
2000              && (devname[3] == 'P')
2001              && (devname[4] == 'H')
2002              && (devname[5] == 'I')
2003              && (devname[6] == 'N'));
2004 }
2005 
2006 
2007 static struct block_device_operations opt_fops = {
2008         open:                   opt_open,
2009         release:                opt_release,
2010         ioctl:                  opt_ioctl,
2011         check_media_change:     opt_media_change,
2012 };
2013 
2014 #ifndef MODULE
2015 /* Get kernel parameter when used as a kernel driver */
2016 static int optcd_setup(char *str)
2017 {
2018         int ints[4];
2019         (void)get_options(str, ARRAY_SIZE(ints), ints);
2020         
2021         if (ints[0] > 0)
2022                 optcd_port = ints[1];
2023 
2024         return 1;
2025 }
2026 
2027 __setup("optcd=", optcd_setup);
2028 
2029 #endif MODULE
2030 
2031 /* Test for presence of drive and initialize it. Called at boot time
2032    or during module initialisation. */
2033 int __init optcd_init(void)
2034 {
2035         int status;
2036 
2037         if (optcd_port <= 0) {
2038                 printk(KERN_INFO
2039                         "optcd: no Optics Storage CDROM Initialization\n");
2040                 return -EIO;
2041         }
2042         if (check_region(optcd_port, 4)) {
2043                 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2044                         optcd_port);
2045                 return -EIO;
2046         }
2047 
2048         if (!reset_drive()) {
2049                 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2050                 return -EIO;
2051         }
2052         if (!version_ok()) {
2053                 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2054                 return -EIO;
2055         }
2056         status = exec_cmd(COMINITDOUBLE);
2057         if (status < 0) {
2058                 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2059                 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2060                 return -EIO;
2061         }
2062         if (devfs_register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2063         {
2064                 printk(KERN_ERR "optcd: unable to get major %d\n", MAJOR_NR);
2065                 return -EIO;
2066         }
2067         devfs_register (NULL, "optcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
2068                         S_IFBLK | S_IRUGO | S_IWUGO, &opt_fops, NULL);
2069         hardsect_size[MAJOR_NR] = &hsecsize;
2070         blksize_size[MAJOR_NR] = &blksize;
2071         blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
2072         read_ahead[MAJOR_NR] = 4;
2073         request_region(optcd_port, 4, "optcd");
2074         register_disk(NULL, MKDEV(MAJOR_NR,0), 1, &opt_fops, 0);
2075 
2076         printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2077         return 0;
2078 }
2079 
2080 
2081 void __exit optcd_exit(void)
2082 {
2083         devfs_unregister(devfs_find_handle(NULL, "optcd", 0, 0,
2084                                            DEVFS_SPECIAL_BLK, 0));
2085         if (devfs_unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2086                 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2087                 return;
2088         }
2089         blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
2090         release_region(optcd_port, 4);
2091         printk(KERN_INFO "optcd: module released.\n");
2092 }
2093 
2094 #ifdef MODULE
2095 module_init(optcd_init);
2096 #endif
2097 module_exit(optcd_exit);
2098 
2099 
2100 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.