root/drivers/cdrom/optcd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. debug
  2. flag_low
  3. sleep_timer
  4. sleep_flag_low
  5. send_cmd
  6. send_params
  7. send_seek_params
  8. get_exec_status
  9. get_data
  10. reset_drive
  11. stdt_flags
  12. fetch_status
  13. fetch_data
  14. flush_data
  15. exec_cmd
  16. exec_read_cmd
  17. exec_seek_cmd
  18. exec_long_cmd
  19. single_bin2bcd
  20. bin2bcd
  21. lba2msf
  22. bcd2bin
  23. msf2lba
  24. msf_bcd2bin
  25. drive_status
  26. get_q_channel
  27. toc_debug_info
  28. read_toc
  29. get_multi_disk_info
  30. update_toc
  31. opt_invalidate_buffers
  32. transfer
  33. poll
  34. do_optcd_request
  35. cdrompause
  36. cdromresume
  37. cdromplaymsf
  38. cdromplaytrkind
  39. cdromreadtochdr
  40. cdromreadtocentry
  41. cdromvolctrl
  42. cdromsubchnl
  43. cdromread
  44. cdromseek
  45. cdrommultisession
  46. cdromreset
  47. opt_ioctl
  48. opt_open
  49. opt_release
  50. opt_media_change
  51. version_ok
  52. optcd_setup
  53. optcd_init
  54. init_module
  55. cleanup_module

   1 /*      linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
   2         $Id: optcd.c,v 1.29 1996/02/22 22:38:30 root 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 */
  57 
  58 /* Includes */
  59 
  60 
  61 #include <linux/module.h>
  62 #include <linux/mm.h>
  63 #include <linux/ioport.h>
  64 #include <asm/io.h>
  65 
  66 #define MAJOR_NR OPTICS_CDROM_MAJOR
  67 #include <linux/blk.h>
  68 
  69 #include <linux/cdrom.h>
  70 #include <linux/optcd.h>
  71 
  72 
  73 /* Debug support */
  74 
  75 
  76 /* Don't forget to add new debug flags here. */
  77 #if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
  78     DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
  79 #define DEBUG(x) debug x
  80 static void debug(int debug_this, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         char s[1024];
  83         va_list args;
  84 
  85         if (!debug_this)
  86                 return;
  87 
  88         va_start(args, fmt);
  89         vsprintf(s, fmt, args);
  90         printk("optcd: %s\n", s);
  91         va_end(args);
  92 }
  93 #else
  94 #define DEBUG(x)
  95 #endif
  96 
  97 /* Drive hardware/firmware characteristics
  98    Identifiers in accordance with Optics Storage documentation */
  99 
 100 
 101 #define optcd_port optcd                        /* Needed for the modutils. */
 102 static short optcd_port = OPTCD_PORTBASE;       /* I/O base of drive. */
 103 
 104 /* Drive registers, read */
 105 #define DATA_PORT       optcd_port      /* Read data/status */
 106 #define STATUS_PORT     optcd_port+1    /* Indicate data/status availability */
 107 
 108 /* Drive registers, write */
 109 #define COMIN_PORT      optcd_port      /* For passing command/parameter */
 110 #define RESET_PORT      optcd_port+1    /* Write anything and wait 0.5 sec */
 111 #define HCON_PORT       optcd_port+2    /* Host Xfer Configuration */
 112 
 113 
 114 /* Command completion/status read from DATA register */
 115 #define ST_DRVERR               0x80
 116 #define ST_DOOR_OPEN            0x40
 117 #define ST_MIXEDMODE_DISK       0x20
 118 #define ST_MODE_BITS            0x1c
 119 #define ST_M_STOP               0x00
 120 #define ST_M_READ               0x04
 121 #define ST_M_AUDIO              0x04
 122 #define ST_M_PAUSE              0x08
 123 #define ST_M_INITIAL            0x0c
 124 #define ST_M_ERROR              0x10
 125 #define ST_M_OTHERS             0x14
 126 #define ST_MODE2TRACK           0x02
 127 #define ST_DSK_CHG              0x01
 128 #define ST_L_LOCK               0x01
 129 #define ST_CMD_OK               0x00
 130 #define ST_OP_OK                0x01
 131 #define ST_PA_OK                0x02
 132 #define ST_OP_ERROR             0x05
 133 #define ST_PA_ERROR             0x06
 134 
 135 
 136 /* Error codes (appear as command completion code from DATA register) */
 137 /* Player related errors */
 138 #define ERR_ILLCMD      0x11    /* Illegal command to player module */
 139 #define ERR_ILLPARM     0x12    /* Illegal parameter to player module */
 140 #define ERR_SLEDGE      0x13
 141 #define ERR_FOCUS       0x14
 142 #define ERR_MOTOR       0x15
 143 #define ERR_RADIAL      0x16
 144 #define ERR_PLL         0x17    /* PLL lock error */
 145 #define ERR_SUB_TIM     0x18    /* Subcode timeout error */
 146 #define ERR_SUB_NF      0x19    /* Subcode not found error */
 147 #define ERR_TRAY        0x1a
 148 #define ERR_TOC         0x1b    /* Table of Contents read error */
 149 #define ERR_JUMP        0x1c
 150 /* Data errors */
 151 #define ERR_MODE        0x21
 152 #define ERR_FORM        0x22
 153 #define ERR_HEADADDR    0x23    /* Header Address not found */
 154 #define ERR_CRC         0x24
 155 #define ERR_ECC         0x25    /* Uncorrectable ECC error */
 156 #define ERR_CRC_UNC     0x26    /* CRC error and uncorrectable error */
 157 #define ERR_ILLBSYNC    0x27    /* Illegal block sync error */
 158 #define ERR_VDST        0x28    /* VDST not found */
 159 /* Timeout errors */
 160 #define ERR_READ_TIM    0x31    /* Read timeout error */
 161 #define ERR_DEC_STP     0x32    /* Decoder stopped */
 162 #define ERR_DEC_TIM     0x33    /* Decoder interrupt timeout error */
 163 /* Function abort codes */
 164 #define ERR_KEY         0x41    /* Key -Detected abort */
 165 #define ERR_READ_FINISH 0x42    /* Read Finish */
 166 /* Second Byte diagnostic codes */
 167 #define ERR_NOBSYNC     0x01    /* No block sync */
 168 #define ERR_SHORTB      0x02    /* Short block */
 169 #define ERR_LONGB       0x03    /* Long block */
 170 #define ERR_SHORTDSP    0x04    /* Short DSP word */
 171 #define ERR_LONGDSP     0x05    /* Long DSP word */
 172 
 173 
 174 /* Status availability flags read from STATUS register */
 175 #define FL_EJECT        0x20
 176 #define FL_WAIT         0x10    /* active low */
 177 #define FL_EOP          0x08    /* active low */
 178 #define FL_STEN         0x04    /* Status available when low */
 179 #define FL_DTEN         0x02    /* Data available when low */
 180 #define FL_DRQ          0x01    /* active low */
 181 #define FL_RESET        0xde    /* These bits are high after a reset */
 182 #define FL_STDT         (FL_STEN|FL_DTEN)
 183 
 184 
 185 /* Transfer mode, written to HCON register */
 186 #define HCON_DTS        0x08
 187 #define HCON_SDRQB      0x04
 188 #define HCON_LOHI       0x02
 189 #define HCON_DMA16      0x01
 190 
 191 
 192 /* Drive command set, written to COMIN register */
 193 /* Quick response commands */
 194 #define COMDRVST        0x20    /* Drive Status Read */
 195 #define COMERRST        0x21    /* Error Status Read */
 196 #define COMIOCTLISTAT   0x22    /* Status Read; reset disk changed bit */
 197 #define COMINITSINGLE   0x28    /* Initialize Single Speed */
 198 #define COMINITDOUBLE   0x29    /* Initialize Double Speed */
 199 #define COMUNLOCK       0x30    /* Unlock */
 200 #define COMLOCK         0x31    /* Lock */
 201 #define COMLOCKST       0x32    /* Lock/Unlock Status */
 202 #define COMVERSION      0x40    /* Get Firmware Revision */
 203 #define COMVOIDREADMODE 0x50    /* Void Data Read Mode */
 204 /* Read commands */
 205 #define COMFETCH        0x60    /* Prefetch Data */
 206 #define COMREAD         0x61    /* Read */
 207 #define COMREADRAW      0x62    /* Read Raw Data */
 208 #define COMREADALL      0x63    /* Read All 2646 Bytes */
 209 /* Player control commands */
 210 #define COMLEADIN       0x70    /* Seek To Lead-in */
 211 #define COMSEEK         0x71    /* Seek */
 212 #define COMPAUSEON      0x80    /* Pause On */
 213 #define COMPAUSEOFF     0x81    /* Pause Off */
 214 #define COMSTOP         0x82    /* Stop */
 215 #define COMOPEN         0x90    /* Open Tray Door */
 216 #define COMCLOSE        0x91    /* Close Tray Door */
 217 #define COMPLAY         0xa0    /* Audio Play */
 218 #define COMPLAY_TNO     0xa2    /* Audio Play By Track Number */
 219 #define COMSUBQ         0xb0    /* Read Sub-q Code */
 220 #define COMLOCATION     0xb1    /* Read Head Position */
 221 /* Audio control commands */
 222 #define COMCHCTRL       0xc0    /* Audio Channel Control */
 223 /* Miscellaneous (test) commands */
 224 #define COMDRVTEST      0xd0    /* Write Test Bytes */
 225 #define COMTEST         0xd1    /* Diagnostic Test */
 226 
 227 /* Low level drive interface. Only here we do actual I/O
 228    Waiting for status / data available */
 229 
 230 
 231 /* Busy wait until FLAG goes low. Return 0 on timeout. */
 232 inline static int flag_low(int flag, unsigned long timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         int flag_high;
 235         unsigned long count = 0;
 236 
 237         while ((flag_high = (inb(STATUS_PORT) & flag)))
 238                 if (++count >= timeout)
 239                         break;
 240 
 241         DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
 242                 flag, count, flag_high ? " timeout" : ""));
 243         return !flag_high;
 244 }
 245 
 246 
 247 /* Timed waiting for status or data */
 248 static int sleep_timeout;       /* max # of ticks to sleep */
 249 static struct wait_queue *waitq = NULL;
 250 static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
 251 
 252 #define SET_TIMER(func, jifs) \
 253         delay_timer.expires = jiffies+(jifs); \
 254         delay_timer.function = (void *) (func); \
 255         add_timer(&delay_timer);
 256 #define CLEAR_TIMER     del_timer(&delay_timer)
 257 
 258 
 259 /* Timer routine: wake up when desired flag goes low,
 260    or when timeout expires. */
 261 static void sleep_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 262 {
 263         int flags = inb(STATUS_PORT) & FL_STDT;
 264 
 265         if (flags == FL_STDT && --sleep_timeout > 0) {
 266                 SET_TIMER(sleep_timer, HZ/100); /* multi-statement macro */
 267         } else
 268                 wake_up(&waitq);
 269 }
 270 
 271 
 272 /* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
 273 static int sleep_flag_low(int flag, unsigned long timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 274 {
 275         int flag_high;
 276 
 277         DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
 278 
 279         sleep_timeout = timeout;
 280         flag_high = inb(STATUS_PORT) & flag;
 281         if (flag_high && sleep_timeout > 0) {
 282                 SET_TIMER(sleep_timer, HZ/100);
 283                 sleep_on(&waitq);
 284                 flag_high = inb(STATUS_PORT) & flag;
 285         }
 286 
 287         DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
 288                 flag, timeout, flag_high ? " timeout" : ""));
 289         return !flag_high;
 290 }
 291 
 292 /* Low level drive interface. Only here we do actual I/O
 293    Sending commands and parameters */
 294 
 295 
 296 /* Errors in the command protocol */
 297 #define ERR_IF_CMD_TIMEOUT      0x100
 298 #define ERR_IF_ERR_TIMEOUT      0x101
 299 #define ERR_IF_RESP_TIMEOUT     0x102
 300 #define ERR_IF_DATA_TIMEOUT     0x103
 301 #define ERR_IF_NOSTAT           0x104
 302 
 303 
 304 /* Send command code. Return <0 indicates error */
 305 static int send_cmd(int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307         unsigned char ack;
 308 
 309         DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
 310 
 311         outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
 312         outb(cmd, COMIN_PORT);          /* Send command code */
 313         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 314                 return -ERR_IF_CMD_TIMEOUT;
 315         ack = inb(DATA_PORT);           /* read command acknowledge */
 316         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 317         return ack==ST_OP_OK ? 0 : -ack;
 318 }
 319 
 320 
 321 /* Send command parameters. Return <0 indicates error */
 322 static int send_params(struct cdrom_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 {
 324         unsigned char ack;
 325 
 326         DEBUG((DEBUG_DRIVE_IF, "sending parameters"
 327                 " %02x:%02x:%02x"
 328                 " %02x:%02x:%02x",
 329                 params->cdmsf_min0,
 330                 params->cdmsf_sec0,
 331                 params->cdmsf_frame0,
 332                 params->cdmsf_min1,
 333                 params->cdmsf_sec1,
 334                 params->cdmsf_frame1));
 335 
 336         outb(params->cdmsf_min0, COMIN_PORT);
 337         outb(params->cdmsf_sec0, COMIN_PORT);
 338         outb(params->cdmsf_frame0, COMIN_PORT);
 339         outb(params->cdmsf_min1, COMIN_PORT);
 340         outb(params->cdmsf_sec1, COMIN_PORT);
 341         outb(params->cdmsf_frame1, COMIN_PORT);
 342         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 343                 return -ERR_IF_CMD_TIMEOUT;
 344         ack = inb(DATA_PORT);           /* read command acknowledge */
 345         return ack==ST_PA_OK ? 0 : -ack;
 346 }
 347 
 348 
 349 /* Send parameters for SEEK command. Return <0 indicates error */
 350 static int send_seek_params(struct cdrom_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 351 {
 352         unsigned char ack;
 353 
 354         DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
 355                 " %02x:%02x:%02x",
 356                 params->cdmsf_min0,
 357                 params->cdmsf_sec0,
 358                 params->cdmsf_frame0));
 359 
 360         outb(params->cdmsf_min0, COMIN_PORT);
 361         outb(params->cdmsf_sec0, COMIN_PORT);
 362         outb(params->cdmsf_frame0, COMIN_PORT);
 363         if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 364                 return -ERR_IF_CMD_TIMEOUT;
 365         ack = inb(DATA_PORT);           /* read command acknowledge */
 366         return ack==ST_PA_OK ? 0 : -ack;
 367 }
 368 
 369 
 370 /* Wait for command execution status. Choice between busy waiting
 371    and sleeping. Return value <0 indicates timeout. */
 372 inline static int get_exec_status(int busy_waiting)
     /* [previous][next][first][last][top][bottom][index][help] */
 373 {
 374         unsigned char exec_status;
 375 
 376         if (busy_waiting
 377             ? !flag_low(FL_STEN, BUSY_TIMEOUT)
 378             : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
 379                 return -ERR_IF_CMD_TIMEOUT;
 380 
 381         exec_status = inb(DATA_PORT);
 382         DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
 383         return exec_status;
 384 }
 385 
 386 
 387 /* Wait busy for extra byte of data that a command returns.
 388    Return value <0 indicates timeout. */
 389 inline static int get_data(int short_timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 390 {
 391         unsigned char data;
 392 
 393         if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
 394                 return -ERR_IF_DATA_TIMEOUT;
 395 
 396         data = inb(DATA_PORT);
 397         DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
 398         return data;
 399 }
 400 
 401 
 402 /* Returns 0 if failed */
 403 static int reset_drive(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405         unsigned long count = 0;
 406         int flags;
 407 
 408         DEBUG((DEBUG_DRIVE_IF, "reset drive"));
 409 
 410         outb(0, RESET_PORT);
 411         while (++count < RESET_WAIT)
 412                 inb(DATA_PORT);
 413 
 414         count = 0;
 415         while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
 416                 if (++count >= BUSY_TIMEOUT)
 417                         break;
 418 
 419         DEBUG((DEBUG_DRIVE_IF, "reset %s",
 420                 flags == FL_RESET ? "succeeded" : "failed"));
 421 
 422         if (flags != FL_RESET)
 423                 return 0;               /* Reset failed */
 424         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 425         return 1;                       /* Reset succeeded */
 426 }
 427 
 428 
 429 /* Facilities for asynchronous operation */
 430 
 431 /* Read status/data availability flags FL_STEN and FL_DTEN */
 432 inline static int stdt_flags(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434         return inb(STATUS_PORT) & FL_STDT;
 435 }
 436 
 437 
 438 /* Fetch status that has previously been waited for. <0 means not available */
 439 inline static int fetch_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 440 {
 441         unsigned char status;
 442 
 443         if (inb(STATUS_PORT) & FL_STEN)
 444                 return -ERR_IF_NOSTAT;
 445 
 446         status = inb(DATA_PORT);
 447         DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
 448         return status;
 449 }
 450 
 451 
 452 /* Fetch data that has previously been waited for. */
 453 inline static void fetch_data(char *buf, int n)
     /* [previous][next][first][last][top][bottom][index][help] */
 454 {
 455         insb(DATA_PORT, buf, n);
 456         DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
 457 }
 458 
 459 
 460 /* Flush status and data fifos */
 461 inline static void flush_data(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 462 {
 463         while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
 464                 inb(DATA_PORT);
 465         DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
 466 }
 467 
 468 /* Command protocol */
 469 
 470 
 471 /* Send a simple command and wait for response. Command codes < COMFETCH
 472    are quick response commands */
 473 inline static int exec_cmd(int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 474 {
 475         int ack = send_cmd(cmd);
 476         if (ack < 0)
 477                 return ack;
 478         return get_exec_status(cmd < COMFETCH);
 479 }
 480 
 481 
 482 /* Send a command with parameters. Don't wait for the response,
 483  * which consists of data blocks read from the CD. */
 484 inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 485 {
 486         int ack = send_cmd(cmd);
 487         if (ack < 0)
 488                 return ack;
 489         return send_params(params);
 490 }
 491 
 492 
 493 /* Send a seek command with parameters and wait for response */
 494 inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 495 {
 496         int ack = send_cmd(cmd);
 497         if (ack < 0)
 498                 return ack;
 499         ack = send_seek_params(params);
 500         if (ack < 0)
 501                 return ack;
 502         return 0;
 503 }
 504 
 505 
 506 /* Send a command with parameters and wait for response */
 507 inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 508 {
 509         int ack = exec_read_cmd(cmd, params);
 510         if (ack < 0)
 511                 return ack;
 512         return get_exec_status(0);
 513 }
 514 
 515 /* Address conversion routines */
 516 
 517 
 518 /* Binary to BCD (2 digits) */
 519 inline static void single_bin2bcd(u_char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 520 {
 521         DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
 522         *p = (*p % 10) | ((*p / 10) << 4);
 523 }
 524 
 525 
 526 /* Convert entire msf struct */
 527 static void bin2bcd(struct cdrom_msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 528 {
 529         single_bin2bcd(&msf->cdmsf_min0);
 530         single_bin2bcd(&msf->cdmsf_sec0);
 531         single_bin2bcd(&msf->cdmsf_frame0);
 532         single_bin2bcd(&msf->cdmsf_min1);
 533         single_bin2bcd(&msf->cdmsf_sec1);
 534         single_bin2bcd(&msf->cdmsf_frame1);
 535 }
 536 
 537 
 538 /* Linear block address to minute, second, frame form */
 539 #define CD_FPM  (CD_SECS * CD_FRAMES)   /* frames per minute */
 540 
 541 static void lba2msf(int lba, struct cdrom_msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 542 {
 543         DEBUG((DEBUG_CONV, "lba2msf %d", lba));
 544         lba += CD_MSF_OFFSET;
 545         msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
 546         msf->cdmsf_sec0 = lba / CD_FRAMES;
 547         msf->cdmsf_frame0 = lba % CD_FRAMES;
 548         msf->cdmsf_min1 = 0;
 549         msf->cdmsf_sec1 = 0;
 550         msf->cdmsf_frame1 = 0;
 551         bin2bcd(msf);
 552 }
 553 
 554 
 555 /* Two BCD digits to binary */
 556 inline static u_char bcd2bin(u_char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
 559         return (bcd >> 4) * 10 + (bcd & 0x0f);
 560 }
 561 
 562 
 563 static void msf2lba(union cdrom_addr *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 564 {
 565         addr->lba = addr->msf.minute * CD_FPM
 566                     + addr->msf.second * CD_FRAMES
 567                     + addr->msf.frame - CD_MSF_OFFSET;
 568 }
 569 
 570 
 571 /* Minute, second, frame address BCD to binary or to linear address,
 572    depending on MODE */
 573 static void msf_bcd2bin(union cdrom_addr *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 574 {
 575         addr->msf.minute = bcd2bin(addr->msf.minute);
 576         addr->msf.second = bcd2bin(addr->msf.second);
 577         addr->msf.frame = bcd2bin(addr->msf.frame);
 578 }
 579 
 580 /* High level drive commands */
 581 
 582 
 583 static int audio_status = CDROM_AUDIO_NO_STATUS;
 584 static char toc_uptodate = 0;
 585 static char disk_changed = 1;
 586 
 587 /* Get drive status, flagging completion of audio play and disk changes. */
 588 static int drive_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 589 {
 590         int status;
 591 
 592         status = exec_cmd(COMIOCTLISTAT);
 593         DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
 594         if (status < 0)
 595                 return status;
 596         if (status == 0xff)     /* No status available */
 597                 return -ERR_IF_NOSTAT;
 598 
 599         if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
 600                 (audio_status == CDROM_AUDIO_PLAY)) {
 601                 audio_status = CDROM_AUDIO_COMPLETED;
 602         }
 603 
 604         if (status & ST_DSK_CHG) {
 605                 toc_uptodate = 0;
 606                 disk_changed = 1;
 607                 audio_status = CDROM_AUDIO_NO_STATUS;
 608         }
 609 
 610         return status;
 611 }
 612 
 613 
 614 /* Read the current Q-channel info. Also used for reading the
 615    table of contents. qp->cdsc_format must be set on entry to
 616    indicate the desired address format */
 617 static int get_q_channel(struct cdrom_subchnl *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
 618 {
 619         int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
 620 
 621         status = drive_status();
 622         if (status < 0)
 623                 return status;
 624         qp->cdsc_audiostatus = audio_status;
 625 
 626         status = exec_cmd(COMSUBQ);
 627         if (status < 0)
 628                 return status;
 629 
 630         d1 = get_data(0);
 631         if (d1 < 0)
 632                 return d1;
 633         qp->cdsc_adr = d1;
 634         qp->cdsc_ctrl = d1 >> 4;
 635 
 636         d2 = get_data(0);
 637         if (d2 < 0)
 638                 return d2;
 639         qp->cdsc_trk = bcd2bin(d2);
 640 
 641         d3 = get_data(0);
 642         if (d3 < 0)
 643                 return d3;
 644         qp->cdsc_ind = bcd2bin(d3);
 645 
 646         d4 = get_data(0);
 647         if (d4 < 0)
 648                 return d4;
 649         qp->cdsc_reladdr.msf.minute = d4;
 650 
 651         d5 = get_data(0);
 652         if (d5 < 0)
 653                 return d5;
 654         qp->cdsc_reladdr.msf.second = d5;
 655 
 656         d6 = get_data(0);
 657         if (d6 < 0)
 658                 return d6;
 659         qp->cdsc_reladdr.msf.frame = d6;
 660 
 661         d7 = get_data(0);
 662         if (d7 < 0)
 663                 return d7;
 664         /* byte not used */
 665 
 666         d8 = get_data(0);
 667         if (d8 < 0)
 668                 return d8;
 669         qp->cdsc_absaddr.msf.minute = d8;
 670 
 671         d9 = get_data(0);
 672         if (d9 < 0)
 673                 return d9;
 674         qp->cdsc_absaddr.msf.second = d9;
 675 
 676         d10 = get_data(0);
 677         if (d10 < 0)
 678                 return d10;
 679         qp->cdsc_absaddr.msf.frame = d10;
 680 
 681         DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 682                 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
 683 
 684         msf_bcd2bin(&qp->cdsc_absaddr);
 685         msf_bcd2bin(&qp->cdsc_reladdr);
 686         if (qp->cdsc_format == CDROM_LBA) {
 687                 msf2lba(&qp->cdsc_absaddr);
 688                 msf2lba(&qp->cdsc_reladdr);
 689         }
 690 
 691         return 0;
 692 }
 693 
 694 /* Table of contents handling */
 695 
 696 
 697 /* Errors in table of contents */
 698 #define ERR_TOC_MISSINGINFO     0x120
 699 #define ERR_TOC_MISSINGENTRY    0x121
 700 
 701 
 702 struct cdrom_disk_info {
 703         unsigned char           first;
 704         unsigned char           last;
 705         struct cdrom_msf0       disk_length;
 706         struct cdrom_msf0       first_track;
 707         /* Multisession info: */
 708         unsigned char           next;
 709         struct cdrom_msf0       next_session;
 710         struct cdrom_msf0       last_session;
 711         unsigned char           multi;
 712         unsigned char           xa;
 713         unsigned char           audio;
 714 };
 715 static struct cdrom_disk_info disk_info;
 716 
 717 #define MAX_TRACKS              111
 718 static struct cdrom_subchnl toc[MAX_TRACKS];
 719 
 720 #define QINFO_FIRSTTRACK        100 /* bcd2bin(0xa0) */
 721 #define QINFO_LASTTRACK         101 /* bcd2bin(0xa1) */
 722 #define QINFO_DISKLENGTH        102 /* bcd2bin(0xa2) */
 723 #define QINFO_NEXTSESSION       110 /* bcd2bin(0xb0) */
 724 
 725 #define I_FIRSTTRACK    0x01
 726 #define I_LASTTRACK     0x02
 727 #define I_DISKLENGTH    0x04
 728 #define I_NEXTSESSION   0x08
 729 #define I_ALL   (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
 730 
 731 
 732 #if DEBUG_TOC
 733 void toc_debug_info(int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 734 {
 735         printk("#%3d ctl %1x, adr %1x, track %2d index %3d"
 736                 "  %2d:%02d.%02d %2d:%02d.%02d\n",
 737                 i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
 738                 toc[i].cdsc_trk, toc[i].cdsc_ind,
 739                 toc[i].cdsc_reladdr.msf.minute,
 740                 toc[i].cdsc_reladdr.msf.second,
 741                 toc[i].cdsc_reladdr.msf.frame,
 742                 toc[i].cdsc_absaddr.msf.minute,
 743                 toc[i].cdsc_absaddr.msf.second,
 744                 toc[i].cdsc_absaddr.msf.frame);
 745 }
 746 #endif
 747 
 748 
 749 static int read_toc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 750 {
 751         int status, limit, count;
 752         unsigned char got_info = 0;
 753         struct cdrom_subchnl q_info;
 754 #if DEBUG_TOC
 755         int i;
 756 #endif
 757 
 758         DEBUG((DEBUG_TOC, "starting read_toc"));
 759 
 760         count = 0;
 761         for (limit = 60; limit > 0; limit--) {
 762                 int index;
 763 
 764                 q_info.cdsc_format = CDROM_MSF;
 765                 status = get_q_channel(&q_info);
 766                 if (status < 0)
 767                         return status;
 768 
 769                 index = q_info.cdsc_ind;
 770                 if (index > 0 && index < MAX_TRACKS
 771                     && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
 772                         toc[index] = q_info;
 773                         DEBUG((DEBUG_TOC, "got %d", index));
 774                         if (index < 100)
 775                                 count++;
 776 
 777                         switch (q_info.cdsc_ind) {
 778                         case QINFO_FIRSTTRACK:
 779                                 got_info |= I_FIRSTTRACK;
 780                                 break;
 781                         case QINFO_LASTTRACK:
 782                                 got_info |= I_LASTTRACK;
 783                                 break;
 784                         case QINFO_DISKLENGTH:
 785                                 got_info |= I_DISKLENGTH;
 786                                 break;
 787                         case QINFO_NEXTSESSION:
 788                                 got_info |= I_NEXTSESSION;
 789                                 break;
 790                         }
 791                 }
 792 
 793                 if ((got_info & I_ALL) == I_ALL
 794                     && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 795                        >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 796                         break;
 797         }
 798 
 799         /* Construct disk_info from TOC */
 800         if (disk_info.first == 0) {
 801                 disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 802                 disk_info.first_track.minute =
 803                         toc[disk_info.first].cdsc_absaddr.msf.minute;
 804                 disk_info.first_track.second =
 805                         toc[disk_info.first].cdsc_absaddr.msf.second;
 806                 disk_info.first_track.frame =
 807                         toc[disk_info.first].cdsc_absaddr.msf.frame;
 808         }
 809         disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
 810         disk_info.disk_length.minute =
 811                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
 812         disk_info.disk_length.second =
 813                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
 814         disk_info.disk_length.frame =
 815                         toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
 816         disk_info.next_session.minute =
 817                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
 818         disk_info.next_session.second =
 819                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
 820         disk_info.next_session.frame =
 821                         toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
 822         disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 823         disk_info.last_session.minute =
 824                         toc[disk_info.next].cdsc_absaddr.msf.minute;
 825         disk_info.last_session.second =
 826                         toc[disk_info.next].cdsc_absaddr.msf.second;
 827         disk_info.last_session.frame =
 828                         toc[disk_info.next].cdsc_absaddr.msf.frame;
 829         toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
 830                         disk_info.disk_length.minute;
 831         toc[disk_info.last + 1].cdsc_absaddr.msf.second =
 832                         disk_info.disk_length.second;
 833         toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
 834                         disk_info.disk_length.frame;
 835 #if DEBUG_TOC
 836         for (i = 1; i <= disk_info.last + 1; i++)
 837                 toc_debug_info(i);
 838         toc_debug_info(QINFO_FIRSTTRACK);
 839         toc_debug_info(QINFO_LASTTRACK);
 840         toc_debug_info(QINFO_DISKLENGTH);
 841         toc_debug_info(QINFO_NEXTSESSION);
 842 #endif
 843 
 844         DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
 845                 got_info, count));
 846         if ((got_info & I_ALL) != I_ALL
 847             || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 848                < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 849                 return -ERR_TOC_MISSINGINFO;
 850         return 0;
 851 }
 852 
 853 
 854 #ifdef MULTISESSION
 855 static int get_multi_disk_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 856 {
 857         int sessions, status;
 858         struct cdrom_msf multi_index;
 859 
 860 
 861         for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
 862                 int count;
 863 
 864                 for (count = 100; count < MAX_TRACKS; count++) 
 865                         toc[count].cdsc_ind = 0;
 866 
 867                 multi_index.cdmsf_min0 = disk_info.next_session.minute;
 868                 multi_index.cdmsf_sec0 = disk_info.next_session.second;
 869                 multi_index.cdmsf_frame0 = disk_info.next_session.frame;
 870                 if (multi_index.cdmsf_sec0 >= 20)
 871                         multi_index.cdmsf_sec0 -= 20;
 872                 else {
 873                         multi_index.cdmsf_sec0 += 40;
 874                         multi_index.cdmsf_min0--;
 875                 }
 876                 DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
 877                         multi_index.cdmsf_min0,
 878                         multi_index.cdmsf_sec0,
 879                         multi_index.cdmsf_frame0));
 880                 bin2bcd(&multi_index);
 881                 multi_index.cdmsf_min1 = 0;
 882                 multi_index.cdmsf_sec1 = 0;
 883                 multi_index.cdmsf_frame1 = 1;
 884 
 885                 status = exec_read_cmd(COMREAD, &multi_index);
 886                 if (status < 0) {
 887                         DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
 888                                 -status));
 889                         break;
 890                 }
 891                 status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
 892                                 0 : -ERR_TOC_MISSINGINFO;
 893                 flush_data();
 894                 if (status < 0) {
 895                         DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
 896                         break;
 897                 }
 898 
 899                 status = read_toc();
 900                 if (status < 0) {
 901                         DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 902                         break;
 903                 }
 904 
 905                 disk_info.multi = 1;
 906         }
 907 
 908         exec_cmd(COMSTOP);
 909 
 910         if (status < 0)
 911                 return -EIO;
 912         return 0;
 913 }
 914 #endif MULTISESSION
 915 
 916 
 917 static int update_toc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 918 {
 919         int status, count;
 920 
 921         if (toc_uptodate)
 922                 return 0;
 923 
 924         DEBUG((DEBUG_TOC, "starting update_toc"));
 925 
 926         disk_info.first = 0;
 927         for (count = 0; count < MAX_TRACKS; count++) 
 928                 toc[count].cdsc_ind = 0;
 929 
 930         status = exec_cmd(COMLEADIN);
 931         if (status < 0)
 932                 return -EIO;
 933 
 934         status = read_toc();
 935         if (status < 0) {
 936                 DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 937                 return -EIO;
 938         }
 939 
 940         /* Audio disk detection. Look at first track. */
 941         disk_info.audio =
 942                 (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
 943 
 944         /* XA detection */
 945         disk_info.xa = drive_status() & ST_MODE2TRACK;
 946 
 947         /* Multisession detection: if we want this, define MULTISESSION */
 948         disk_info.multi = 0;
 949 #ifdef MULTISESSION
 950         if (disk_info.xa)
 951                 get_multi_disk_info();  /* Here disk_info.multi is set */
 952 #endif MULTISESSION
 953         if (disk_info.multi)
 954                 printk("optcd: Multisession support experimental, "
 955                         "see linux/Documentation/cdrom/optcd\n");
 956 
 957         DEBUG((DEBUG_TOC, "exiting update_toc"));
 958 
 959         toc_uptodate = 1;
 960         return 0;
 961 }
 962 
 963 /* Request handling */
 964 
 965 
 966 #define CURRENT_VALID \
 967         (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
 968          && CURRENT -> cmd == READ && CURRENT -> sector != -1)
 969 
 970 
 971 /* Buffers for block size conversion. */
 972 #define NOBUF           -1
 973 
 974 static char buf[CD_FRAMESIZE * N_BUFS];
 975 static volatile int buf_bn[N_BUFS], next_bn;
 976 static volatile int buf_in = 0, buf_out = NOBUF;
 977 
 978 inline static void opt_invalidate_buffers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 979 {
 980         int i;
 981 
 982         DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
 983 
 984         for (i = 0; i < N_BUFS; i++)
 985                 buf_bn[i] = NOBUF;
 986         buf_out = NOBUF;
 987 }
 988 
 989 
 990 /* Take care of the different block sizes between cdrom and Linux.
 991    When Linux gets variable block sizes this will probably go away. */
 992 static void transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 993 {
 994 #if DEBUG_BUFFERS | DEBUG_REQUEST
 995         printk("optcd: executing transfer\n");
 996 #endif
 997 
 998         if (!CURRENT_VALID)
 999                 return;
1000         while (CURRENT -> nr_sectors) {
1001                 int bn = CURRENT -> sector / 4;
1002                 int i, offs, nr_sectors;
1003                 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1004 
1005                 DEBUG((DEBUG_REQUEST, "found %d", i));
1006 
1007                 if (i >= N_BUFS) {
1008                         buf_out = NOBUF;
1009                         break;
1010                 }
1011 
1012                 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1013                 nr_sectors = 4 - (CURRENT -> sector & 3);
1014 
1015                 if (buf_out != i) {
1016                         buf_out = i;
1017                         if (buf_bn[i] != bn) {
1018                                 buf_out = NOBUF;
1019                                 continue;
1020                         }
1021                 }
1022 
1023                 if (nr_sectors > CURRENT -> nr_sectors)
1024                         nr_sectors = CURRENT -> nr_sectors;
1025                 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1026                 CURRENT -> nr_sectors -= nr_sectors;
1027                 CURRENT -> sector += nr_sectors;
1028                 CURRENT -> buffer += nr_sectors * 512;
1029         }
1030 }
1031 
1032 
1033 /* State machine for reading disk blocks */
1034 
1035 enum state_e {
1036         S_IDLE,         /* 0 */
1037         S_START,        /* 1 */
1038         S_READ,         /* 2 */
1039         S_DATA,         /* 3 */
1040         S_STOP,         /* 4 */
1041         S_STOPPING      /* 5 */
1042 };
1043 
1044 static volatile enum state_e state = S_IDLE;
1045 #if DEBUG_STATE
1046 static volatile enum state_e state_old = S_STOP;
1047 static volatile int flags_old = 0;
1048 static volatile long state_n = 0;
1049 #endif
1050 
1051 
1052 /* Used as mutex to keep do_optcd_request (and other processes calling
1053    ioctl) out while some process is inside a VFS call.
1054    Reverse is accomplished by checking if state = S_IDLE upon entry
1055    of opt_ioctl and opt_media_change. */
1056 static int in_vfs = 0;
1057 
1058 
1059 static volatile int transfer_is_active = 0;
1060 static volatile int error = 0;  /* %% do something with this?? */
1061 static int tries;               /* ibid?? */
1062 static int timeout = 0;
1063 
1064 static struct timer_list req_timer = {NULL, NULL, 0, 0, NULL};
1065 
1066 #define SET_REQ_TIMER(func, jifs) \
1067         req_timer.expires = jiffies+(jifs); \
1068         req_timer.function = (void *) (func); \
1069         add_timer(&req_timer);
1070 #define CLEAR_REQ_TIMER del_timer(&req_timer)
1071 
1072 static void poll(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1073 {
1074         static volatile int read_count = 1;
1075         int flags;
1076         int loop_again = 1;
1077         int status = 0;
1078         int skip = 0;
1079 
1080         if (error) {
1081                 printk("optcd: I/O error 0x%02x\n", error);
1082                 opt_invalidate_buffers();
1083                 if (!tries--) {
1084                         printk("optcd: read block %d failed; Giving up\n",
1085                                next_bn);
1086                         if (transfer_is_active)
1087                                 loop_again = 0;
1088                         if (CURRENT_VALID)
1089                                 end_request(0);
1090                         tries = 5;
1091                 }
1092                 error = 0;
1093                 state = S_STOP;
1094         }
1095 
1096         while (loop_again)
1097         {
1098                 loop_again = 0; /* each case must flip this back to 1 if we want
1099                                  to come back up here */
1100 
1101 #if DEBUG_STATE
1102                 if (state == state_old)
1103                         state_n++;
1104                 else {
1105                         state_old = state;
1106                         if (++state_n > 1)
1107                                 printk("optcd: %ld times in previous state\n",
1108                                         state_n);
1109                         printk("optcd: state %d\n", state);
1110                         state_n = 0;
1111                 }
1112 #endif
1113 
1114                 switch (state) {
1115                 case S_IDLE:
1116                         return;
1117                 case S_START:
1118                         if (in_vfs)
1119                                 break;
1120                         if (send_cmd(COMDRVST)) {
1121                                 state = S_IDLE;
1122                                 while (CURRENT_VALID)
1123                                         end_request(0);
1124                                 return;
1125                         }
1126                         state = S_READ;
1127                         timeout = READ_TIMEOUT;
1128                         break;
1129                 case S_READ: {
1130                         struct cdrom_msf msf;
1131                         if (!skip) {
1132                                 status = fetch_status();
1133                                 if (status < 0)
1134                                         break;
1135                                 if (status & ST_DSK_CHG) {
1136                                         toc_uptodate = 0;
1137                                         opt_invalidate_buffers();
1138                                 }
1139                         }
1140                         skip = 0;
1141                         if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1142                                 toc_uptodate = 0;
1143                                 opt_invalidate_buffers();
1144                                 printk((status & ST_DOOR_OPEN)
1145                                        ? "optcd: door open\n"
1146                                        : "optcd: disk removed\n");
1147                                 state = S_IDLE;
1148                                 while (CURRENT_VALID)
1149                                         end_request(0);
1150                                 return;
1151                         }
1152                         if (!CURRENT_VALID) {
1153                                 state = S_STOP;
1154                                 loop_again = 1;
1155                                 break;
1156                         }
1157                         next_bn = CURRENT -> sector / 4;
1158                         lba2msf(next_bn, &msf);
1159                         read_count = N_BUFS;
1160                         msf.cdmsf_frame1 = read_count; /* Not BCD! */
1161 
1162                         DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x",
1163                                 msf.cdmsf_min0,
1164                                 msf.cdmsf_sec0,
1165                                 msf.cdmsf_frame0,
1166                                 msf.cdmsf_min1,
1167                                 msf.cdmsf_sec1,
1168                                 msf.cdmsf_frame1));
1169                         DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d"
1170                                 " buf_out:%d buf_bn:%d",
1171                                 next_bn,
1172                                 buf_in,
1173                                 buf_out,
1174                                 buf_bn[buf_in]));
1175 
1176                         exec_read_cmd(COMREAD, &msf);
1177                         state = S_DATA;
1178                         timeout = READ_TIMEOUT;
1179                         break;
1180                 }
1181                 case S_DATA:
1182                         flags = stdt_flags() & (FL_STEN|FL_DTEN);
1183 
1184 #if DEBUG_STATE
1185                         if (flags != flags_old) {
1186                                 flags_old = flags;
1187                                 printk("optcd: flags:%x\n", flags);
1188                         }
1189                         if (flags == FL_STEN)
1190                                 printk("timeout cnt: %d\n", timeout);
1191 #endif
1192 
1193                         switch (flags) {
1194                         case FL_DTEN:           /* only STEN low */
1195                                 if (!tries--) {
1196                                         printk("optcd: read block %d failed; "
1197                                                 "Giving up\n", next_bn);
1198                                         if (transfer_is_active) {
1199                                                 tries = 0;
1200                                                 break;
1201                                         }
1202                                         if (CURRENT_VALID)
1203                                                 end_request(0);
1204                                         tries = 5;
1205                                 }
1206                                 state = S_START;
1207                                 timeout = READ_TIMEOUT;
1208                                 loop_again = 1;
1209                         case (FL_STEN|FL_DTEN):  /* both high */
1210                                 break;
1211                         default:        /* DTEN low */
1212                                 tries = 5;
1213                                 if (!CURRENT_VALID && buf_in == buf_out) {
1214                                         state = S_STOP;
1215                                         loop_again = 1;
1216                                         break;
1217                                 }
1218                                 if (read_count<=0)
1219                                         printk("optcd: warning - try to read"
1220                                                 " 0 frames\n");
1221                                 while (read_count) {
1222                                         buf_bn[buf_in] = NOBUF;
1223                                         if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) {
1224                                         /* should be no waiting here!?? */
1225                                                 printk("read_count:%d "
1226                                                    "CURRENT->nr_sectors:%ld "
1227                                                    "buf_in:%d\n",
1228                                                         read_count,
1229                                                         CURRENT->nr_sectors,
1230                                                         buf_in);
1231                                                 printk("transfer active: %x\n",
1232                                                         transfer_is_active);
1233                                                 read_count = 0;
1234                                                 state = S_STOP;
1235                                                 loop_again = 1;
1236                                                 end_request(0);
1237                                                 break;
1238                                         }
1239                                         fetch_data(buf+
1240                                             CD_FRAMESIZE*buf_in,
1241                                             CD_FRAMESIZE);
1242                                         read_count--;
1243 
1244                                         DEBUG((DEBUG_REQUEST,
1245                                                 "S_DATA; ---I've read data- "
1246                                                 "read_count: %d",
1247                                                 read_count));
1248                                         DEBUG((DEBUG_REQUEST,
1249                                                 "next_bn:%d  buf_in:%d "
1250                                                 "buf_out:%d  buf_bn:%d",
1251                                                 next_bn,
1252                                                 buf_in,
1253                                                 buf_out,
1254                                                 buf_bn[buf_in]));
1255 
1256                                         buf_bn[buf_in] = next_bn++;
1257                                         if (buf_out == NOBUF)
1258                                                 buf_out = buf_in;
1259                                         buf_in = buf_in + 1 ==
1260                                                 N_BUFS ? 0 : buf_in + 1;
1261                                 }
1262                                 if (!transfer_is_active) {
1263                                         while (CURRENT_VALID) {
1264                                                 transfer();
1265                                                 if (CURRENT -> nr_sectors == 0)
1266                                                         end_request(1);
1267                                                 else
1268                                                         break;
1269                                         }
1270                                 }
1271 
1272                                 if (CURRENT_VALID
1273                                     && (CURRENT -> sector / 4 < next_bn ||
1274                                     CURRENT -> sector / 4 >
1275                                      next_bn + N_BUFS)) {
1276                                         state = S_STOP;
1277                                         loop_again = 1;
1278                                         break;
1279                                 }
1280                                 timeout = READ_TIMEOUT;
1281                                 if (read_count == 0) {
1282                                         state = S_STOP;
1283                                         loop_again = 1;
1284                                         break;
1285                                 }
1286                         }
1287                         break;
1288                 case S_STOP:
1289                         if (read_count != 0)
1290                                 printk("optcd: discard data=%x frames\n",
1291                                         read_count);
1292                         flush_data();
1293                         if (send_cmd(COMDRVST)) {
1294                                 state = S_IDLE;
1295                                 while (CURRENT_VALID)
1296                                         end_request(0);
1297                                 return;
1298                         }
1299                         state = S_STOPPING;
1300                         timeout = STOP_TIMEOUT;
1301                         break;
1302                 case S_STOPPING:
1303                         status = fetch_status();
1304                         if (status < 0 && timeout)
1305                                         break;
1306                         if ((status >= 0) && (status & ST_DSK_CHG)) {
1307                                 toc_uptodate = 0;
1308                                 opt_invalidate_buffers();
1309                         }
1310                         if (CURRENT_VALID) {
1311                                 if (status >= 0) {
1312                                         state = S_READ;
1313                                         loop_again = 1;
1314                                         skip = 1;
1315                                         break;
1316                                 } else {
1317                                         state = S_START;
1318                                         timeout = 1;
1319                                 }
1320                         } else {
1321                                 state = S_IDLE;
1322                                 return;
1323                         }
1324                         break;
1325                 default:
1326                         printk("optcd: invalid state %d\n", state);
1327                         return;
1328                 } /* case */
1329         } /* while */
1330 
1331         if (!timeout--) {
1332                 printk("optcd: timeout in state %d\n", state);
1333                 state = S_STOP;
1334                 if (exec_cmd(COMSTOP) < 0) {
1335                         state = S_IDLE;
1336                         while (CURRENT_VALID)
1337                                 end_request(0);
1338                         return;
1339                 }
1340         }
1341 
1342         SET_REQ_TIMER(poll, HZ/100);
1343 }
1344 
1345 
1346 static void do_optcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1347 {
1348         DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1349                CURRENT -> sector, CURRENT -> nr_sectors));
1350 
1351         if (disk_info.audio) {
1352                 printk("optcd: Error: tried to mount an Audio CD\n");
1353                 end_request(0);
1354                 return;
1355         }
1356 
1357         transfer_is_active = 1;
1358         while (CURRENT_VALID) {
1359                 if (CURRENT->bh) {
1360                         if (!buffer_locked(CURRENT->bh))
1361                                 panic(DEVICE_NAME ": block not locked");
1362                 }
1363                 transfer();     /* First try to transfer block from buffers */
1364                 if (CURRENT -> nr_sectors == 0) {
1365                         end_request(1);
1366                 } else {        /* Want to read a block not in buffer */
1367                         buf_out = NOBUF;
1368                         if (state == S_IDLE) {
1369                                 /* %% Should this block the request queue?? */
1370                                 if (update_toc() < 0) {
1371                                         while (CURRENT_VALID)
1372                                                 end_request(0);
1373                                         break;
1374                                 }
1375                                 /* Start state machine */
1376                                 state = S_START;
1377                                 timeout = READ_TIMEOUT;
1378                                 tries = 5;
1379                                 /* %% why not start right away?? */
1380                                 SET_REQ_TIMER(poll, HZ/100);
1381                         }
1382                         break;
1383                 }
1384         }
1385         transfer_is_active = 0;
1386 
1387         DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1388                next_bn, buf_in, buf_out, buf_bn[buf_in]));
1389         DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1390 }
1391 
1392 /* IOCTLs */
1393 
1394 
1395 static char auto_eject = 0;
1396 
1397 static int cdrompause(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1398 {
1399         int status;
1400 
1401         if (audio_status != CDROM_AUDIO_PLAY)
1402                 return -EINVAL;
1403 
1404         status = exec_cmd(COMPAUSEON);
1405         if (status < 0) {
1406                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1407                 return -EIO;
1408         }
1409         audio_status = CDROM_AUDIO_PAUSED;
1410         return 0;
1411 }
1412 
1413 
1414 static int cdromresume(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1415 {
1416         int status;
1417 
1418         if (audio_status != CDROM_AUDIO_PAUSED)
1419                 return -EINVAL;
1420 
1421         status = exec_cmd(COMPAUSEOFF);
1422         if (status < 0) {
1423                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1424                 audio_status = CDROM_AUDIO_ERROR;
1425                 return -EIO;
1426         }
1427         audio_status = CDROM_AUDIO_PLAY;
1428         return 0;
1429 }
1430 
1431 
1432 static int cdromplaymsf(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1433 {
1434         int status;
1435         struct cdrom_msf msf;
1436 
1437         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1438         if (status)
1439                 return status;
1440         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1441 
1442         bin2bcd(&msf);
1443         status = exec_long_cmd(COMPLAY, &msf);
1444         if (status < 0) {
1445                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1446                 audio_status = CDROM_AUDIO_ERROR;
1447                 return -EIO;
1448         }
1449 
1450         audio_status = CDROM_AUDIO_PLAY;
1451         return 0;
1452 }
1453 
1454 
1455 static int cdromplaytrkind(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1456 {
1457         int status;
1458         struct cdrom_ti ti;
1459         struct cdrom_msf msf;
1460 
1461         status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1462         if (status)
1463                 return status;
1464         memcpy_fromfs(&ti, (void *) arg, sizeof ti);
1465 
1466         if (ti.cdti_trk0 < disk_info.first
1467             || ti.cdti_trk0 > disk_info.last
1468             || ti.cdti_trk1 < ti.cdti_trk0)
1469                 return -EINVAL;
1470         if (ti.cdti_trk1 > disk_info.last)
1471                 ti.cdti_trk1 = disk_info.last;
1472 
1473         msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1474         msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1475         msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1476         msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1477         msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1478         msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1479 
1480         DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1481                 msf.cdmsf_min0,
1482                 msf.cdmsf_sec0,
1483                 msf.cdmsf_frame0,
1484                 msf.cdmsf_min1,
1485                 msf.cdmsf_sec1,
1486                 msf.cdmsf_frame1));
1487 
1488         bin2bcd(&msf);
1489         status = exec_long_cmd(COMPLAY, &msf);
1490         if (status < 0) {
1491                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1492                 audio_status = CDROM_AUDIO_ERROR;
1493                 return -EIO;
1494         }
1495 
1496         audio_status = CDROM_AUDIO_PLAY;
1497         return 0;
1498 }
1499 
1500 
1501 static int cdromreadtochdr(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1502 {
1503         int status;
1504         struct cdrom_tochdr tochdr;
1505 
1506         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1507         if (status)
1508                 return status;
1509 
1510         tochdr.cdth_trk0 = disk_info.first;
1511         tochdr.cdth_trk1 = disk_info.last;
1512 
1513         memcpy_tofs((void *) arg, &tochdr, sizeof tochdr);
1514         return 0;
1515 }
1516 
1517 
1518 static int cdromreadtocentry(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1519 {
1520         int status;
1521         struct cdrom_tocentry entry;
1522         struct cdrom_subchnl *tocptr;
1523 
1524         status = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
1525         if (status)
1526                 return status;
1527         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1528         if (status)
1529                 return status;
1530         memcpy_fromfs(&entry, (void *) arg, sizeof entry);
1531 
1532         if (entry.cdte_track == CDROM_LEADOUT)
1533                 tocptr = &toc[disk_info.last + 1];
1534         else if (entry.cdte_track > disk_info.last
1535                 || entry.cdte_track < disk_info.first)
1536                 return -EINVAL;
1537         else
1538                 tocptr = &toc[entry.cdte_track];
1539 
1540         entry.cdte_adr = tocptr->cdsc_adr;
1541         entry.cdte_ctrl = tocptr->cdsc_ctrl;
1542         entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1543         entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1544         entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1545         /* %% What should go into entry.cdte_datamode? */
1546 
1547         if (entry.cdte_format == CDROM_LBA)
1548                 msf2lba(&entry.cdte_addr);
1549         else if (entry.cdte_format != CDROM_MSF)
1550                 return -EINVAL;
1551 
1552         memcpy_tofs((void *) arg, &entry, sizeof entry);
1553         return 0;
1554 }
1555 
1556 
1557 static int cdromvolctrl(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1558 {
1559         int status;
1560         struct cdrom_volctrl volctrl;
1561         struct cdrom_msf msf;
1562 
1563         status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1564         if (status)
1565                 return status;
1566         memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl);
1567 
1568         msf.cdmsf_min0 = 0x10;
1569         msf.cdmsf_sec0 = 0x32;
1570         msf.cdmsf_frame0 = volctrl.channel0;
1571         msf.cdmsf_min1 = volctrl.channel1;
1572         msf.cdmsf_sec1 = volctrl.channel2;
1573         msf.cdmsf_frame1 = volctrl.channel3;
1574 
1575         status = exec_long_cmd(COMCHCTRL, &msf);
1576         if (status < 0) {
1577                 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1578                 return -EIO;
1579         }
1580         return 0;
1581 }
1582 
1583 
1584 static int cdromsubchnl(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1585 {
1586         int status;
1587         struct cdrom_subchnl subchnl;
1588 
1589         status = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl);
1590         if (status)
1591                 return status;
1592         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1593         if (status)
1594                 return status;
1595         memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
1596 
1597         if (subchnl.cdsc_format != CDROM_LBA
1598             && subchnl.cdsc_format != CDROM_MSF)
1599                 return -EINVAL;
1600 
1601         status = get_q_channel(&subchnl);
1602         if (status < 0) {
1603                 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1604                 return -EIO;
1605         }
1606 
1607         memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
1608         return 0;
1609 }
1610 
1611 
1612 static int cdromread(unsigned long arg, int blocksize, int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
1613 {
1614         int status;
1615         struct cdrom_msf msf;
1616         char buf[CD_FRAMESIZE_RAWER];
1617 
1618         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1619         if (status)
1620                 return status;
1621         status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1622         if (status)
1623                 return status;
1624         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1625 
1626         bin2bcd(&msf);
1627         msf.cdmsf_min1 = 0;
1628         msf.cdmsf_sec1 = 0;
1629         msf.cdmsf_frame1 = 1;   /* read only one frame */
1630         status = exec_read_cmd(cmd, &msf);
1631 
1632         DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1633 
1634         if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1635                 return -EIO;
1636         fetch_data(buf, blocksize);
1637 
1638         memcpy_tofs((void *) arg, &buf, blocksize);
1639         return 0;
1640 }
1641 
1642 
1643 static int cdromseek(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1644 {
1645         int status;
1646         struct cdrom_msf msf;
1647 
1648         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1649         if (status)
1650                 return status;
1651         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1652 
1653         bin2bcd(&msf);
1654         status = exec_seek_cmd(COMSEEK, &msf);
1655 
1656         DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1657 
1658         if (status < 0)
1659                 return -EIO;
1660         return 0;
1661 }
1662 
1663 
1664 #ifdef MULTISESSION
1665 static int cdrommultisession(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1666 {
1667         int status;
1668         struct cdrom_multisession ms;
1669 
1670         status = verify_area(VERIFY_READ, (void*) arg, sizeof ms);
1671         if (status)
1672                 return status;
1673         status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1674         if (status)
1675                 return status;
1676         memcpy_fromfs(&ms, (void*) arg, sizeof ms);
1677 
1678         ms.addr.msf.minute = disk_info.last_session.minute;
1679         ms.addr.msf.second = disk_info.last_session.second;
1680         ms.addr.msf.frame = disk_info.last_session.frame;
1681 
1682         if (ms.addr_format != CDROM_LBA
1683            && ms.addr_format != CDROM_MSF)
1684                 return -EINVAL;
1685         if (ms.addr_format == CDROM_LBA)
1686                 msf2lba(&ms.addr);
1687 
1688         ms.xa_flag = disk_info.xa;
1689 
1690         memcpy_tofs((void*) arg, &ms,
1691                 sizeof(struct cdrom_multisession));
1692 
1693 #if DEBUG_MULTIS
1694         if (ms.addr_format == CDROM_MSF)
1695                 printk("optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1696                         ms.xa_flag,
1697                         ms.addr.msf.minute,
1698                         ms.addr.msf.second,
1699                         ms.addr.msf.frame);
1700         else
1701                 printk("optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1702                         ms.xa_flag,
1703                         ms.addr.lba,
1704                         disk_info.last_session.minute,
1705                         disk_info.last_session.second,
1706                         disk_info.last_session.frame);
1707 #endif DEBUG_MULTIS
1708 
1709         return 0;
1710 }
1711 #endif MULTISESSION
1712 
1713 
1714 static int cdromreset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1715 {
1716         if (state != S_IDLE) {
1717                 error = 1;
1718                 tries = 0;
1719         }
1720 
1721         toc_uptodate = 0;
1722         disk_changed = 1;
1723         opt_invalidate_buffers();
1724         audio_status = CDROM_AUDIO_NO_STATUS;
1725 
1726         if (!reset_drive())
1727                 return -EIO;
1728         return 0;
1729 }
1730 
1731 /* VFS calls */
1732 
1733 
1734 static int opt_ioctl(struct inode *ip, struct file *fp,
     /* [previous][next][first][last][top][bottom][index][help] */
1735                      unsigned int cmd, unsigned long arg)
1736 {
1737         int status, err, retval = 0;
1738 
1739         DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1740 
1741         if (!ip)
1742                 return -EINVAL;
1743 
1744         if (cmd == CDROMRESET)
1745                 return cdromreset();
1746 
1747         /* is do_optcd_request or another ioctl busy? */
1748         if (state != S_IDLE || in_vfs)
1749                 return -EBUSY;
1750 
1751         in_vfs = 1;
1752 
1753         status = drive_status();
1754         if (status < 0) {
1755                 DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1756                 in_vfs = 0;
1757                 return -EIO;
1758         }
1759 
1760         if (status & ST_DOOR_OPEN)
1761                 switch (cmd) {  /* Actions that can be taken with door open */
1762                 case CDROMCLOSETRAY:
1763                         /* We do this before trying to read the toc. */
1764                         err = exec_cmd(COMCLOSE);
1765                         if (err < 0) {
1766                                 DEBUG((DEBUG_VFS,
1767                                        "exec_cmd COMCLOSE: %02x", -err));
1768                                 in_vfs = 0;
1769                                 return -EIO;
1770                         }
1771                         break;
1772                 default:        in_vfs = 0;
1773                                 return -EBUSY;
1774                 }
1775 
1776         err = update_toc();
1777         if (err < 0) {
1778                 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1779                 in_vfs = 0;
1780                 return -EIO;
1781         }
1782 
1783         DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1784 
1785         switch (cmd) {
1786         case CDROMPAUSE:        retval = cdrompause(); break;
1787         case CDROMRESUME:       retval = cdromresume(); break;
1788         case CDROMPLAYMSF:      retval = cdromplaymsf(arg); break;
1789         case CDROMPLAYTRKIND:   retval = cdromplaytrkind(arg); break;
1790         case CDROMREADTOCHDR:   retval = cdromreadtochdr(arg); break;
1791         case CDROMREADTOCENTRY: retval = cdromreadtocentry(arg); break;
1792 
1793         case CDROMSTOP:         err = exec_cmd(COMSTOP);
1794                                 if (err < 0) {
1795                                         DEBUG((DEBUG_VFS,
1796                                                 "exec_cmd COMSTOP: %02x",
1797                                                 -err));
1798                                         retval = -EIO;
1799                                 } else
1800                                         audio_status = CDROM_AUDIO_NO_STATUS;
1801                                 break;
1802         case CDROMSTART:        break;  /* This is a no-op */
1803         case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
1804                                 if (err < 0) {
1805                                         DEBUG((DEBUG_VFS,
1806                                                 "exec_cmd COMUNLOCK: %02x",
1807                                                 -err));
1808                                         retval = -EIO;
1809                                         break;
1810                                 }
1811                                 err = exec_cmd(COMOPEN);
1812                                 if (err < 0) {
1813                                         DEBUG((DEBUG_VFS,
1814                                                 "exec_cmd COMOPEN: %02x",
1815                                                 -err));
1816                                         retval = -EIO;
1817                                 }
1818                                 break;
1819 
1820         case CDROMVOLCTRL:      retval = cdromvolctrl(arg); break;
1821         case CDROMSUBCHNL:      retval = cdromsubchnl(arg); break;
1822 
1823         /* The drive detects the mode and automatically delivers the
1824            correct 2048 bytes, so we don't need these IOCTLs */
1825         case CDROMREADMODE2:    retval = -EINVAL; break;
1826         case CDROMREADMODE1:    retval = -EINVAL; break;
1827 
1828         /* Drive doesn't support reading audio */
1829         case CDROMREADAUDIO:    retval = -EINVAL; break;
1830 
1831         case CDROMEJECT_SW:     auto_eject = (char) arg;
1832                                 break;
1833 
1834 #ifdef MULTISESSION
1835         case CDROMMULTISESSION: retval = cdrommultisession(arg); break;
1836 #endif
1837 
1838         case CDROM_GET_UPC:     retval = -EINVAL; break; /* not implemented */
1839         case CDROMVOLREAD:      retval = -EINVAL; break; /* not implemented */
1840 
1841         case CDROMREADRAW:
1842                         /* this drive delivers 2340 bytes in raw mode */
1843                         retval = cdromread(arg, CD_FRAMESIZE_RAW1, COMREADRAW);
1844                         break;
1845         case CDROMREADCOOKED:
1846                         retval = cdromread(arg, CD_FRAMESIZE, COMREAD);
1847                         break;
1848         case CDROMREADALL:
1849                         retval = cdromread(arg, CD_FRAMESIZE_RAWER, COMREADALL);
1850                         break;
1851 
1852         case CDROMSEEK:         retval = cdromseek(arg); break;
1853         case CDROMPLAYBLK:      retval = -EINVAL; break; /* not implemented */
1854         case CDROMCLOSETRAY:    break;  /* The action was taken earlier */
1855         default:                retval = -EINVAL;
1856         }
1857         in_vfs = 0;
1858         return retval;
1859 }
1860 
1861 
1862 static int open_count = 0;
1863 
1864 /* Open device special file; check that a disk is in. */
1865 static int opt_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1866 {
1867         DEBUG((DEBUG_VFS, "starting opt_open"));
1868 
1869         if (!open_count && state == S_IDLE) {
1870                 int status;
1871 
1872                 toc_uptodate = 0;
1873                 opt_invalidate_buffers();
1874 
1875                 status = exec_cmd(COMCLOSE);    /* close door */
1876                 if (status < 0) {
1877                         DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1878                 }
1879 
1880                 status = drive_status();
1881                 if (status < 0) {
1882                         DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1883                         return -EIO;
1884                 }
1885                 DEBUG((DEBUG_VFS, "status: %02x", status));
1886                 if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1887                         printk("optcd: no disk or door open\n");
1888                         return -EIO;
1889                 }
1890                 status = exec_cmd(COMLOCK);             /* Lock door */
1891                 if (status < 0) {
1892                         DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1893                 }
1894                 status = update_toc();  /* Read table of contents */
1895                 if (status < 0) {
1896                         DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1897                         status = exec_cmd(COMUNLOCK);   /* Unlock door */
1898                         if (status < 0) {
1899                                 DEBUG((DEBUG_VFS,
1900                                        "exec_cmd COMUNLOCK: %02x", -status));
1901                         }
1902                         return -EIO;
1903                 }
1904                 open_count++;
1905         }
1906         MOD_INC_USE_COUNT;
1907 
1908         DEBUG((DEBUG_VFS, "exiting opt_open"));
1909 
1910         return 0;
1911 }
1912 
1913 
1914 /* Release device special file; flush all blocks from the buffer cache */
1915 static void opt_release(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1916 {
1917         int status;
1918 
1919         DEBUG((DEBUG_VFS, "executing opt_release"));
1920         DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1921                 ip, ip -> i_rdev, fp));
1922 
1923         if (!--open_count) {
1924                 toc_uptodate = 0;
1925                 opt_invalidate_buffers();
1926                 sync_dev(ip -> i_rdev);
1927                 invalidate_buffers(ip -> i_rdev);
1928                 status = exec_cmd(COMUNLOCK);   /* Unlock door */
1929                 if (status < 0) {
1930                         DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1931                 }
1932                 if (auto_eject) {
1933                         status = exec_cmd(COMOPEN);
1934                         DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1935                 }
1936                 CLEAR_TIMER;
1937                 CLEAR_REQ_TIMER;
1938         }
1939         MOD_DEC_USE_COUNT;
1940 }
1941 
1942 
1943 /* Check if disk has been changed */
1944 static int opt_media_change(kdev_t dev)
     /* [previous][next][first][last][top][bottom][index][help] */
1945 {
1946         DEBUG((DEBUG_VFS, "executing opt_media_change"));
1947         DEBUG((DEBUG_VFS, "dev: 0x%x; disk_changed = %d\n", dev, disk_changed));
1948 
1949         if (disk_changed) {
1950                 disk_changed = 0;
1951                 return 1;
1952         }
1953         return 0;
1954 }
1955 
1956 /* Driver initialisation */
1957 
1958 
1959 /* Returns 1 if a drive is detected with a version string
1960    starting with "DOLPHIN". Otherwise 0. */
1961 static int version_ok(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1962 {
1963         char devname[100];
1964         int count, i, ch, status;
1965 
1966         status = exec_cmd(COMVERSION);
1967         if (status < 0) {
1968                 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1969                 return 0;
1970         }
1971         if ((count = get_data(1)) < 0) {
1972                 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1973                 return 0;
1974         }
1975         for (i = 0, ch = -1; count > 0; count--) {
1976                 if ((ch = get_data(1)) < 0) {
1977                         DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1978                         break;
1979                 }
1980                 if (i < 99)
1981                         devname[i++] = ch;
1982         }
1983         devname[i] = '\0';
1984         if (ch < 0)
1985                 return 0;
1986 
1987         printk("optcd: Device %s detected\n", devname);
1988         return ((devname[0] == 'D')
1989              && (devname[1] == 'O')
1990              && (devname[2] == 'L')
1991              && (devname[3] == 'P')
1992              && (devname[4] == 'H')
1993              && (devname[5] == 'I')
1994              && (devname[6] == 'N'));
1995 }
1996 
1997 
1998 static struct file_operations opt_fops = {
1999         NULL,                   /* lseek - default */
2000         block_read,             /* read - general block-dev read */
2001         block_write,            /* write - general block-dev write */
2002         NULL,                   /* readdir - bad */
2003         NULL,                   /* select */
2004         opt_ioctl,              /* ioctl */
2005         NULL,                   /* mmap */
2006         opt_open,               /* open */
2007         opt_release,            /* release */
2008         NULL,                   /* fsync */
2009         NULL,                   /* fasync */
2010         opt_media_change,       /* media change */
2011         NULL                    /* revalidate */
2012 };
2013 
2014 
2015 /* Get kernel parameter when used as a kernel driver */
2016 void optcd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
2017 {
2018         if (ints[0] > 0)
2019                 optcd_port = ints[1];
2020 }
2021 
2022 /* Test for presence of drive and initialize it. Called at boot time
2023    or during module initialisation. */
2024 int optcd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2025 {
2026         int status;
2027 
2028         if (optcd_port <= 0) {
2029                 printk("optcd: no Optics Storage CDROM Initialization\n");
2030                 return -EIO;
2031         }
2032         if (check_region(optcd_port, 4)) {
2033                 printk("optcd: conflict, I/O port 0x%x already used\n",
2034                         optcd_port);
2035                 return -EIO;
2036         }
2037 
2038         if (!reset_drive()) {
2039                 printk("optcd: drive at 0x%x not ready\n", optcd_port);
2040                 return -EIO;
2041         }
2042         if (!version_ok()) {
2043                 printk("optcd: unknown drive detected; aborting\n");
2044                 return -EIO;
2045         }
2046         status = exec_cmd(COMINITDOUBLE);
2047         if (status < 0) {
2048                 printk("optcd: cannot init double speed mode\n");
2049                 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2050                 return -EIO;
2051         }
2052         if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
2053         {
2054                 printk("optcd: unable to get major %d\n", MAJOR_NR);
2055                 return -EIO;
2056         }
2057 
2058         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
2059         read_ahead[MAJOR_NR] = 4;
2060         request_region(optcd_port, 4, "optcd");
2061 
2062         printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2063         return 0;
2064 }
2065 
2066 
2067 #ifdef MODULE
2068 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2069 {
2070         return optcd_init();
2071 }
2072 
2073 
2074 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2075 {
2076         if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2077                 printk("optcd: what's that: can't unregister\n");
2078                 return;
2079         }
2080         release_region(optcd_port, 4);
2081         printk(KERN_INFO "optcd: module released.\n");
2082 }
2083 #endif MODULE

/* [previous][next][first][last][top][bottom][index][help] */