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. version_ok
  51. optcd_setup
  52. optcd_init
  53. init_module
  54. cleanup_module

   1 /*      linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver
   2         $Id: optcd.c,v 1.20 1996/01/17 19:44:39 root Exp root $
   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 static void lba2msf(int lba, struct cdrom_msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541         DEBUG((DEBUG_CONV, "lba2msf %d", lba));
 542         lba += CD_MSF_OFFSET;
 543         msf->cdmsf_min0 = lba / 4500; lba %= 4500;
 544         msf->cdmsf_sec0 = lba / 75;
 545         msf->cdmsf_frame0 = lba % 75;
 546         msf->cdmsf_min1 = 0;
 547         msf->cdmsf_sec1 = 0;
 548         msf->cdmsf_frame1 = 0;
 549         bin2bcd(msf);
 550 }
 551 
 552 
 553 /* Two BCD digits to binary */
 554 inline static u_char bcd2bin(u_char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
 555 {
 556         DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
 557         return (bcd >> 4) * 10 + (bcd & 0x0f);
 558 }
 559 
 560 
 561 union cd_addr {
 562         struct {
 563                 u_char  minute;
 564                 u_char  second;
 565                 u_char  frame;
 566         } msf;
 567         int     lba;
 568 };
 569 
 570 
 571 static void msf2lba(union cd_addr *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 572 {
 573         addr->lba = addr->msf.minute * 4500
 574                     + addr->msf.second * 75
 575                     + addr->msf.frame - CD_MSF_OFFSET;
 576 }
 577 
 578 
 579 /* Minute, second, frame address BCD to binary or to linear address,
 580    depending on MODE */
 581 static void msf_bcd2bin(union cd_addr *addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 582 {
 583         addr->msf.minute = bcd2bin(addr->msf.minute);
 584         addr->msf.second = bcd2bin(addr->msf.second);
 585         addr->msf.frame = bcd2bin(addr->msf.frame);
 586 }
 587 
 588 /* High level drive commands */
 589 
 590 
 591 static int audio_status = CDROM_AUDIO_NO_STATUS;
 592 static char toc_uptodate = 0;
 593 
 594 /* Get drive status, flagging completion of audio play and disk changes. */
 595 static int drive_status(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 596 {
 597         int status;
 598 
 599         status = exec_cmd(COMIOCTLISTAT);
 600         DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
 601         if (status < 0)
 602                 return status;
 603         if (status == 0xff)     /* No status available */
 604                 return -ERR_IF_NOSTAT;
 605 
 606         if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
 607                 (audio_status == CDROM_AUDIO_PLAY)) {
 608                 audio_status = CDROM_AUDIO_COMPLETED;
 609         }
 610 
 611         if (status & ST_DSK_CHG) {
 612                 toc_uptodate = 0;
 613                 audio_status = CDROM_AUDIO_NO_STATUS;
 614         }
 615 
 616         return status;
 617 }
 618 
 619 
 620 /* Read the current Q-channel info. Also used for reading the
 621    table of contents. qp->cdsc_format must be set on entry to
 622    indicate the desired address format */
 623 static int get_q_channel(struct cdrom_subchnl *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
 624 {
 625         int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
 626 
 627         status = drive_status();
 628         if (status < 0)
 629                 return status;
 630         qp->cdsc_audiostatus = audio_status;
 631 
 632         status = exec_cmd(COMSUBQ);
 633         if (status < 0)
 634                 return status;
 635 
 636         d1 = get_data(0);
 637         if (d1 < 0)
 638                 return d1;
 639         qp->cdsc_adr = d1;
 640         qp->cdsc_ctrl = d1 >> 4;
 641 
 642         d2 = get_data(0);
 643         if (d2 < 0)
 644                 return d2;
 645         qp->cdsc_trk = bcd2bin(d2);
 646 
 647         d3 = get_data(0);
 648         if (d3 < 0)
 649                 return d3;
 650         qp->cdsc_ind = bcd2bin(d3);
 651 
 652         d4 = get_data(0);
 653         if (d4 < 0)
 654                 return d4;
 655         qp->cdsc_reladdr.msf.minute = d4;
 656 
 657         d5 = get_data(0);
 658         if (d5 < 0)
 659                 return d5;
 660         qp->cdsc_reladdr.msf.second = d5;
 661 
 662         d6 = get_data(0);
 663         if (d6 < 0)
 664                 return d6;
 665         qp->cdsc_reladdr.msf.frame = d6;
 666 
 667         d7 = get_data(0);
 668         if (d7 < 0)
 669                 return d7;
 670         /* byte not used */
 671 
 672         d8 = get_data(0);
 673         if (d8 < 0)
 674                 return d8;
 675         qp->cdsc_absaddr.msf.minute = d8;
 676 
 677         d9 = get_data(0);
 678         if (d9 < 0)
 679                 return d9;
 680         qp->cdsc_absaddr.msf.second = d9;
 681 
 682         d10 = get_data(0);
 683         if (d10 < 0)
 684                 return d10;
 685         qp->cdsc_absaddr.msf.frame = d10;
 686 
 687         DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 688                 d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
 689 
 690         msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_absaddr);
 691         msf_bcd2bin((union cd_addr *)/*%%*/&qp->cdsc_reladdr);
 692         if (qp->cdsc_format == CDROM_LBA) {
 693                 msf2lba((union cd_addr *)/*%%*/&qp->cdsc_absaddr);
 694                 msf2lba((union cd_addr *)/*%%*/&qp->cdsc_reladdr);
 695         }
 696 
 697         return 0;
 698 }
 699 
 700 /* Table of contents handling */
 701 
 702 
 703 /* Errors in table of contents */
 704 #define ERR_TOC_MISSINGINFO     0x120
 705 #define ERR_TOC_MISSINGENTRY    0x121
 706 
 707 
 708 struct msf {
 709         u_char  minute;
 710         u_char  second;
 711         u_char  frame;
 712 };
 713 
 714 struct cdrom_disk_info {
 715         unsigned char   first;
 716         unsigned char   last;
 717         struct msf      disk_length;
 718         struct msf      first_track;
 719         /* Multisession info: */
 720         unsigned char   next;
 721         struct msf      next_session;
 722         struct msf      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 void toc_debug_info(int i)
     /* [previous][next][first][last][top][bottom][index][help] */
 746 {
 747         printk("#%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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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("optcd: Multisession support experimental, "
 967                         "see linux/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 
 978 #define CURRENT_VALID \
 979         (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR \
 980          && CURRENT -> cmd == READ && CURRENT -> sector != -1)
 981 
 982 
 983 #define BLOCKSIZE       2048
 984 #define BLOCKSIZE_RAW   2336
 985 #define BLOCKSIZE_ALL   2646
 986 #define N_BUFS          16
 987 #define NOBUF           -1
 988 
 989 
 990 /* Buffer for block size conversion. */
 991 static char buf[BLOCKSIZE * N_BUFS];
 992 static volatile int buf_bn[N_BUFS], next_bn;
 993 static volatile int buf_in = 0, buf_out = NOBUF;
 994 
 995 inline static void opt_invalidate_buffers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 996 {
 997         int i;
 998 
 999         DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers"));
1000 
1001         for (i = 0; i < N_BUFS; i++)
1002                 buf_bn[i] = NOBUF;
1003         buf_out = NOBUF;
1004 }
1005 
1006 
1007 /* Take care of the different block sizes between cdrom and Linux.
1008    When Linux gets variable block sizes this will probably go away. */
1009 static void transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1010 {
1011 #if DEBUG_BUFFERS | DEBUG_REQUEST
1012         printk("optcd: executing transfer\n");
1013 #endif
1014 
1015         if (!CURRENT_VALID)
1016                 return;
1017         while (CURRENT -> nr_sectors) {
1018                 int bn = CURRENT -> sector / 4;
1019                 int i, offs, nr_sectors;
1020                 for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i);
1021 
1022                 DEBUG((DEBUG_REQUEST, "found %d", i));
1023 
1024                 if (i >= N_BUFS) {
1025                         buf_out = NOBUF;
1026                         break;
1027                 }
1028 
1029                 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
1030                 nr_sectors = 4 - (CURRENT -> sector & 3);
1031 
1032                 if (buf_out != i) {
1033                         buf_out = i;
1034                         if (buf_bn[i] != bn) {
1035                                 buf_out = NOBUF;
1036                                 continue;
1037                         }
1038                 }
1039 
1040                 if (nr_sectors > CURRENT -> nr_sectors)
1041                         nr_sectors = CURRENT -> nr_sectors;
1042                 memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512);
1043                 CURRENT -> nr_sectors -= nr_sectors;
1044                 CURRENT -> sector += nr_sectors;
1045                 CURRENT -> buffer += nr_sectors * 512;
1046         }
1047 }
1048 
1049 
1050 /* State machine for reading disk blocks */
1051 
1052 enum state_e {
1053         S_IDLE,         /* 0 */
1054         S_START,        /* 1 */
1055         S_READ,         /* 2 */
1056         S_DATA,         /* 3 */
1057         S_STOP,         /* 4 */
1058         S_STOPPING      /* 5 */
1059 };
1060 
1061 static volatile enum state_e state = S_IDLE;
1062 #if DEBUG_STATE
1063 static volatile enum state_e state_old = S_STOP;
1064 static volatile int flags_old = 0;
1065 static volatile long state_n = 0;
1066 #endif
1067 
1068 
1069 static volatile int transfer_is_active = 0;
1070 static volatile int error = 0;  /* %% do something with this?? */
1071 static int tries;               /* ibid?? */
1072 
1073 static void poll(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1074 {
1075         static int timeout;
1076         static volatile int read_count = 1;
1077         int flags;
1078         int loop_again = 1;
1079         int status = 0;
1080         int skip = 0;
1081 
1082         if (error) {
1083                 printk("optcd: I/O error 0x%02x\n", error);
1084                 opt_invalidate_buffers();
1085                 if (!tries--) {
1086                         printk("optcd: read block %d failed; Giving up\n",
1087                                next_bn);
1088                         if (transfer_is_active)
1089                                 loop_again = 0;
1090                         if (CURRENT_VALID)
1091                                 end_request(0);
1092                         tries = 5;
1093                 }
1094                 error = 0;
1095                 state = S_STOP;
1096         }
1097 
1098         while (loop_again)
1099         {
1100                 loop_again = 0; /* each case must flip this back to 1 if we want
1101                                  to come back up here */
1102 
1103 #if DEBUG_STATE
1104                 if (state == state_old)
1105                         state_n++;
1106                 else {
1107                         state_old = state;
1108                         if (++state_n > 1)
1109                                 printk("optcd: %ld times in previous state\n",
1110                                         state_n);
1111                         printk("optcd: state %d\n", state);
1112                         state_n = 0;
1113                 }
1114 #endif
1115 
1116                 switch (state) {
1117                 case S_IDLE:
1118                         return;
1119                 case S_START:
1120                         if (send_cmd(COMDRVST))
1121                                 return;
1122                         state = S_READ;
1123                         timeout = READ_TIMEOUT;
1124                         break;
1125                 case S_READ: {
1126                         struct cdrom_msf msf;
1127                         if (!skip) {
1128                                 status = fetch_status();
1129                                 if (status < 0)
1130                                         break;
1131                                 if (status & ST_DSK_CHG) {
1132                                         toc_uptodate = 0;
1133                                         opt_invalidate_buffers();
1134                                 }
1135                         }
1136                         skip = 0;
1137                         if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1138                                 toc_uptodate = 0;
1139                                 printk((status & ST_DOOR_OPEN)
1140                                        ? "optcd: door open\n"
1141                                        : "optcd: disk removed\n");
1142                                 if (transfer_is_active) {
1143                                         state = S_START;
1144                                         loop_again = 1;
1145                                         break;
1146                                 }
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                                             BLOCKSIZE*buf_in,
1241                                             BLOCKSIZE);
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                                 return;
1295                         state = S_STOPPING;
1296                         timeout = STOP_TIMEOUT;
1297                         break;
1298                 case S_STOPPING:
1299                         status = fetch_status();
1300                         if (status < 0 && timeout)
1301                                         break;
1302                         if ((status >= 0) && (status & ST_DSK_CHG)) {
1303                                 toc_uptodate = 0;
1304                                 opt_invalidate_buffers();
1305                         }
1306                         if (CURRENT_VALID) {
1307                                 if (status >= 0) {
1308                                         state = S_READ;
1309                                         loop_again = 1;
1310                                         skip = 1;
1311                                         break;
1312                                 } else {
1313                                         state = S_START;
1314                                         timeout = 1;
1315                                 }
1316                         } else {
1317                                 state = S_IDLE;
1318                                 return;
1319                         }
1320                         break;
1321                 default:
1322                         printk("optcd: invalid state %d\n", state);
1323                         return;
1324                 } /* case */
1325         } /* while */
1326 
1327         if (!timeout--) {
1328                 printk("optcd: timeout in state %d\n", state);
1329                 state = S_STOP;
1330                 if (exec_cmd(COMSTOP) < 0)
1331                         return;
1332         }
1333 
1334         SET_TIMER(poll, HZ/100);
1335 }
1336 
1337 
1338 static void do_optcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1339 {
1340         DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)",
1341                CURRENT -> sector, CURRENT -> nr_sectors));
1342 
1343         if (disk_info.audio) {
1344                 printk("optcd: Error: tried to mount an Audio CD\n");
1345                 end_request(0);
1346                 return;
1347         }
1348 
1349         transfer_is_active = 1;
1350         while (CURRENT_VALID) {
1351                 if (CURRENT->bh) {
1352                         if (!buffer_locked(CURRENT->bh))
1353                                 panic(DEVICE_NAME ": block not locked");
1354                 }
1355                 transfer();     /* First try to transfer block from buffers */
1356                 if (CURRENT -> nr_sectors == 0) {
1357                         end_request(1);
1358                 } else {        /* Want to read a block not in buffer */
1359                         buf_out = NOBUF;
1360                         if (state == S_IDLE) {
1361                                 /* %% Should this block the request queue?? */
1362                                 if (update_toc() < 0) {
1363                                         while (CURRENT_VALID)
1364                                                 end_request(0);
1365                                         break;
1366                                 }
1367                                 /* Start state machine */
1368                                 state = S_START;
1369                                 tries = 5;
1370                                 /* %% why not start right away?? */
1371                                 SET_TIMER(poll, HZ/100);
1372                         }
1373                         break;
1374                 }
1375         }
1376         transfer_is_active = 0;
1377 
1378         DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1379                next_bn, buf_in, buf_out, buf_bn[buf_in]));
1380         DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1381 }
1382 
1383 /* IOCTLs */
1384 
1385 
1386 static char auto_eject = 0;
1387 
1388 static int cdrompause(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1389 {
1390         int status;
1391 
1392         if (audio_status != CDROM_AUDIO_PLAY)
1393                 return -EINVAL;
1394 
1395         status = exec_cmd(COMPAUSEON);
1396         if (status < 0) {
1397                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1398                 return -EIO;
1399         }
1400         audio_status = CDROM_AUDIO_PAUSED;
1401         return 0;
1402 }
1403 
1404 
1405 static int cdromresume(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1406 {
1407         int status;
1408 
1409         if (audio_status != CDROM_AUDIO_PAUSED)
1410                 return -EINVAL;
1411 
1412         status = exec_cmd(COMPAUSEOFF);
1413         if (status < 0) {
1414                 DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1415                 audio_status = CDROM_AUDIO_ERROR;
1416                 return -EIO;
1417         }
1418         audio_status = CDROM_AUDIO_PLAY;
1419         return 0;
1420 }
1421 
1422 
1423 static int cdromplaymsf(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1424 {
1425         int status;
1426         struct cdrom_msf msf;
1427 
1428         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1429         if (status)
1430                 return status;
1431         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1432 
1433         bin2bcd(&msf);
1434         status = exec_long_cmd(COMPLAY, &msf);
1435         if (status < 0) {
1436                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1437                 audio_status = CDROM_AUDIO_ERROR;
1438                 return -EIO;
1439         }
1440 
1441         audio_status = CDROM_AUDIO_PLAY;
1442         return 0;
1443 }
1444 
1445 
1446 static int cdromplaytrkind(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1447 {
1448         int status;
1449         struct cdrom_ti ti;
1450         struct cdrom_msf msf;
1451 
1452         status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
1453         if (status)
1454                 return status;
1455         memcpy_fromfs(&ti, (void *) arg, sizeof ti);
1456 
1457         if (ti.cdti_trk0 < disk_info.first
1458             || ti.cdti_trk0 > disk_info.last
1459             || ti.cdti_trk1 < ti.cdti_trk0)
1460                 return -EINVAL;
1461         if (ti.cdti_trk1 > disk_info.last)
1462                 ti.cdti_trk1 = disk_info.last;
1463 
1464         msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1465         msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1466         msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1467         msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1468         msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1469         msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1470 
1471         DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1472                 msf.cdmsf_min0,
1473                 msf.cdmsf_sec0,
1474                 msf.cdmsf_frame0,
1475                 msf.cdmsf_min1,
1476                 msf.cdmsf_sec1,
1477                 msf.cdmsf_frame1));
1478 
1479         bin2bcd(&msf);
1480         status = exec_long_cmd(COMPLAY, &msf);
1481         if (status < 0) {
1482                 DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1483                 audio_status = CDROM_AUDIO_ERROR;
1484                 return -EIO;
1485         }
1486 
1487         audio_status = CDROM_AUDIO_PLAY;
1488         return 0;
1489 }
1490 
1491 
1492 static int cdromreadtochdr(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1493 {
1494         int status;
1495         struct cdrom_tochdr tochdr;
1496 
1497         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
1498         if (status)
1499                 return status;
1500 
1501         tochdr.cdth_trk0 = disk_info.first;
1502         tochdr.cdth_trk1 = disk_info.last;
1503 
1504         memcpy_tofs((void *) arg, &tochdr, sizeof tochdr);
1505         return 0;
1506 }
1507 
1508 
1509 static int cdromreadtocentry(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1510 {
1511         int status;
1512         struct cdrom_tocentry entry;
1513         struct cdrom_subchnl *tocptr;
1514 
1515         status = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
1516         if (status)
1517                 return status;
1518         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
1519         if (status)
1520                 return status;
1521         memcpy_fromfs(&entry, (void *) arg, sizeof entry);
1522 
1523         if (entry.cdte_track == CDROM_LEADOUT)
1524                 tocptr = &toc[disk_info.last + 1];
1525         else if (entry.cdte_track > disk_info.last
1526                 || entry.cdte_track < disk_info.first)
1527                 return -EINVAL;
1528         else
1529                 tocptr = &toc[entry.cdte_track];
1530 
1531         entry.cdte_adr = tocptr->cdsc_adr;
1532         entry.cdte_ctrl = tocptr->cdsc_ctrl;
1533         entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1534         entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1535         entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1536         /* %% What should go into entry.cdte_datamode? */
1537 
1538         if (entry.cdte_format == CDROM_LBA)
1539                 msf2lba((union cd_addr *)/*%%*/&entry.cdte_addr);
1540         else if (entry.cdte_format != CDROM_MSF)
1541                 return -EINVAL;
1542 
1543         memcpy_tofs((void *) arg, &entry, sizeof entry);
1544         return 0;
1545 }
1546 
1547 
1548 static int cdromvolctrl(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1549 {
1550         int status;
1551         struct cdrom_volctrl volctrl;
1552         struct cdrom_msf msf;
1553 
1554         status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
1555         if (status)
1556                 return status;
1557         memcpy_fromfs(&volctrl, (char *) arg, sizeof volctrl);
1558 
1559         msf.cdmsf_min0 = 0x10;
1560         msf.cdmsf_sec0 = 0x32;
1561         msf.cdmsf_frame0 = volctrl.channel0;
1562         msf.cdmsf_min1 = volctrl.channel1;
1563         msf.cdmsf_sec1 = volctrl.channel2;
1564         msf.cdmsf_frame1 = volctrl.channel3;
1565 
1566         status = exec_long_cmd(COMCHCTRL, &msf);
1567         if (status < 0) {
1568                 DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1569                 return -EIO;
1570         }
1571         return 0;
1572 }
1573 
1574 
1575 static int cdromsubchnl(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1576 {
1577         int status;
1578         struct cdrom_subchnl subchnl;
1579 
1580         status = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl);
1581         if (status)
1582                 return status;
1583         status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
1584         if (status)
1585                 return status;
1586         memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
1587 
1588         if (subchnl.cdsc_format != CDROM_LBA
1589             && subchnl.cdsc_format != CDROM_MSF)
1590                 return -EINVAL;
1591 
1592         status = get_q_channel(&subchnl);
1593         if (status < 0) {
1594                 DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1595                 return -EIO;
1596         }
1597 
1598         memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
1599         return 0;
1600 }
1601 
1602 
1603 static int cdromread(unsigned long arg, int blocksize, int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
1604 {
1605         int status;
1606         struct cdrom_msf msf;
1607         char buf[BLOCKSIZE_ALL];
1608 
1609         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1610         if (status)
1611                 return status;
1612         status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
1613         if (status)
1614                 return status;
1615         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1616 
1617         bin2bcd(&msf);
1618         msf.cdmsf_min1 = 0;
1619         msf.cdmsf_sec1 = 0;
1620         msf.cdmsf_frame1 = 1;   /* read only one frame */
1621         status = exec_read_cmd(cmd, &msf);
1622 
1623         DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1624 
1625         if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1626                 return -EIO;
1627         fetch_data(buf, blocksize);
1628 
1629         memcpy_tofs((void *) arg, &buf, blocksize);
1630         return 0;
1631 }
1632 
1633 
1634 static int cdromseek(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1635 {
1636         int status;
1637         struct cdrom_msf msf;
1638 
1639         status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
1640         if (status)
1641                 return status;
1642         memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1643 
1644         bin2bcd(&msf);
1645         status = exec_seek_cmd(COMSEEK, &msf);
1646 
1647         DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1648 
1649         if (status < 0)
1650                 return -EIO;
1651         return 0;
1652 }
1653 
1654 
1655 #ifdef MULTISESSION
1656 static int cdrommultisession(unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
1657 {
1658         int status;
1659         struct cdrom_multisession ms;
1660 
1661         status = verify_area(VERIFY_READ, (void*) arg, sizeof ms);
1662         if (status)
1663                 return status;
1664         status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
1665         if (status)
1666                 return status;
1667         memcpy_fromfs(&ms, (void*) arg, sizeof ms);
1668 
1669         ms.addr.msf.minute = disk_info.last_session.minute;
1670         ms.addr.msf.second = disk_info.last_session.second;
1671         ms.addr.msf.frame = disk_info.last_session.frame;
1672 
1673         if (ms.addr_format != CDROM_LBA
1674            && ms.addr_format != CDROM_MSF)
1675                 return -EINVAL;
1676         if (ms.addr_format == CDROM_LBA)
1677                 msf2lba((union cd_addr *)/*%%*/&ms.addr);
1678 
1679         ms.xa_flag = disk_info.xa;
1680 
1681         memcpy_tofs((void*) arg, &ms,
1682                 sizeof(struct cdrom_multisession));
1683 
1684 #if DEBUG_MULTIS
1685         if (ms.addr_format == CDROM_MSF)
1686                 printk("optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1687                         ms.xa_flag,
1688                         ms.addr.msf.minute,
1689                         ms.addr.msf.second,
1690                         ms.addr.msf.frame);
1691         else
1692                 printk("optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1693                         ms.xa_flag,
1694                         ms.addr.lba,
1695                         disk_info.last_session.minute,
1696                         disk_info.last_session.second,
1697                         disk_info.last_session.frame);
1698 #endif DEBUG_MULTIS
1699 
1700         return 0;
1701 }
1702 #endif MULTISESSION
1703 
1704 
1705 static int cdromreset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1706 {
1707         if (state != S_IDLE) {
1708                 error = 1;
1709                 tries = 0;
1710         }
1711 
1712         toc_uptodate = 0;
1713         opt_invalidate_buffers();
1714         audio_status = CDROM_AUDIO_NO_STATUS;
1715 
1716         if (!reset_drive())
1717                 return -EIO;
1718         return 0;
1719 }
1720 
1721 /* VFS calls */
1722 
1723 
1724 static int opt_ioctl(struct inode *ip, struct file *fp,
     /* [previous][next][first][last][top][bottom][index][help] */
1725                      unsigned int cmd, unsigned long arg)
1726 {
1727         int err;
1728 
1729         DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1730 
1731         if (!ip)
1732                 return -EINVAL;
1733 
1734         if (cmd == CDROMRESET)
1735                 return cdromreset();
1736 
1737         if (state != S_IDLE)
1738                 return -EBUSY;
1739 
1740         err = drive_status();
1741         if (err < 0) {
1742                 DEBUG((DEBUG_VFS, "drive_status: %02x", -err));
1743                 return -EIO;
1744         }
1745         err = update_toc();
1746         if (err < 0) {
1747                 DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1748                 return -EIO;
1749         }
1750 
1751         DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1752 
1753         switch (cmd) {
1754         case CDROMPAUSE:        return cdrompause();
1755         case CDROMRESUME:       return cdromresume();
1756         case CDROMPLAYMSF:      return cdromplaymsf(arg);
1757         case CDROMPLAYTRKIND:   return cdromplaytrkind(arg);
1758         case CDROMREADTOCHDR:   return cdromreadtochdr(arg);
1759         case CDROMREADTOCENTRY: return cdromreadtocentry(arg);
1760 
1761         case CDROMSTOP:         err = exec_cmd(COMSTOP);
1762                                 if (err < 0) {
1763                                         DEBUG((DEBUG_VFS,
1764                                                 "exec_cmd COMSTOP: %02x",
1765                                                 -err));
1766                                         return -EIO;
1767                                 }
1768                                 audio_status = CDROM_AUDIO_NO_STATUS;
1769                                 break;
1770         case CDROMSTART:        err = exec_cmd(COMCLOSE);  /* What else? */
1771                                 if (err < 0) {
1772                                         DEBUG((DEBUG_VFS,
1773                                                 "exec_cmd COMCLOSE: %02x",
1774                                                 -err));
1775                                         return -EIO;
1776                                 }
1777                                 break;
1778         case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
1779                                 if (err < 0) {
1780                                         DEBUG((DEBUG_VFS,
1781                                                 "exec_cmd COMUNLOCK: %02x",
1782                                                 -err));
1783                                         return -EIO;
1784                                 }
1785                                 err = exec_cmd(COMOPEN);
1786                                 if (err < 0) {
1787                                         DEBUG((DEBUG_VFS,
1788                                                 "exec_cmd COMOPEN: %02x",
1789                                                 -err));
1790                                         return -EIO;
1791                                 }
1792                                 break;
1793 
1794         case CDROMVOLCTRL:      return cdromvolctrl(arg);
1795         case CDROMSUBCHNL:      return cdromsubchnl(arg);
1796 
1797         case CDROMREADAUDIO:    return -EINVAL; /* not implemented */
1798         case CDROMEJECT_SW:     auto_eject = (char) arg;
1799                                 break;
1800 
1801 #ifdef MULTISESSION
1802         case CDROMMULTISESSION: return cdrommultisession(arg);
1803 #endif
1804 
1805         case CDROM_GET_UPC:     return -EINVAL; /* not implemented */
1806         case CDROMVOLREAD:      return -EINVAL; /* not implemented */
1807 
1808         case CDROMREADRAW:
1809                         return cdromread(arg, BLOCKSIZE_RAW, COMREADRAW);
1810         case CDROMREADCOOKED:
1811                         return cdromread(arg, BLOCKSIZE, COMREAD);
1812         case CDROMSEEK:         return cdromseek(arg);
1813         case CDROMPLAYBLK:      return -EINVAL; /* not implemented */
1814         default:                return -EINVAL;
1815         }
1816         return 0;
1817 }
1818 
1819 
1820 static int open_count = 0;
1821 
1822 /* Open device special file; check that a disk is in. */
1823 static int opt_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1824 {
1825         DEBUG((DEBUG_VFS, "starting opt_open"));
1826 
1827         if (!open_count++ && state == S_IDLE) {
1828                 int status;
1829 
1830                 opt_invalidate_buffers();
1831                 status = drive_status();
1832                 if (status < 0) {
1833                         DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1834                         return -EIO;
1835                 }
1836                 DEBUG((DEBUG_VFS, "status: %02x", status));
1837                 if (status & ST_DOOR_OPEN) {
1838                         status = exec_cmd(COMCLOSE);    /* close door */
1839                         if (status < 0) {
1840                                 DEBUG((DEBUG_VFS,
1841                                         "exec_cmd COMCLOSE: %02x", -status));
1842                         }
1843                         status = drive_status();        /* try again */
1844                         if (status < 0) {
1845                                 DEBUG((DEBUG_VFS,
1846                                         "drive_status: %02x", -status));
1847                                 return -EIO;
1848                         }
1849                         DEBUG((DEBUG_VFS, "status: %02x", status));
1850                 }
1851                 if (status & (ST_DOOR_OPEN|ST_DRVERR)) {
1852                         printk("optcd: no disk or door open\n");
1853                         return -EIO;
1854                 }
1855                 status = exec_cmd(COMLOCK);             /* Lock door */
1856                 if (status < 0) {
1857                         DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1858                 }
1859                 status = update_toc();  /* Read table of contents */
1860                 if (status < 0) {
1861                         DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1862                         return -EIO;
1863                 }
1864         }
1865         MOD_INC_USE_COUNT;
1866 
1867         DEBUG((DEBUG_VFS, "exiting opt_open"));
1868 
1869         return 0;
1870 }
1871 
1872 
1873 /* Release device special file; flush all blocks from the buffer cache */
1874 static void opt_release(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1875 {
1876         int status;
1877 
1878         DEBUG((DEBUG_VFS, "executing opt_release"));
1879         DEBUG((DEBUG_VFS, "inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1880                 ip, ip -> i_rdev, fp));
1881 
1882         if (!--open_count) {
1883                 opt_invalidate_buffers();
1884                 sync_dev(ip -> i_rdev);
1885                 invalidate_buffers(ip -> i_rdev);
1886                 status = exec_cmd(COMUNLOCK);   /* Unlock door */
1887                 if (status < 0) {
1888                         DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1889                 }
1890                 if (auto_eject) {
1891                         status = exec_cmd(COMOPEN);
1892                         DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1893                 }
1894                 CLEAR_TIMER;
1895         }
1896         MOD_DEC_USE_COUNT;
1897 }
1898 
1899 /* Driver initialisation */
1900 
1901 
1902 /* Returns 1 if a drive is detected with a version string
1903    starting with "DOLPHIN". Otherwise 0. */
1904 static int version_ok(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1905 {
1906         char devname[100];
1907         int count, i, ch, status;
1908 
1909         status = exec_cmd(COMVERSION);
1910         if (status < 0) {
1911                 DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1912                 return 0;
1913         }
1914         if ((count = get_data(1)) < 0) {
1915                 DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1916                 return 0;
1917         }
1918         for (i = 0, ch = -1; count > 0; count--) {
1919                 if ((ch = get_data(1)) < 0) {
1920                         DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1921                         break;
1922                 }
1923                 if (i < 99)
1924                         devname[i++] = ch;
1925         }
1926         devname[i] = '\0';
1927         if (ch < 0)
1928                 return 0;
1929 
1930         printk("optcd: Device %s detected\n", devname);
1931         return ((devname[0] == 'D')
1932              && (devname[1] == 'O')
1933              && (devname[2] == 'L')
1934              && (devname[3] == 'P')
1935              && (devname[4] == 'H')
1936              && (devname[5] == 'I')
1937              && (devname[6] == 'N'));
1938 }
1939 
1940 
1941 static struct file_operations opt_fops = {
1942         NULL,           /* lseek - default */
1943         block_read,     /* read - general block-dev read */
1944         block_write,    /* write - general block-dev write */
1945         NULL,           /* readdir - bad */
1946         NULL,           /* select */
1947         opt_ioctl,      /* ioctl */
1948         NULL,           /* mmap */
1949         opt_open,       /* open */
1950         opt_release,    /* release */
1951         NULL,           /* fsync */
1952         NULL,           /* fasync */
1953         NULL,           /* media change */
1954         NULL            /* revalidate */
1955 };
1956 
1957 
1958 /* Get kernel parameter when used as a kernel driver */
1959 void optcd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
1960 {
1961         if (ints[0] > 0)
1962                 optcd_port = ints[1];
1963 }
1964 
1965 /* Test for presence of drive and initialize it. Called at boot time
1966    or during module initialisation. */
1967 int optcd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1968 {
1969         int status;
1970 
1971         if (optcd_port <= 0) {
1972                 printk("optcd: no Optics Storage CDROM Initialization\n");
1973                 return -EIO;
1974         }
1975         if (check_region(optcd_port, 4)) {
1976                 printk("optcd: conflict, I/O port 0x%x already used\n",
1977                         optcd_port);
1978                 return -EIO;
1979         }
1980 
1981         if (!reset_drive()) {
1982                 printk("optcd: drive at 0x%x not ready\n", optcd_port);
1983                 return -EIO;
1984         }
1985         if (!version_ok()) {
1986                 printk("optcd: unknown drive detected; aborting\n");
1987                 return -EIO;
1988         }
1989         status = exec_cmd(COMINITDOUBLE);
1990         if (status < 0) {
1991                 printk("optcd: cannot init double speed mode\n");
1992                 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
1993                 return -EIO;
1994         }
1995         if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
1996         {
1997                 printk("optcd: unable to get major %d\n", MAJOR_NR);
1998                 return -EIO;
1999         }
2000 
2001         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
2002         read_ahead[MAJOR_NR] = 4;
2003         request_region(optcd_port, 4, "optcd");
2004 
2005         printk("optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2006         return 0;
2007 }
2008 
2009 
2010 #ifdef MODULE
2011 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2012 {
2013         return optcd_init();
2014 }
2015 
2016 
2017 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2018 {
2019         if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2020                 printk("optcd: what's that: can't unregister\n");
2021                 return;
2022         }
2023         release_region(optcd_port, 4);
2024         printk("optcd: module released.\n");
2025 }
2026 #endif MODULE

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