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

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