Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
 75 #include <asm/io.h>
 76 #include <linux/blkdev.h>
 77 
 78 #include <linux/cdrom.h>
 79 #include "optcd.h"
 80 
 81 #include <asm/uaccess.h>
 82 
 83 #define MAJOR_NR OPTICS_CDROM_MAJOR
 84 #define QUEUE (opt_queue)
 85 #define CURRENT elv_next_request(opt_queue)
 86 
 87 
 88 /* Debug support */
 89 
 90 
 91 /* Don't forget to add new debug flags here. */
 92 #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
 93     DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
 94 #define DEBUG(x) debug x
 95 static void debug(int debug_this, const char* fmt, ...)
 96 {
 97         char s[1024];
 98         va_list args;
 99 
100         if (!debug_this)
101                 return;
102 
103         va_start(args, fmt);
104         vsprintf(s, fmt, args);
105         printk(KERN_DEBUG "optcd: %s\n", s);
106         va_end(args);
107 }
108 #else
109 #define DEBUG(x)
110 #endif
111 
112 
113 /* Drive hardware/firmware characteristics
114    Identifiers in accordance with Optics Storage documentation */
115 
116 
117 #define optcd_port optcd                        /* Needed for the modutils. */
118 static short optcd_port = OPTCD_PORTBASE;       /* I/O base of drive. */
119 module_param(optcd_port, short, 0);
120 /* Drive registers, read */
121 #define DATA_PORT       optcd_port      /* Read data/status */
122 #define STATUS_PORT     optcd_port+1    /* Indicate data/status availability */
123 
124 /* Drive registers, write */
125 #define COMIN_PORT      optcd_port      /* For passing command/parameter */
126 #define RESET_PORT      optcd_port+1    /* Write anything and wait 0.5 sec */
127 #define HCON_PORT       optcd_port+2    /* Host Xfer Configuration */
128 
129 
130 /* Command completion/status read from DATA register */
131 #define ST_DRVERR               0x80
132 #define ST_DOOR_OPEN            0x40
133 #define ST_MIXEDMODE_DISK       0x20
134 #define ST_MODE_BITS            0x1c
135 #define ST_M_STOP               0x00
136 #define ST_M_READ               0x04
137 #define ST_M_AUDIO              0x04
138 #define ST_M_PAUSE              0x08
139 #define ST_M_INITIAL            0x0c
140 #define ST_M_ERROR              0x10
141 #define ST_M_OTHERS             0x14
142 #define ST_MODE2TRACK           0x02
143 #define ST_DSK_CHG              0x01
144 #define ST_L_LOCK               0x01
145 #define ST_CMD_OK               0x00
146 #define ST_OP_OK                0x01
147 #define ST_PA_OK                0x02
148 #define ST_OP_ERROR             0x05
149 #define ST_PA_ERROR             0x06
150 
151 
152 /* Error codes (appear as command completion code from DATA register) */
153 /* Player related errors */
154 #define ERR_ILLCMD      0x11    /* Illegal command to player module */
155 #define ERR_ILLPARM     0x12    /* Illegal parameter to player module */
156 #define ERR_SLEDGE      0x13
157 #define ERR_FOCUS       0x14
158 #define ERR_MOTOR       0x15
159 #define ERR_RADIAL      0x16
160 #define ERR_PLL         0x17    /* PLL lock error */
161 #define ERR_SUB_TIM     0x18    /* Subcode timeout error */
162 #define ERR_SUB_NF      0x19    /* Subcode not found error */
163 #define ERR_TRAY        0x1a
164 #define ERR_TOC         0x1b    /* Table of Contents read error */
165 #define ERR_JUMP        0x1c
166 /* Data errors */
167 #define ERR_MODE        0x21
168 #define ERR_FORM        0x22
169 #define ERR_HEADADDR    0x23    /* Header Address not found */
170 #define ERR_CRC         0x24
171 #define ERR_ECC         0x25    /* Uncorrectable ECC error */
172 #define ERR_CRC_UNC     0x26    /* CRC error and uncorrectable error */
173 #define ERR_ILLBSYNC    0x27    /* Illegal block sync error */
174 #define ERR_VDST        0x28    /* VDST not found */
175 /* Timeout errors */
176 #define ERR_READ_TIM    0x31    /* Read timeout error */
177 #define ERR_DEC_STP     0x32    /* Decoder stopped */
178 #define ERR_DEC_TIM     0x33    /* Decoder interrupt timeout error */
179 /* Function abort codes */
180 #define ERR_KEY         0x41    /* Key -Detected abort */
181 #define ERR_READ_FINISH 0x42    /* Read Finish */
182 /* Second Byte diagnostic codes */
183 #define ERR_NOBSYNC     0x01    /* No block sync */
184 #define ERR_SHORTB      0x02    /* Short block */
185 #define ERR_LONGB       0x03    /* Long block */
186 #define ERR_SHORTDSP    0x04    /* Short DSP word */
187 #define ERR_LONGDSP     0x05    /* Long DSP word */
188 
189 
190 /* Status availability flags read from STATUS register */
191 #define FL_EJECT        0x20
192 #define FL_WAIT         0x10    /* active low */
193 #define FL_EOP          0x08    /* active low */
194 #define FL_STEN         0x04    /* Status available when low */
195 #define FL_DTEN         0x02    /* Data available when low */
196 #define FL_DRQ          0x01    /* active low */
197 #define FL_RESET        0xde    /* These bits are high after a reset */
198 #define FL_STDT         (FL_STEN|FL_DTEN)
199 
200 
201 /* Transfer mode, written to HCON register */
202 #define HCON_DTS        0x08
203 #define HCON_SDRQB      0x04
204 #define HCON_LOHI       0x02
205 #define HCON_DMA16      0x01
206 
207 
208 /* Drive command set, written to COMIN register */
209 /* Quick response commands */
210 #define COMDRVST        0x20    /* Drive Status Read */
211 #define COMERRST        0x21    /* Error Status Read */
212 #define COMIOCTLISTAT   0x22    /* Status Read; reset disk changed bit */
213 #define COMINITSINGLE   0x28    /* Initialize Single Speed */
214 #define COMINITDOUBLE   0x29    /* Initialize Double Speed */
215 #define COMUNLOCK       0x30    /* Unlock */
216 #define COMLOCK         0x31    /* Lock */
217 #define COMLOCKST       0x32    /* Lock/Unlock Status */
218 #define COMVERSION      0x40    /* Get Firmware Revision */
219 #define COMVOIDREADMODE 0x50    /* Void Data Read Mode */
220 /* Read commands */
221 #define COMFETCH        0x60    /* Prefetch Data */
222 #define COMREAD         0x61    /* Read */
223 #define COMREADRAW      0x62    /* Read Raw Data */
224 #define COMREADALL      0x63    /* Read All 2646 Bytes */
225 /* Player control commands */
226 #define COMLEADIN       0x70    /* Seek To Lead-in */
227 #define COMSEEK         0x71    /* Seek */
228 #define COMPAUSEON      0x80    /* Pause On */
229 #define COMPAUSEOFF     0x81    /* Pause Off */
230 #define COMSTOP         0x82    /* Stop */
231 #define COMOPEN         0x90    /* Open Tray Door */
232 #define COMCLOSE        0x91    /* Close Tray Door */
233 #define COMPLAY         0xa0    /* Audio Play */
234 #define COMPLAY_TNO     0xa2    /* Audio Play By Track Number */
235 #define COMSUBQ         0xb0    /* Read Sub-q Code */
236 #define COMLOCATION     0xb1    /* Read Head Position */
237 /* Audio control commands */
238 #define COMCHCTRL       0xc0    /* Audio Channel Control */
239 /* Miscellaneous (test) commands */
240 #define COMDRVTEST      0xd0    /* Write Test Bytes */
241 #define COMTEST         0xd1    /* Diagnostic Test */
242 
243 /* Low level drive interface. Only here we do actual I/O
244    Waiting for status / data available */
245 
246 
247 /* Busy wait until FLAG goes low. Return 0 on timeout. */
248 inline static int flag_low(int flag, unsigned long timeout)
249 {
250         int flag_high;
251         unsigned long count = 0;
252 
253         while ((flag_high = (inb(STATUS_PORT) & flag)))
254                 if (++count >= timeout)
255                         break;
256 
257         DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
258                 flag, count, flag_high ? " timeout" : ""));
259         return !flag_high;
260 }
261 
262 
263 /* Timed waiting for status or data */
264 static int sleep_timeout;       /* max # of ticks to sleep */
265 static DECLARE_WAIT_QUEUE_HEAD(waitq);
266 static void sleep_timer(unsigned long data);
267 static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0);
268 static DEFINE_SPINLOCK(optcd_lock);
269 static struct request_queue *opt_queue;
270 
271 /* Timer routine: wake up when desired flag goes low,
272    or when timeout expires. */
273 static void sleep_timer(unsigned long data)
274 {
275         int flags = inb(STATUS_PORT) & FL_STDT;
276 
277         if (flags == FL_STDT && --sleep_timeout > 0) {
278                 mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */
279         } else
280                 wake_up(&waitq);
281 }
282 
283 
284 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
285 static int sleep_flag_low(int flag, unsigned long timeout)
286 {
287         int flag_high;
288 
289         DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
290 
291         sleep_timeout = timeout;
292         flag_high = inb(STATUS_PORT) & flag;
293         if (flag_high && sleep_timeout > 0) {
294                 mod_timer(&delay_timer, jiffies + HZ/100);
295                 sleep_on(&waitq);
296                 flag_high = inb(STATUS_PORT) & flag;
297         }
298 
299         DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
300                 flag, timeout, flag_high ? " timeout" : ""));
301         return !flag_high;
302 }
303 
304 /* Low level drive interface. Only here we do actual I/O
305    Sending commands and parameters */
306 
307 
308 /* Errors in the command protocol */
309 #define ERR_IF_CMD_TIMEOUT      0x100
310 #define ERR_IF_ERR_TIMEOUT      0x101
311 #define ERR_IF_RESP_TIMEOUT     0x102
312 #define ERR_IF_DATA_TIMEOUT     0x103
313 #define ERR_IF_NOSTAT           0x104
314 
315 
316 /* Send command code. Return <0 indicates error */
317 static int send_cmd(int cmd)
318 {
319         unsigned char ack;
320 
321         DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
322 
323         outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
324         outb(cmd, COMIN_PORT);          /* Send command code */
325         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
326                 return -ERR_IF_CMD_TIMEOUT;
327         ack = inb(DATA_PORT);           /* read command acknowledge */
328         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
329         return ack==ST_OP_OK ? 0 : -ack;
330 }
331 
332 
333 /* Send command parameters. Return <0 indicates error */
334 static int send_params(struct cdrom_msf *params)
335 {
336         unsigned char ack;
337 
338         DEBUG((DEBUG_DRIVE_IF, "sending parameters"
339                 " %02x:%02x:%02x"
340                 " %02x:%02x:%02x",
341                 params->cdmsf_min0,
342                 params->cdmsf_sec0,
343                 params->cdmsf_frame0,
344                 params->cdmsf_min1,
345                 params->cdmsf_sec1,
346                 params->cdmsf_frame1));
347 
348         outb(params->cdmsf_min0, COMIN_PORT);
349         outb(params->cdmsf_sec0, COMIN_PORT);
350         outb(params->cdmsf_frame0, COMIN_PORT);
351         outb(params->cdmsf_min1, COMIN_PORT);
352         outb(params->cdmsf_sec1, COMIN_PORT);
353         outb(params->cdmsf_frame1, COMIN_PORT);
354         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
355                 return -ERR_IF_CMD_TIMEOUT;
356         ack = inb(DATA_PORT);           /* read command acknowledge */
357         return ack==ST_PA_OK ? 0 : -ack;
358 }
359 
360 
361 /* Send parameters for SEEK command. Return <0 indicates error */
362 static int send_seek_params(struct cdrom_msf *params)
363 {
364         unsigned char ack;
365 
366         DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
367                 " %02x:%02x:%02x",
368                 params->cdmsf_min0,
369                 params->cdmsf_sec0,
370                 params->cdmsf_frame0));
371 
372         outb(params->cdmsf_min0, COMIN_PORT);
373         outb(params->cdmsf_sec0, COMIN_PORT);
374         outb(params->cdmsf_frame0, COMIN_PORT);
375         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
376                 return -ERR_IF_CMD_TIMEOUT;
377         ack = inb(DATA_PORT);           /* read command acknowledge */
378         return ack==ST_PA_OK ? 0 : -ack;
379 }
380 
381 
382 /* Wait for command execution status. Choice between busy waiting
383    and sleeping. Return value <0 indicates timeout. */
384 inline static int get_exec_status(int busy_waiting)
385 {
386         unsigned char exec_status;
387 
388         if (busy_waiting
389             ? !flag_low(FL_STEN, BUSY_TIMEOUT)
390             : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
391                 return -ERR_IF_CMD_TIMEOUT;
392 
393         exec_status = inb(DATA_PORT);
394         DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
395         return exec_status;
396 }
397 
398 
399 /* Wait busy for extra byte of data that a command returns.
400    Return value <0 indicates timeout. */
401 inline static int get_data(int short_timeout)
402 {
403         unsigned char data;
404 
405         if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
406                 return -ERR_IF_DATA_TIMEOUT;
407 
408         data = inb(DATA_PORT);
409         DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
410         return data;
411 }
412 
413 
414 /* Returns 0 if failed */
415 static int reset_drive(void)
416 {
417         unsigned long count = 0;
418         int flags;
419 
420         DEBUG((DEBUG_DRIVE_IF, "reset drive"));
421 
422         outb(0, RESET_PORT);
423         while (++count < RESET_WAIT)
424                 inb(DATA_PORT);
425 
426         count = 0;
427         while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
428                 if (++count >= BUSY_TIMEOUT)
429                         break;
430 
431         DEBUG((DEBUG_DRIVE_IF, "reset %s",
432                 flags == FL_RESET ? "succeeded" : "failed"));
433 
434         if (flags != FL_RESET)
435                 return 0;               /* Reset failed */
436         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
437         return 1;                       /* Reset succeeded */
438 }
439 
440 
441 /* Facilities for asynchronous operation */
442 
443 /* Read status/data availability flags FL_STEN and FL_DTEN */
444 inline static int stdt_flags(void)
445 {
446         return inb(STATUS_PORT) & FL_STDT;
447 }
448 
449 
450 /* Fetch status that has previously been waited for. <0 means not available */
451 inline static int fetch_status(void)
452 {
453         unsigned char status;
454 
455         if (inb(STATUS_PORT) & FL_STEN)
456                 return -ERR_IF_NOSTAT;
457 
458         status = inb(DATA_PORT);
459         DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
460         return status;
461 }
462 
463 
464 /* Fetch data that has previously been waited for. */
465 inline static void fetch_data(char *buf, int n)
466 {
467         insb(DATA_PORT, buf, n);
468         DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
469 }
470 
471 
472 /* Flush status and data fifos */
473 inline static void flush_data(void)
474 {
475         while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
476                 inb(DATA_PORT);
477         DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
478 }
479 
480 /* Command protocol */
481 
482 
483 /* Send a simple command and wait for response. Command codes < COMFETCH
484    are quick response commands */
485 inline static int exec_cmd(int cmd)
486 {
487         int ack = send_cmd(cmd);
488         if (ack < 0)
489                 return ack;
490         return get_exec_status(cmd < COMFETCH);
491 }
492 
493 
494 /* Send a command with parameters. Don't wait for the response,
495  * which consists of data blocks read from the CD. */
496 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
497 {
498         int ack = send_cmd(cmd);
499         if (ack < 0)
500                 return ack;
501         return send_params(params);
502 }
503 
504 
505 /* Send a seek command with parameters and wait for response */
506 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
507 {
508         int ack = send_cmd(cmd);
509         if (ack < 0)
510                 return ack;
511         ack = send_seek_params(params);
512         if (ack < 0)
513                 return ack;
514         return 0;
515 }
516 
517 
518 /* Send a command with parameters and wait for response */
519 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
520 {
521         int ack = exec_read_cmd(cmd, params);
522         if (ack < 0)
523                 return ack;
524         return get_exec_status(0);
525 }
526 
527 /* Address conversion routines */
528 
529 
530 /* Binary to BCD (2 digits) */
531 inline static void single_bin2bcd(u_char *p)
532 {
533         DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
534         *p = (*p % 10) | ((*p / 10) << 4);
535 }
536 
537 
538 /* Convert entire msf struct */
539 static void bin2bcd(struct cdrom_msf *msf)
540 {
541         single_bin2bcd(&msf->cdmsf_min0);
542         single_bin2bcd(&msf->cdmsf_sec0);
543         single_bin2bcd(&msf->cdmsf_frame0);
544         single_bin2bcd(&msf->cdmsf_min1);
545         single_bin2bcd(&msf->cdmsf_sec1);
546         single_bin2bcd(&msf->cdmsf_frame1);
547 }
548 
549 
550 /* Linear block address to minute, second, frame form */
551 #define CD_FPM  (CD_SECS * CD_FRAMES)   /* frames per minute */
552 
553 static void lba2msf(int lba, struct cdrom_msf *msf)
554 {
555         DEBUG((DEBUG_CONV, "lba2msf %d", lba));
556         lba += CD_MSF_OFFSET;
557         msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
558         msf->cdmsf_sec0 = lba / CD_FRAMES;
559         msf->cdmsf_frame0 = lba % CD_FRAMES;
560         msf->cdmsf_min1 = 0;
561         msf->cdmsf_sec1 = 0;
562         msf->cdmsf_frame1 = 0;
563         bin2bcd(msf);
564 }
565 
566 
567 /* Two BCD digits to binary */
568 inline static u_char bcd2bin(u_char bcd)
569 {
570         DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
571         return (bcd >> 4) * 10 + (bcd & 0x0f);
572 }
573 
574 
575 static void msf2lba(union cdrom_addr *addr)
576 {
577         addr->lba = addr->msf.minute * CD_FPM
578                     + addr->msf.second * CD_FRAMES
579                     + addr->msf.frame - CD_MSF_OFFSET;
580 }
581 
582 
583 /* Minute, second, frame address BCD to binary or to linear address,
584    depending on MODE */
585 static void msf_bcd2bin(union cdrom_addr *addr)
586 {
587         addr->msf.minute = bcd2bin(addr->msf.minute);
588         addr->msf.second = bcd2bin(addr->msf.second);
589         addr->msf.frame = bcd2bin(addr->msf.frame);
590 }
591 
592 /* High level drive commands */
593 
594 
595 static int audio_status = CDROM_AUDIO_NO_STATUS;
596 static char toc_uptodate = 0;
597 static char disk_changed = 1;
598 
599 /* Get drive status, flagging completion of audio play and disk changes. */
600 static int drive_status(void)
601 {
602         int status;
603 
604         status = exec_cmd(COMIOCTLISTAT);
605         DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
606         if (status < 0)
607                 return status;
608         if (status == 0xff)     /* No status available */
609                 return -ERR_IF_NOSTAT;
610 
611         if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
612                 (audio_status == CDROM_AUDIO_PLAY)) {
613                 audio_status = CDROM_AUDIO_COMPLETED;
614         }
615 
616         if (status & ST_DSK_CHG) {
617                 toc_uptodate = 0;
618                 disk_changed = 1;
619                 audio_status = CDROM_AUDIO_NO_STATUS;
620         }
621 
622         return status;
623 }
624 
625 
626 /* Read the current Q-channel info. Also used for reading the
627    table of contents. qp->cdsc_format must be set on entry to
628    indicate the desired address format */
629 static int get_q_channel(struct cdrom_subchnl *qp)
630 {
631         int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
632 
633         status = drive_status();
634         if (status < 0)
635                 return status;
636         qp->cdsc_audiostatus = audio_status;
637 
638         status = exec_cmd(COMSUBQ);
639         if (status < 0)
640                 return status;
641 
642         d1 = get_data(0);
643         if (d1 < 0)
644                 return d1;
645         qp->cdsc_adr = d1;
646         qp->cdsc_ctrl = d1 >> 4;
647 
648         d2 = get_data(0);
649         if (d2 < 0)
650                 return d2;
651         qp->cdsc_trk = bcd2bin(d2);
652 
653         d3 = get_data(0);
654         if (d3 < 0)
655                 return d3;
656         qp->cdsc_ind = bcd2bin(d3);
657 
658         d4 = get_data(0);
659         if (d4 < 0)
660                 return d4;
661         qp->cdsc_reladdr.msf.minute = d4;
662 
663         d5 = get_data(0);
664         if (d5 < 0)
665                 return d5;
666         qp->cdsc_reladdr.msf.second = d5;
667 
668         d6 = get_data(0);
669         if (d6 < 0)
670                 return d6;
671         qp->cdsc_reladdr.msf.frame = d6;
672 
673         d7 = get_data(0);
674         if (d7 < 0)
675                 return d7;
676         /* byte not used */
677 
678         d8 = get_data(0);
679         if (d8 < 0)
680                 return d8;
681         qp->cdsc_absaddr.msf.minute = d8;
682 
683         d9 = get_data(0);
684         if (d9 < 0)
685                 return d9;
686         qp->cdsc_absaddr.msf.second = d9;
687 
688         d10 = get_data(0);
689         if (d10 < 0)
690                 return d10;
691         qp->cdsc_absaddr.msf.frame = d10;
692 
693         DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
694                 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
695 
696         msf_bcd2bin(&qp->cdsc_absaddr);
697         msf_bcd2bin(&qp->cdsc_reladdr);
698         if (qp->cdsc_format == CDROM_LBA) {
699                 msf2lba(&qp->cdsc_absaddr);
700                 msf2lba(&qp->cdsc_reladdr);
701         }
702 
703         return 0;
704 }
705 
706 /* Table of contents handling */
707 
708 
709 /* Errors in table of contents */
710 #define ERR_TOC_MISSINGINFO     0x120
711 #define ERR_TOC_MISSINGENTRY    0x121
712 
713 
714 struct cdrom_disk_info {
715         unsigned char           first;
716         unsigned char           last;
717         struct cdrom_msf0       disk_length;
718         struct cdrom_msf0       first_track;
719         /* Multisession info: */
720         unsigned char           next;
721         struct cdrom_msf0       next_session;
722         struct cdrom_msf0       last_session;
723         unsigned char           multi;
724         unsigned char           xa;
725         unsigned char           audio;
726 };
727 static struct cdrom_disk_info disk_info;
728 
729 #define MAX_TRACKS              111
730 static struct cdrom_subchnl toc[MAX_TRACKS];
731 
732 #define QINFO_FIRSTTRACK        100 /* bcd2bin(0xa0) */
733 #define QINFO_LASTTRACK         101 /* bcd2bin(0xa1) */
734 #define QINFO_DISKLENGTH        102 /* bcd2bin(0xa2) */
735 #define QINFO_NEXTSESSION       110 /* bcd2bin(0xb0) */
736 
737 #define I_FIRSTTRACK    0x01
738 #define I_LASTTRACK     0x02
739 #define I_DISKLENGTH    0x04
740 #define I_NEXTSESSION   0x08
741 #define I_ALL   (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
742 
743 
744 #if DEBUG_TOC
745 static void toc_debug_info(int i)
746 {
747         printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
748                 "  %2d:%02d.%02d %2d:%02d.%02d\n",
749                 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
750                 toc[i].cdsc_trk, toc[i].cdsc_ind,
751                 toc[i].cdsc_reladdr.msf.minute,
752                 toc[i].cdsc_reladdr.msf.second,
753                 toc[i].cdsc_reladdr.msf.frame,
754                 toc[i].cdsc_absaddr.msf.minute,
755                 toc[i].cdsc_absaddr.msf.second,
756                 toc[i].cdsc_absaddr.msf.frame);
757 }
758 #endif
759 
760 
761 static int read_toc(void)
762 {
763         int status, limit, count;
764         unsigned char got_info = 0;
765         struct cdrom_subchnl q_info;
766 #if DEBUG_TOC
767         int i;
768 #endif
769 
770         DEBUG((DEBUG_TOC, "starting read_toc"));
771 
772         count = 0;
773         for (limit = 60; limit > 0; limit--) {
774                 int index;
775 
776                 q_info.cdsc_format = CDROM_MSF;
777                 status = get_q_channel(&q_info);
778                 if (status < 0)
779                         return status;
780 
781                 index = q_info.cdsc_ind;
782                 if (index > 0 && index < MAX_TRACKS
783                     && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
784                         toc[index] = q_info;
785                         DEBUG((DEBUG_TOC, "got %d", index));
786                         if (index < 100)
787                                 count++;
788 
789                         switch (q_info.cdsc_ind) {
790                         case QINFO_FIRSTTRACK:
791                                 got_info |= I_FIRSTTRACK;
792                                 break;
793                         case QINFO_LASTTRACK:
794                                 got_info |= I_LASTTRACK;
795                                 break;
796                         case QINFO_DISKLENGTH:
797                                 got_info |= I_DISKLENGTH;
798                                 break;
799                         case QINFO_NEXTSESSION:
800                                 got_info |= I_NEXTSESSION;
801                                 break;
802                         }
803                 }
804 
805                 if ((got_info & I_ALL) == I_ALL
806                     && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
807                        >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
808                         break;
809         }
810 
811         /* Construct disk_info from TOC */
812         if (disk_info.first == 0) {
813                 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
814                 disk_info.first_track.minute =
815                         toc[disk_info.first].cdsc_absaddr.msf.minute;
816                 disk_info.first_track.second =
817                         toc[disk_info.first].cdsc_absaddr.msf.second;
818                 disk_info.first_track.frame =
819                         toc[disk_info.first].cdsc_absaddr.msf.frame;
820         }
821         disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
822         disk_info.disk_length.minute =
823                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
824         disk_info.disk_length.second =
825                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
826         disk_info.disk_length.frame =
827                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
828         disk_info.next_session.minute =
829                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
830         disk_info.next_session.second =
831                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
832         disk_info.next_session.frame =
833                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
834         disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
835         disk_info.last_session.minute =
836                         toc[disk_info.next].cdsc_absaddr.msf.minute;
837         disk_info.last_session.second =
838                         toc[disk_info.next].cdsc_absaddr.msf.second;
839         disk_info.last_session.frame =
840                         toc[disk_info.next].cdsc_absaddr.msf.frame;
841         toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
842                         disk_info.disk_length.minute;
843         toc[disk_info.last + 1].cdsc_absaddr.msf.second =
844                         disk_info.disk_length.second;
845         toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
846                         disk_info.disk_length.frame;
847 #if DEBUG_TOC
848         for (i = 1; i <= disk_info.last + 1; i++)
849                 toc_debug_info(i);
850         toc_debug_info(QINFO_FIRSTTRACK);
851         toc_debug_info(QINFO_LASTTRACK);
852         toc_debug_info(QINFO_DISKLENGTH);
853         toc_debug_info(QINFO_NEXTSESSION);
854 #endif
855 
856         DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
857                 got_info, count));
858         if ((got_info & I_ALL) != I_ALL
859             || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
860                < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
861                 return -ERR_TOC_MISSINGINFO;
862         return 0;
863 }
864 
865 
866 #ifdef MULTISESSION
867 static int get_multi_disk_info(void)
868 {
869         int sessions, status;
870         struct cdrom_msf multi_index;
871 
872 
873         for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
874                 int count;
875 
876                 for (count = 100; count < MAX_TRACKS; count++) 
877                         toc[count].cdsc_ind = 0;
878 
879                 multi_index.cdmsf_min0 = disk_info.next_session.minute;
880                 multi_index.cdmsf_sec0 = disk_info.next_session.second;
881                 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
882                 if (multi_index.cdmsf_sec0 >= 20)
883                         multi_index.cdmsf_sec0 -= 20;
884                 else {
885                         multi_index.cdmsf_sec0 += 40;
886                         multi_index.cdmsf_min0--;
887                 }
888                 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
889                         multi_index.cdmsf_min0,
890                         multi_index.cdmsf_sec0,
891                         multi_index.cdmsf_frame0));
892                 bin2bcd(&multi_index);
893                 multi_index.cdmsf_min1 = 0;
894                 multi_index.cdmsf_sec1 = 0;
895                 multi_index.cdmsf_frame1 = 1;
896 
897                 status = exec_read_cmd(COMREAD, &multi_index);
898                 if (status < 0) {
899                         DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
900                                 -status));
901                         break;
902                 }
903                 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
904                                 0 : -ERR_TOC_MISSINGINFO;
905                 flush_data();
906                 if (status < 0) {
907                         DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
908                         break;
909                 }
910 
911                 status = read_toc();
912                 if (status < 0) {
913                         DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
914                         break;
915                 }
916 
917                 disk_info.multi = 1;
918         }
919 
920         exec_cmd(COMSTOP);
921 
922         if (status < 0)
923                 return -EIO;
924         return 0;
925 }
926 #endif /* MULTISESSION */
927 
928 
929 static int update_toc(void)
930 {
931         int status, count;
932 
933         if (toc_uptodate)
934                 return 0;
935 
936         DEBUG((DEBUG_TOC, "starting update_toc"));
937 
938         disk_info.first = 0;
939         for (count = 0; count < MAX_TRACKS; count++) 
940                 toc[count].cdsc_ind = 0;
941 
942         status = exec_cmd(COMLEADIN);
943         if (status < 0)
944                 return -EIO;
945 
946         status = read_toc();
947         if (status < 0) {
948                 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
949                 return -EIO;
950         }
951 
952         /* Audio disk detection. Look at first track. */
953         disk_info.audio =
954                 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
955 
956         /* XA detection */
957         disk_info.xa = drive_status() & ST_MODE2TRACK;
958 
959         /* Multisession detection: if we want this, define MULTISESSION */
960         disk_info.multi = 0;
961 #ifdef MULTISESSION
962         if (disk_info.xa)
963                 get_multi_disk_info();  /* Here disk_info.multi is set */
964 #endif /* MULTISESSION */
965         if (disk_info.multi)
966                 printk(KERN_WARNING "optcd: Multisession support experimental, "
967                         "see Documentation/cdrom/optcd\n");
968 
969         DEBUG((DEBUG_TOC, "exiting update_toc"));
970 
971         toc_uptodate = 1;
972         return 0;
973 }
974 
975 /* Request handling */
976 
977 static int current_valid(void)
978 {
979         return CURRENT &&
980                 CURRENT->cmd == READ &&
981                 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 0);
1369                 return;
1370         }
1371 
1372         transfer_is_active = 1;
1373         while (current_valid()) {
1374                 transfer();     /* First try to transfer block from buffers */
1375                 if (CURRENT -> nr_sectors == 0) {
1376                         end_request(CURRENT, 1);
1377                 } else {        /* Want to read a block not in buffer */
1378                         buf_out = NOBUF;
1379                         if (state == S_IDLE) {
1380                                 /* %% Should this block the request queue?? */
1381                                 if (update_toc() < 0) {
1382                                         while (current_valid())
1383                                                 end_request(CURRENT, 0);
1384                                         break;
1385                                 }
1386                                 /* Start state machine */
1387                                 state = S_START;
1388                                 timeout = READ_TIMEOUT;
1389                                 tries = 5;
1390                                 /* %% why not start right away?? */
1391                                 mod_timer(&req_timer, jiffies + HZ/100);
1392                         }
1393                         break;
1394                 }
1395         }
1396         transfer_is_active = 0;
1397 
1398         DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1399                next_bn, buf_in, buf_out, buf_bn[buf_in]));
1400         DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1401 }
1402 
1403 /* IOCTLs */
1404 
1405 
1406 static char auto_eject = 0;
1407 
1408 static int cdrompause(void)
1409 {
1410         int status;
1411 
1412         if (audio_status != CDROM_AUDIO_PLAY)
1413                 return -EINVAL;
1414 
1415         status = exec_cmd(COMPAUSEON);
1416         if (status < 0) {
1417                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1418                 return -EIO;
1419         }
1420         audio_status = CDROM_AUDIO_PAUSED;
1421         return 0;
1422 }
1423 
1424 
1425 static int cdromresume(void)
1426 {
1427         int status;
1428 
1429         if (audio_status != CDROM_AUDIO_PAUSED)
1430                 return -EINVAL;
1431 
1432         status = exec_cmd(COMPAUSEOFF);
1433         if (status < 0) {
1434                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1435                 audio_status = CDROM_AUDIO_ERROR;
1436                 return -EIO;
1437         }
1438         audio_status = CDROM_AUDIO_PLAY;
1439         return 0;
1440 }
1441 
1442 
1443 static int cdromplaymsf(void __user *arg)
1444 {
1445         int status;
1446         struct cdrom_msf msf;
1447 
1448         if (copy_from_user(&msf, arg, sizeof msf))
1449                 return -EFAULT;
1450 
1451         bin2bcd(&msf);
1452         status = exec_long_cmd(COMPLAY, &msf);
1453         if (status < 0) {
1454                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1455                 audio_status = CDROM_AUDIO_ERROR;
1456                 return -EIO;
1457         }
1458 
1459         audio_status = CDROM_AUDIO_PLAY;
1460         return 0;
1461 }
1462 
1463 
1464 static int cdromplaytrkind(void __user *arg)
1465 {
1466         int status;
1467         struct cdrom_ti ti;
1468         struct cdrom_msf msf;
1469 
1470         if (copy_from_user(&ti, arg, sizeof ti))
1471                 return -EFAULT;
1472 
1473         if (ti.cdti_trk0 < disk_info.first
1474             || ti.cdti_trk0 > disk_info.last
1475             || ti.cdti_trk1 < ti.cdti_trk0)
1476                 return -EINVAL;
1477         if (ti.cdti_trk1 > disk_info.last)
1478                 ti.cdti_trk1 = disk_info.last;
1479 
1480         msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1481         msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1482         msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1483         msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1484         msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1485         msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1486 
1487         DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1488                 msf.cdmsf_min0,
1489                 msf.cdmsf_sec0,
1490                 msf.cdmsf_frame0,
1491                 msf.cdmsf_min1,
1492                 msf.cdmsf_sec1,
1493                 msf.cdmsf_frame1));
1494 
1495         bin2bcd(&msf);
1496         status = exec_long_cmd(COMPLAY, &msf);
1497         if (status < 0) {
1498                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1499                 audio_status = CDROM_AUDIO_ERROR;
1500                 return -EIO;
1501         }
1502 
1503         audio_status = CDROM_AUDIO_PLAY;
1504         return 0;
1505 }
1506 
1507 
1508 static int cdromreadtochdr(void __user *arg)
1509 {
1510         struct cdrom_tochdr tochdr;
1511 
1512         tochdr.cdth_trk0 = disk_info.first;
1513         tochdr.cdth_trk1 = disk_info.last;
1514 
1515         return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0;
1516 }
1517 
1518 
1519 static int cdromreadtocentry(void __user *arg)
1520 {
1521         struct cdrom_tocentry entry;
1522         struct cdrom_subchnl *tocptr;
1523 
1524         if (copy_from_user(&entry, arg, sizeof entry))
1525                 return -EFAULT;
1526 
1527         if (entry.cdte_track == CDROM_LEADOUT)
1528                 tocptr = &toc[disk_info.last + 1];
1529         else if (entry.cdte_track > disk_info.last
1530                 || entry.cdte_track < disk_info.first)
1531                 return -EINVAL;
1532         else
1533                 tocptr = &toc[entry.cdte_track];
1534 
1535         entry.cdte_adr = tocptr->cdsc_adr;
1536         entry.cdte_ctrl = tocptr->cdsc_ctrl;
1537         entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1538         entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1539         entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1540         /* %% What should go into entry.cdte_datamode? */
1541 
1542         if (entry.cdte_format == CDROM_LBA)
1543                 msf2lba(&entry.cdte_addr);
1544         else if (entry.cdte_format != CDROM_MSF)
1545                 return -EINVAL;
1546 
1547         return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0;
1548 }
1549 
1550 
1551 static int cdromvolctrl(void __user *arg)
1552 {
1553         int status;
1554         struct cdrom_volctrl volctrl;
1555         struct cdrom_msf msf;
1556 
1557         if (copy_from_user(&volctrl, arg, sizeof volctrl))
1558                 return -EFAULT;
1559 
1560         msf.cdmsf_min0 = 0x10;
1561         msf.cdmsf_sec0 = 0x32;
1562         msf.cdmsf_frame0 = volctrl.channel0;
1563         msf.cdmsf_min1 = volctrl.channel1;
1564         msf.cdmsf_sec1 = volctrl.channel2;
1565         msf.cdmsf_frame1 = volctrl.channel3;
1566 
1567         status = exec_long_cmd(COMCHCTRL, &msf);
1568         if (status < 0) {
1569                 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1570                 return -EIO;
1571         }
1572         return 0;
1573 }
1574 
1575 
1576 static int cdromsubchnl(void __user *arg)
1577 {
1578         int status;
1579         struct cdrom_subchnl subchnl;
1580 
1581         if (copy_from_user(&subchnl, arg, sizeof subchnl))
1582                 return -EFAULT;
1583 
1584         if (subchnl.cdsc_format != CDROM_LBA
1585             && subchnl.cdsc_format != CDROM_MSF)
1586                 return -EINVAL;
1587 
1588         status = get_q_channel(&subchnl);
1589         if (status < 0) {
1590                 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1591                 return -EIO;
1592         }
1593 
1594         if (copy_to_user(arg, &subchnl, sizeof subchnl))
1595                 return -EFAULT;
1596         return 0;
1597 }
1598 
1599 
1600 static struct gendisk *optcd_disk;
1601 
1602 
1603 static int cdromread(void __user *arg, int blocksize, int cmd)
1604 {
1605         int status;
1606         struct cdrom_msf msf;
1607 
1608         if (copy_from_user(&msf, arg, sizeof msf))
1609                 return -EFAULT;
1610 
1611         bin2bcd(&msf);
1612         msf.cdmsf_min1 = 0;
1613         msf.cdmsf_sec1 = 0;
1614         msf.cdmsf_frame1 = 1;   /* read only one frame */
1615         status = exec_read_cmd(cmd, &msf);
1616 
1617         DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1618 
1619         if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1620                 return -EIO;
1621 
1622         fetch_data(optcd_disk->private_data, blocksize);
1623 
1624         if (copy_to_user(arg, optcd_disk->private_data, blocksize))
1625                 return -EFAULT;
1626 
1627         return 0;
1628 }
1629 
1630 
1631 static int cdromseek(void __user *arg)
1632 {
1633         int status;
1634         struct cdrom_msf msf;
1635 
1636         if (copy_from_user(&msf, arg, sizeof msf))
1637                 return -EFAULT;
1638 
1639         bin2bcd(&msf);
1640         status = exec_seek_cmd(COMSEEK, &msf);
1641 
1642         DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1643 
1644         if (status < 0)
1645                 return -EIO;
1646         return 0;
1647 }
1648 
1649 
1650 #ifdef MULTISESSION
1651 static int cdrommultisession(void __user *arg)
1652 {
1653         struct cdrom_multisession ms;
1654 
1655         if (copy_from_user(&ms, arg, sizeof ms))
1656                 return -EFAULT;
1657 
1658         ms.addr.msf.minute = disk_info.last_session.minute;
1659         ms.addr.msf.second = disk_info.last_session.second;
1660         ms.addr.msf.frame = disk_info.last_session.frame;
1661 
1662         if (ms.addr_format != CDROM_LBA
1663            && ms.addr_format != CDROM_MSF)
1664                 return -EINVAL;
1665         if (ms.addr_format == CDROM_LBA)
1666                 msf2lba(&ms.addr);
1667 
1668         ms.xa_flag = disk_info.xa;
1669 
1670         if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession)))
1671                 return -EFAULT;
1672 
1673 #if DEBUG_MULTIS
1674         if (ms.addr_format == CDROM_MSF)
1675                 printk(KERN_DEBUG
1676                         "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1677                         ms.xa_flag,
1678                         ms.addr.msf.minute,
1679                         ms.addr.msf.second,
1680                         ms.addr.msf.frame);
1681         else
1682                 printk(KERN_DEBUG
1683                     "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1684                         ms.xa_flag,
1685                         ms.addr.lba,
1686                         disk_info.last_session.minute,
1687                         disk_info.last_session.second,
1688                         disk_info.last_session.frame);
1689 #endif /* DEBUG_MULTIS */
1690 
1691         return 0;
1692 }
1693 #endif /* MULTISESSION */
1694 
1695 
1696 static int cdromreset(void)
1697 {
1698         if (state != S_IDLE) {
1699                 error = 1;
1700                 tries = 0;
1701         }
1702 
1703         toc_uptodate = 0;
1704         disk_changed = 1;
1705         opt_invalidate_buffers();
1706         audio_status = CDROM_AUDIO_NO_STATUS;
1707 
1708         if (!reset_drive())
1709                 return -EIO;
1710         return 0;
1711 }
1712 
1713 /* VFS calls */
1714 
1715 
1716 static int opt_ioctl(struct inode *ip, struct file *fp,
1717                      unsigned int cmd, unsigned long arg)
1718 {
1719         int status, err, retval = 0;
1720         void __user *argp = (void __user *)arg;
1721 
1722         DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1723 
1724         if (!ip)
1725                 return -EINVAL;
1726 
1727         if (cmd == CDROMRESET)
1728                 return cdromreset();
1729 
1730         /* is do_optcd_request or another ioctl busy? */
1731         if (state != S_IDLE || in_vfs)
1732                 return -EBUSY;
1733 
1734         in_vfs = 1;
1735 
1736         status = drive_status();
1737         if (status < 0) {
1738                 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1739                 in_vfs = 0;
1740                 return -EIO;
1741         }
1742 
1743         if (status & ST_DOOR_OPEN)
1744                 switch (cmd) {  /* Actions that can be taken with door open */
1745                 case CDROMCLOSETRAY:
1746                         /* We do this before trying to read the toc. */
1747                         err = exec_cmd(COMCLOSE);
1748                         if (err < 0) {
1749                                 DEBUG((DEBUG_VFS,
1750                                        "exec_cmd COMCLOSE: %02x", -err));
1751                                 in_vfs = 0;
1752                                 return -EIO;
1753                         }
1754                         break;
1755                 default:        in_vfs = 0;
1756                                 return -EBUSY;
1757                 }
1758 
1759         err = update_toc();
1760         if (err < 0) {
1761                 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1762                 in_vfs = 0;
1763                 return -EIO;
1764         }
1765 
1766         DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1767 
1768         switch (cmd) {
1769         case CDROMPAUSE:        retval = cdrompause(); break;
1770         case CDROMRESUME:       retval = cdromresume(); break;
1771         case CDROMPLAYMSF:      retval = cdromplaymsf(argp); break;
1772         case CDROMPLAYTRKIND:   retval = cdromplaytrkind(argp); break;
1773         case CDROMREADTOCHDR:   retval = cdromreadtochdr(argp); break;
1774         case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break;
1775 
1776         case CDROMSTOP:         err = exec_cmd(COMSTOP);
1777                                 if (err < 0) {
1778                                         DEBUG((DEBUG_VFS,
1779                                                 "exec_cmd COMSTOP: %02x",
1780                                                 -err));
1781                                         retval = -EIO;
1782                                 } else
1783                                         audio_status = CDROM_AUDIO_NO_STATUS;
1784                                 break;
1785         case CDROMSTART:        break;  /* This is a no-op */
1786         case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
1787                                 if (err < 0) {
1788                                         DEBUG((DEBUG_VFS,
1789                                                 "exec_cmd COMUNLOCK: %02x",
1790                                                 -err));
1791                                         retval = -EIO;
1792                                         break;
1793                                 }
1794                                 err = exec_cmd(COMOPEN);
1795                                 if (err < 0) {
1796                                         DEBUG((DEBUG_VFS,
1797                                                 "exec_cmd COMOPEN: %02x",
1798                                                 -err));
1799                                         retval = -EIO;
1800                                 }
1801                                 break;
1802 
1803         case CDROMVOLCTRL:      retval = cdromvolctrl(argp); break;
1804         case CDROMSUBCHNL:      retval = cdromsubchnl(argp); break;
1805 
1806         /* The drive detects the mode and automatically delivers the
1807            correct 2048 bytes, so we don't need these IOCTLs */
1808         case CDROMREADMODE2:    retval = -EINVAL; break;
1809         case CDROMREADMODE1:    retval = -EINVAL; break;
1810 
1811         /* Drive doesn't support reading audio */
1812         case CDROMREADAUDIO:    retval = -EINVAL; break;
1813 
1814         case CDROMEJECT_SW:     auto_eject = (char) arg;
1815                                 break;
1816 
1817 #ifdef MULTISESSION
1818         case CDROMMULTISESSION: retval = cdrommultisession(argp); break;
1819 #endif
1820 
1821         case CDROM_GET_MCN:     retval = -EINVAL; break; /* not implemented */
1822         case CDROMVOLREAD:      retval = -EINVAL; break; /* not implemented */
1823 
1824         case CDROMREADRAW:
1825                         /* this drive delivers 2340 bytes in raw mode */
1826                         retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW);
1827                         break;
1828         case CDROMREADCOOKED:
1829                         retval = cdromread(argp, CD_FRAMESIZE, COMREAD);
1830                         break;
1831         case CDROMREADALL:
1832                         retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL);
1833                         break;
1834 
1835         case CDROMSEEK:         retval = cdromseek(argp); break;
1836         case CDROMPLAYBLK:      retval = -EINVAL; break; /* not implemented */
1837         case CDROMCLOSETRAY:    break;  /* The action was taken earlier */
1838         default:                retval = -EINVAL;
1839         }
1840         in_vfs = 0;
1841         return retval;
1842 }
1843 
1844 
1845 static int open_count = 0;
1846 
1847 /* Open device special file; check that a disk is in. */
1848 static int opt_open(struct inode *ip, struct file *fp)
1849 {
1850         DEBUG((DEBUG_VFS, "starting opt_open"));
1851 
1852         if (!open_count && state == S_IDLE) {
1853                 int status;
1854                 char *buf;
1855 
1856                 buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL);
1857                 if (!buf) {
1858                         printk(KERN_INFO "optcd: cannot allocate read buffer\n");
1859                         return -ENOMEM;
1860                 }
1861                 optcd_disk->private_data = buf;         /* save read buffer */
1862 
1863                 toc_uptodate = 0;
1864                 opt_invalidate_buffers();
1865 
1866                 status = exec_cmd(COMCLOSE);    /* close door */
1867                 if (status < 0) {
1868                         DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1869                 }
1870 
1871                 status = drive_status();
1872                 if (status < 0) {
1873                         DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1874                         goto err_out;
1875                 }
1876                 DEBUG((DEBUG_VFS, "status: %02x", status));
1877                 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1878                         printk(KERN_INFO "optcd: no disk or door open\n");
1879                         goto err_out;
1880                 }
1881                 status = exec_cmd(COMLOCK);             /* Lock door */
1882                 if (status < 0) {
1883                         DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1884                 }
1885                 status = update_toc();  /* Read table of contents */
1886                 if (status < 0) {
1887                         DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1888                         status = exec_cmd(COMUNLOCK);   /* Unlock door */
1889                         if (status < 0) {
1890                                 DEBUG((DEBUG_VFS,
1891                                        "exec_cmd COMUNLOCK: %02x", -status));
1892                         }
1893                         goto err_out;
1894                 }
1895                 open_count++;
1896         }
1897 
1898         DEBUG((DEBUG_VFS, "exiting opt_open"));
1899 
1900         return 0;
1901 
1902 err_out:
1903         return -EIO;
1904 }
1905 
1906 
1907 /* Release device special file; flush all blocks from the buffer cache */
1908 static int opt_release(struct inode *ip, struct file *fp)
1909 {
1910         int status;
1911 
1912         DEBUG((DEBUG_VFS, "executing opt_release"));
1913         DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n",
1914                 ip, ip->i_bdev->bd_disk->disk_name, fp));
1915 
1916         if (!--open_count) {
1917                 toc_uptodate = 0;
1918                 opt_invalidate_buffers();
1919                 status = exec_cmd(COMUNLOCK);   /* Unlock door */
1920                 if (status < 0) {
1921                         DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1922                 }
1923                 if (auto_eject) {
1924                         status = exec_cmd(COMOPEN);
1925                         DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1926                 }
1927                 kfree(optcd_disk->private_data);
1928                 del_timer(&delay_timer);
1929                 del_timer(&req_timer);
1930         }
1931         return 0;
1932 }
1933 
1934 
1935 /* Check if disk has been changed */
1936 static int opt_media_change(struct gendisk *disk)
1937 {
1938         DEBUG((DEBUG_VFS, "executing opt_media_change"));
1939         DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n",
1940                         disk->disk_name, disk_changed));
1941 
1942         if (disk_changed) {
1943                 disk_changed = 0;
1944                 return 1;
1945         }
1946         return 0;
1947 }
1948 
1949 /* Driver initialisation */
1950 
1951 
1952 /* Returns 1 if a drive is detected with a version string
1953    starting with "DOLPHIN". Otherwise 0. */
1954 static int __init version_ok(void)
1955 {
1956         char devname[100];
1957         int count, i, ch, status;
1958 
1959         status = exec_cmd(COMVERSION);
1960         if (status < 0) {
1961                 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1962                 return 0;
1963         }
1964         if ((count = get_data(1)) < 0) {
1965                 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1966                 return 0;
1967         }
1968         for (i = 0, ch = -1; count > 0; count--) {
1969                 if ((ch = get_data(1)) < 0) {
1970                         DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1971                         break;
1972                 }
1973                 if (i < 99)
1974                         devname[i++] = ch;
1975         }
1976         devname[i] = '\0';
1977         if (ch < 0)
1978                 return 0;
1979 
1980         printk(KERN_INFO "optcd: Device %s detected\n", devname);
1981         return ((devname[0] == 'D')
1982              && (devname[1] == 'O')
1983              && (devname[2] == 'L')
1984              && (devname[3] == 'P')
1985              && (devname[4] == 'H')
1986              && (devname[5] == 'I')
1987              && (devname[6] == 'N'));
1988 }
1989 
1990 
1991 static struct block_device_operations opt_fops = {
1992         .owner          = THIS_MODULE,
1993         .open           = opt_open,
1994         .release        = opt_release,
1995         .ioctl          = opt_ioctl,
1996         .media_changed  = opt_media_change,
1997 };
1998 
1999 #ifndef MODULE
2000 /* Get kernel parameter when used as a kernel driver */
2001 static int optcd_setup(char *str)
2002 {
2003         int ints[4];
2004         (void)get_options(str, ARRAY_SIZE(ints), ints);
2005         
2006         if (ints[0] > 0)
2007                 optcd_port = ints[1];
2008 
2009         return 1;
2010 }
2011 
2012 __setup("optcd=", optcd_setup);
2013 
2014 #endif /* MODULE */
2015 
2016 /* Test for presence of drive and initialize it. Called at boot time
2017    or during module initialisation. */
2018 static int __init optcd_init(void)
2019 {
2020         int status;
2021 
2022         if (optcd_port <= 0) {
2023                 printk(KERN_INFO
2024                         "optcd: no Optics Storage CDROM Initialization\n");
2025                 return -EIO;
2026         }
2027         optcd_disk = alloc_disk(1);
2028         if (!optcd_disk) {
2029                 printk(KERN_ERR "optcd: can't allocate disk\n");
2030                 return -ENOMEM;
2031         }
2032         optcd_disk->major = MAJOR_NR;
2033         optcd_disk->first_minor = 0;
2034         optcd_disk->fops = &opt_fops;
2035         sprintf(optcd_disk->disk_name, "optcd");
2036         sprintf(optcd_disk->devfs_name, "optcd");
2037 
2038         if (!request_region(optcd_port, 4, "optcd")) {
2039                 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2040                         optcd_port);
2041                 put_disk(optcd_disk);
2042                 return -EIO;
2043         }
2044 
2045         if (!reset_drive()) {
2046                 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2047                 release_region(optcd_port, 4);
2048                 put_disk(optcd_disk);
2049                 return -EIO;
2050         }
2051         if (!version_ok()) {
2052                 printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2053                 release_region(optcd_port, 4);
2054                 put_disk(optcd_disk);
2055                 return -EIO;
2056         }
2057         status = exec_cmd(COMINITDOUBLE);
2058         if (status < 0) {
2059                 printk(KERN_ERR "optcd: cannot init double speed mode\n");
2060                 release_region(optcd_port, 4);
2061                 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2062                 put_disk(optcd_disk);
2063                 return -EIO;
2064         }
2065         if (register_blkdev(MAJOR_NR, "optcd")) {
2066                 release_region(optcd_port, 4);
2067                 put_disk(optcd_disk);
2068                 return -EIO;
2069         }
2070 
2071 
2072         opt_queue = blk_init_queue(do_optcd_request, &optcd_lock);
2073         if (!opt_queue) {
2074                 unregister_blkdev(MAJOR_NR, "optcd");
2075                 release_region(optcd_port, 4);
2076                 put_disk(optcd_disk);
2077                 return -ENOMEM;
2078         }
2079 
2080         blk_queue_hardsect_size(opt_queue, 2048);
2081         optcd_disk->queue = opt_queue;
2082         add_disk(optcd_disk);
2083 
2084         printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2085         return 0;
2086 }
2087 
2088 
2089 static void __exit optcd_exit(void)
2090 {
2091         del_gendisk(optcd_disk);
2092         put_disk(optcd_disk);
2093         if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2094                 printk(KERN_ERR "optcd: what's that: can't unregister\n");
2095                 return;
2096         }
2097         blk_cleanup_queue(opt_queue);
2098         release_region(optcd_port, 4);
2099         printk(KERN_INFO "optcd: module released.\n");
2100 }
2101 
2102 module_init(optcd_init);
2103 module_exit(optcd_exit);
2104 
2105 MODULE_LICENSE("GPL");
2106 MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR);
2107 
  This page was automatically generated by the LXR engine.