root/drivers/cdrom/optcd.c

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

DEFINITIONS

This source file includes following definitions.
  1. optFlags
  2. sten_low
  3. dten_low
  4. sleep_timer
  5. sleep_status
  6. sleep_sten_low
  7. sleep_dten_low
  8. optSendCmd
  9. optSendParams
  10. optGetExecStatus
  11. optSleepTillExecStatus
  12. optStatus
  13. optGetData
  14. optReadData
  15. optFlushData
  16. optResetDrive
  17. optCmd
  18. optPlayCmd
  19. optReadCmd
  20. bin2bcd
  21. hsg2msf
  22. bcd2bin
  23. msf2hsg
  24. optGetStatus
  25. optGetQChannelInfo
  26. optGetDiskInfo
  27. optGetToc
  28. optUpdateToc
  29. opt_invalidate_buffers
  30. opt_transfer
  31. opt_poll
  32. do_optcd_request
  33. opt_ioctl
  34. opt_open
  35. opt_release
  36. version_ok
  37. optcd_setup
  38. optcd_init
  39. init_module
  40. cleanup_module
  41. isp16_detect
  42. isp16_no_ide__detect
  43. isp16_with_ide__detect
  44. isp16_config

   1 /*      $Id: optcd.c,v 1.3 1995/08/24 19:54:27 root Exp root $
   2         linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver
   3 
   4         Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl)
   5 
   6         Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks
   7         by Eberhard Moenkeberg (emoenke@gwdg.de). ISP16 detection and
   8         configuration by Eric van der Maarel (maarel@marin.nl), with some data
   9         communicated by Vadim V. Model (vadim@rbrf.msk.su).
  10 
  11         This program is free software; you can redistribute it and/or modify
  12         it under the terms of the GNU General Public License as published by
  13         the Free Software Foundation; either version 2, or (at your option)
  14         any later version.
  15 
  16         This program is distributed in the hope that it will be useful,
  17         but WITHOUT ANY WARRANTY; without even the implied warranty of
  18         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19         GNU General Public License for more details.
  20 
  21         You should have received a copy of the GNU General Public License
  22         along with this program; if not, write to the Free Software
  23         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 
  25         History
  26         14-5-95         v0.0    Plays sound tracks. No reading of data CDs yet.
  27                                 Detection of disk change doesn't work.
  28         21-5-95         v0.1    First ALPHA version. CD can be mounted. The
  29                                 device major nr is borrowed from the Aztech
  30                                 driver. Speed is around 240 kb/s, as measured
  31                                 with "time dd if=/dev/cdrom of=/dev/null \
  32                                 bs=2048 count=4096".
  33         24-6-95         v0.2    Reworked the #defines for the command codes
  34                                 and the like, as well as the structure of
  35                                 the hardware communication protocol, to
  36                                 reflect the "official" documentation, kindly
  37                                 supplied by C.K. Tan, Optics Storage Pte. Ltd.
  38                                 Also tidied up the state machine somewhat.
  39         28-6-95         v0.3    Removed the ISP-16 interface code, as this
  40                                 should go into its own driver. The driver now
  41                                 has its own major nr.
  42                                 Disk change detection now seems to work, too.
  43                                 This version became part of the standard
  44                                 kernel as of version 1.3.7
  45         24-9-95         v0.4    Re-inserted ISP-16 interface code which I
  46                                 copied from sjcd.c, with a few changes.
  47                                 Updated README.optcd. Submitted for
  48                                 inclusion in 1.3.21
  49         29-9-95         v0.4a   Fixed bug that prevented compilation as module
  50 */
  51 
  52 #include <linux/module.h>
  53 
  54 #include <linux/errno.h>
  55 #include <linux/mm.h>
  56 #include <linux/fs.h>
  57 #include <linux/timer.h>
  58 #include <linux/kernel.h>
  59 #include <linux/cdrom.h>
  60 #include <linux/ioport.h>
  61 #include <linux/major.h>
  62 
  63 #include <asm/io.h>
  64 
  65 #define MAJOR_NR OPTICS_CDROM_MAJOR
  66 
  67 # include <linux/blk.h>
  68 #define optcd_port optcd        /* Needed for the modutils. */
  69 # include <linux/optcd.h>
  70 
  71 
  72 /* Some (Media)Magic */
  73 /* define types of drive the interface on an ISP16 card may be looking at */
  74 #define ISP16_DRIVE_X 0x00
  75 #define ISP16_SONY  0x02
  76 #define ISP16_PANASONIC0 0x02
  77 #define ISP16_SANYO0 0x02
  78 #define ISP16_MITSUMI  0x04
  79 #define ISP16_PANASONIC1 0x06
  80 #define ISP16_SANYO1 0x06
  81 #define ISP16_DRIVE_NOT_USED 0x08  /* not used */
  82 #define ISP16_DRIVE_SET_MASK 0xF1  /* don't change 0-bit or 4-7-bits*/
  83 /* ...for port */
  84 #define ISP16_DRIVE_SET_PORT 0xF8D
  85 /* set io parameters */
  86 #define ISP16_BASE_340  0x00
  87 #define ISP16_BASE_330  0x40
  88 #define ISP16_BASE_360  0x80
  89 #define ISP16_BASE_320  0xC0
  90 #define ISP16_IRQ_X  0x00
  91 #define ISP16_IRQ_5  0x04  /* shouldn't be used due to soundcard conflicts */
  92 #define ISP16_IRQ_7  0x08  /* shouldn't be used due to soundcard conflicts */
  93 #define ISP16_IRQ_3  0x0C
  94 #define ISP16_IRQ_9  0x10
  95 #define ISP16_IRQ_10  0x14
  96 #define ISP16_IRQ_11  0x18
  97 #define ISP16_DMA_X  0x03
  98 #define ISP16_DMA_3  0x00
  99 #define ISP16_DMA_5  0x00
 100 #define ISP16_DMA_6  0x01
 101 #define ISP16_DMA_7  0x02
 102 #define ISP16_IO_SET_MASK  0x20  /* don't change 5-bit */
 103 /* ...for port */
 104 #define ISP16_IO_SET_PORT  0xF8E
 105 /* enable the drive */
 106 #define ISP16_NO_IDE__ENABLE_CDROM_PORT  0xF90  /* ISP16 without IDE interface */
 107 #define ISP16_IDE__ENABLE_CDROM_PORT  0xF91  /* ISP16 with IDE interface */
 108 #define ISP16_ENABLE_CDROM  0x80  /* seven bit */
 109 
 110 /* the magic stuff */
 111 #define ISP16_CTRL_PORT  0xF8F
 112 #define ISP16_NO_IDE__CTRL  0xE2  /* ISP16 without IDE interface */
 113 #define ISP16_IDE__CTRL  0xE3  /* ISP16 with IDE interface */
 114 
 115 static short isp16_detect(void);
 116 static short isp16_no_ide__detect(void);
 117 static short isp16_with_ide__detect(void);
 118 static short isp16_config( int base, u_char drive_type, int irq, int dma );
 119 static short isp16_type; /* dependent on type of interface card */
 120 static u_char isp16_ctrl;
 121 static u_short isp16_enable_cdrom_port;
 122 
 123 
 124 static short optcd_port = OPTCD_PORTBASE;
 125 
 126 /* Read current status/data availability flags */
 127 inline static int optFlags(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 128         return inb(STATUS_PORT) & FL_STDT;
 129 }
 130 
 131 /* Wait for status available; return TRUE on timeout */
 132 static int sten_low(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 133         int no_status;
 134         unsigned long count = 0;
 135         while ((no_status = (optFlags() & FL_STEN)))
 136                 if (++count >= BUSY_TIMEOUT)
 137                         break;
 138 #ifdef DEBUG_DRIVE_IF
 139         if (no_status)
 140                 printk("optcd: timeout waiting for STEN low\n");
 141         else
 142                 printk("optcd: STEN low after %ld\n", count);
 143 #endif
 144         return no_status;
 145 }
 146 
 147 /* Wait for data available; return TRUE on timeout */
 148 static int dten_low(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 149         int no_data;
 150         unsigned long count = 0;
 151         while ((no_data = (optFlags() & FL_DTEN)))
 152                 if (++count >= BUSY_TIMEOUT)
 153                         break;
 154 #ifdef DEBUG_DRIVE_IF
 155         if (no_data)
 156                 printk("optcd: timeout waiting for DTEN low\n");
 157         else
 158                 printk("optcd: DTEN low after %ld\n", count);
 159 #endif
 160         return no_data;
 161 }
 162 
 163 /* Facilities for polled waiting for status or data */
 164 static int sleep_timeout;               /* Max amount of time still to sleep */
 165 static unsigned char sleep_flags;       /* Flags read last time around */
 166 static struct wait_queue *waitq = NULL;
 167 static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL};
 168 
 169 /* Timer routine: wake up when either of FL_STEN or FL_DTEN goes down,
 170  * or when timeout expires. Otherwise wait some more.
 171  */
 172 static void sleep_timer(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 173         if ((sleep_flags = optFlags()) != FL_STDT) {
 174                 wake_up(&waitq);
 175                 return;
 176         }
 177         if (--sleep_timeout <= 0) {
 178                 wake_up(&waitq);
 179                 return;
 180         }
 181         SET_TIMER(sleep_timer, 1);
 182 }
 183 
 184 /* Sleep until any of FL_STEN or FL_DTEN go down, or until timeout.
 185  * sleep_timeout must be set first.
 186  */
 187 static int sleep_status(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 188 #ifdef DEBUG_DRIVE_IF
 189         printk("optcd: sleeping %d on status\n", sleep_timeout);
 190 #endif
 191         if (sleep_timeout <= 0)         /* timeout immediately */
 192                 return FL_STDT;
 193         if ((sleep_flags = optFlags()) == FL_STDT) {
 194                 SET_TIMER(sleep_timer, 1);
 195                 sleep_on(&waitq);
 196         }
 197 #ifdef DEBUG_DRIVE_IF
 198         printk("optcd: woken up with %d to go, flags %d\n",
 199                 sleep_timeout, sleep_flags);
 200 #endif
 201         return sleep_flags;
 202 }
 203 
 204 /* Sleep until status available; return TRUE on timeout */
 205 inline static int sleep_sten_low(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 206         int flags;
 207         sleep_timeout = SLEEP_TIMEOUT;
 208         flags = sleep_status();
 209 #ifdef DEBUG_DRIVE_IF
 210         if (!(flags & FL_DTEN))
 211                 printk("optcd: DTEN while waiting for STEN\n");
 212 #endif
 213         return flags & FL_STEN;
 214 }
 215 
 216 /* Sleep until data available; return TRUE on timeout */
 217 inline static int sleep_dten_low(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 218         int flags;
 219         sleep_timeout = SLEEP_TIMEOUT;
 220         flags = sleep_status();
 221 #ifdef DEBUG_DRIVE_IF
 222         if (!(flags & FL_STEN))
 223                 printk("optcd: STEN while waiting for DTEN\n");
 224 #endif
 225         return flags & FL_DTEN;
 226 }
 227 
 228 /* Send command code. Return <0 indicates error */
 229 static int optSendCmd(int cmd) {
     /* [previous][next][first][last][top][bottom][index][help] */
 230         unsigned char ack;
 231 #if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
 232         printk("optcd: executing command 0x%02x\n", cmd);
 233 #endif
 234         outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
 235         outb(cmd, COMIN_PORT);          /* Send command code */
 236         if (sten_low())                 /* Wait for status available */
 237                 return -ERR_IF_CMD_TIMEOUT;
 238         ack = inb(DATA_PORT);           /* read command acknowledge */
 239 #ifdef DEBUG_DRIVE_IF
 240         printk("optcd: acknowledge code 0x%02x\n", ack);
 241 #endif
 242         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 243         return ack==ST_OP_OK ? 0 : -ack;
 244 }
 245 
 246 /* Send command parameters. Return <0 indicates error */
 247 static int optSendParams(struct opt_Play_msf *params) {
     /* [previous][next][first][last][top][bottom][index][help] */
 248         unsigned char ack;
 249 #if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS)
 250         printk("optcd: params %02x:%02x:%02x %02x:%02x:%02x\n",
 251                 params->start.min, params->start.sec, params->start.frame,
 252                 params->end.min, params->end.sec, params->end.frame);
 253 #endif
 254         outb(params -> start.min, COMIN_PORT);
 255         outb(params -> start.sec, COMIN_PORT);
 256         outb(params -> start.frame, COMIN_PORT);
 257         outb(params -> end.min, COMIN_PORT);
 258         outb(params -> end.sec, COMIN_PORT);
 259         outb(params -> end.frame, COMIN_PORT);
 260         if (sten_low())                 /* Wait for status available */
 261                 return -ERR_IF_CMD_TIMEOUT;
 262         ack = inb(DATA_PORT);           /* read command acknowledge */
 263 #ifdef DEBUG_DRIVE_IF
 264         printk("optcd: acknowledge code 0x%02x\n", ack);
 265 #endif
 266         return ack==ST_PA_OK ? 0 : -ack;
 267 }
 268 
 269 /* Return execution status for quick response commands, i.e. busy wait.
 270  * Return value <0 indicates timeout.
 271  */
 272 static int optGetExecStatus(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 273         unsigned char exec_status;
 274         if (sten_low())                 /* Wait for status available */
 275                 return -ERR_IF_CMD_TIMEOUT;
 276         exec_status = inb(DATA_PORT);   /* read command execution status */
 277 #ifdef DEBUG_DRIVE_IF
 278         printk("optcd: returned execution status: 0x%02x\n", exec_status);
 279 #endif
 280         return exec_status;
 281 }
 282 
 283 /* Return execution status for slow commands. Only use when no data is
 284  * expected. Return value <0 indicates timeout.
 285  */
 286 static int optSleepTillExecStatus(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 287         unsigned char exec_status;
 288         if (sleep_sten_low())           /* Wait for status available */
 289                 return -ERR_IF_CMD_TIMEOUT;
 290         exec_status = inb(DATA_PORT);   /* read command execution status */
 291 #ifdef DEBUG_DRIVE_IF
 292         printk("optcd: returned execution status: 0x%02x\n", exec_status);
 293 #endif
 294         return exec_status;
 295 }
 296 
 297 /* Fetch status that has previously been waited for. <0 means not available */
 298 inline static int optStatus(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 299         unsigned char status;
 300         if (optFlags() & FL_STEN)
 301                 return -ERR_IF_NOSTAT;
 302         status = inb(DATA_PORT);
 303 #ifdef DEBUG_DRIVE_IF
 304         printk("optcd: read status: 0x%02x\n", status);
 305 #endif
 306         return status;
 307 }
 308 
 309 /* Wait for extra byte of data that a command returns */
 310 static int optGetData(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 311         unsigned char data;
 312         if (sten_low())
 313                 return -ERR_IF_DATA_TIMEOUT;
 314         data = inb(DATA_PORT);
 315 #ifdef DEBUG_DRIVE_IF
 316         printk("optcd: read data: 0x%02x\n", data);
 317 #endif
 318         return data;
 319 }
 320 
 321 /* Read data that has previously been waited for. */
 322 inline static void optReadData(char *buf, int n) {
     /* [previous][next][first][last][top][bottom][index][help] */
 323         insb(DATA_PORT, buf, n);
 324 }
 325 
 326 /* Flush status and data fifos */
 327 inline static void optFlushData(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 328         while (optFlags() != FL_STDT)
 329                 inb(DATA_PORT);
 330 }
 331 
 332 /* Write something to RESET_PORT and wait. Return TRUE upon success. */
 333 static int optResetDrive(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 334         unsigned long count = 0;
 335         int flags;
 336 #ifdef DEBUG_DRIVE_IF
 337         printk("optcd: reset drive\n");
 338 #endif
 339         outb(0, RESET_PORT);
 340         while (++count < RESET_WAIT)
 341                 inb(DATA_PORT);
 342         count = 0;
 343         while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
 344                 if (++count >= BUSY_TIMEOUT)
 345                         break;
 346 #ifdef DEBUG_DRIVE_IF
 347         if (flags == FL_RESET)
 348                 printk("optcd: drive reset\n");
 349         else
 350                 printk("optcd: reset failed\n");
 351 #endif
 352         if (flags != FL_RESET)
 353                 return 0;               /* Reset failed */
 354         outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 355         return 1;                       /* Reset succeeded */
 356 }
 357 
 358 
 359 /* Command protocol */
 360 
 361 /* Send a simple command and wait for response */
 362 inline static int optCmd(int cmd) {
     /* [previous][next][first][last][top][bottom][index][help] */
 363         int ack = optSendCmd(cmd);
 364         if (ack < 0)
 365                 return ack;
 366         if (cmd < COMFETCH)             /* Quick response command */
 367                 return optGetExecStatus();
 368         else                            /* Slow command */
 369                 return optSleepTillExecStatus();
 370 }
 371 
 372 /* Send a command with parameters and wait for response */
 373 inline static int optPlayCmd(int cmd, struct opt_Play_msf *params) {
     /* [previous][next][first][last][top][bottom][index][help] */
 374         int ack = optSendCmd(cmd);
 375         if (ack < 0)
 376                 return ack;
 377         if ((ack = optSendParams(params)) < 0)
 378                 return ack;
 379         return optSleepTillExecStatus();
 380 }
 381 
 382 /* Send a command with parameters. Don't wait for the response,
 383  * which consists of the data blocks read. */
 384 inline static int optReadCmd(int cmd, struct opt_Play_msf *params) {
     /* [previous][next][first][last][top][bottom][index][help] */
 385         int ack = optSendCmd(cmd);
 386         if (ack < 0)
 387                 return ack;
 388         return optSendParams(params);
 389 }
 390 
 391 
 392 /* Address conversion routines */
 393 
 394 /* Binary to BCD (2 digits) */
 395 inline static unsigned char bin2bcd(unsigned char p) {
     /* [previous][next][first][last][top][bottom][index][help] */
 396 #ifdef DEBUG_CONV
 397         if (p > 99)
 398                 printk("optcd: error bin2bcd %d\n", p);
 399 #endif
 400         return (p % 10) | ((p / 10) << 4);
 401 }
 402 
 403 /* Linear address to minute, second, frame form */
 404 static void hsg2msf(long hsg, struct msf *msf) {
     /* [previous][next][first][last][top][bottom][index][help] */
 405         hsg += 150;
 406         msf -> min = hsg / 4500;
 407         hsg %= 4500;
 408         msf -> sec = hsg / 75;
 409         msf -> frame = hsg % 75;
 410 #ifdef DEBUG_CONV
 411         if (msf -> min >= 70)
 412                 printk("optcd: Error hsg2msf address Minutes\n");
 413         if (msf -> sec >= 60)
 414                 printk("optcd: Error hsg2msf address Seconds\n");
 415         if (msf -> frame >= 75)
 416                 printk("optcd: Error hsg2msf address Frames\n");
 417 #endif
 418         msf -> min = bin2bcd(msf -> min);       /* convert to BCD */
 419         msf -> sec = bin2bcd(msf -> sec);
 420         msf -> frame = bin2bcd(msf -> frame);
 421 }
 422 
 423 /* Two BCD digits to binary */
 424 inline static int bcd2bin(unsigned char bcd) {
     /* [previous][next][first][last][top][bottom][index][help] */
 425         return (bcd >> 4) * 10 + (bcd & 0x0f);
 426 }
 427 
 428 /* Minute, second, frame address to linear address */
 429 static long msf2hsg(struct msf *mp) {
     /* [previous][next][first][last][top][bottom][index][help] */
 430 #ifdef DEBUG_CONV
 431         if (mp -> min >= 70)
 432                 printk("optcd: Error msf2hsg address Minutes\n");
 433         if (mp -> sec >= 60)
 434                 printk("optcd: Error msf2hsg address Seconds\n");
 435         if (mp -> frame >= 75)
 436                 printk("optcd: Error msf2hsg address Frames\n");
 437 #endif
 438         return bcd2bin(mp -> frame)
 439                 + bcd2bin(mp -> sec) * 75
 440                 + bcd2bin(mp -> min) * 4500
 441                 - 150;
 442 }
 443 
 444 
 445 /* Drive status and table of contents */
 446 
 447 static int optAudioStatus = CDROM_AUDIO_NO_STATUS;
 448 static char optDiskChanged = 1;
 449 static char optTocUpToDate = 0;
 450 static struct opt_DiskInfo DiskInfo;
 451 static struct opt_Toc Toc[MAX_TRACKS];
 452 
 453 /* Get CDROM status, flagging completion of audio play and disk changes. */
 454 static int optGetStatus(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 455         int st;
 456         if ((st = optCmd(COMIOCTLISTAT)) < 0)
 457                 return st;
 458         if (st == 0xff)
 459                 return -ERR_IF_NOSTAT;
 460         if (((st & ST_MODE_BITS) != ST_M_AUDIO) &&
 461                 (optAudioStatus == CDROM_AUDIO_PLAY)) {
 462                 optAudioStatus = CDROM_AUDIO_COMPLETED;
 463         }
 464         if (st & ST_DSK_CHG) {
 465                 optDiskChanged = 1;
 466                 optTocUpToDate = 0;
 467                 optAudioStatus = CDROM_AUDIO_NO_STATUS;
 468         }
 469         return st;
 470 }
 471 
 472 /*
 473  * Read the current Q-channel info. Also used for reading the
 474  * table of contents.
 475  */
 476 static int optGetQChannelInfo(struct opt_Toc *qp) {
     /* [previous][next][first][last][top][bottom][index][help] */
 477         int st;
 478 #ifdef DEBUG_TOC
 479         printk("optcd: starting optGetQChannelInfo\n");
 480 #endif
 481         if ((st = optGetStatus()) < 0)
 482                 return st;
 483         if ((st = optCmd(COMSUBQ)) < 0)
 484                 return st;
 485         if ((qp -> ctrl_addr = st = optGetData()), st < 0) return st;
 486         if ((qp -> track = st = optGetData()), st < 0) return st;
 487         if ((qp -> pointIndex = st = optGetData()), st < 0) return st;
 488         if ((qp -> trackTime.min = st = optGetData()), st < 0) return st;
 489         if ((qp -> trackTime.sec = st = optGetData()), st < 0) return st;
 490         if ((qp -> trackTime.frame = st = optGetData()), st < 0) return st;
 491         if ((st = optGetData()) < 0) return st;         /* byte not used */
 492         if ((qp -> diskTime.min = st = optGetData()), st < 0) return st;
 493         if ((qp -> diskTime.sec = st = optGetData()), st < 0) return st;
 494         if ((qp -> diskTime.frame = st = optGetData()), st < 0) return st;
 495 #ifdef DEBUG_TOC
 496         printk("optcd: exiting optGetQChannelInfo\n");
 497 #endif
 498         return 0;
 499 }
 500 
 501 #define QINFO_FIRSTTRACK        0xa0
 502 #define QINFO_LASTTRACK         0xa1
 503 #define QINFO_DISKLENGTH        0xa2
 504 
 505 static int optGetDiskInfo(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 506         int st, limit;
 507         unsigned char test = 0;
 508         struct opt_Toc qInfo;
 509 #ifdef DEBUG_TOC
 510         printk("optcd: starting optGetDiskInfo\n");
 511 #endif
 512         optDiskChanged = 0;
 513         if ((st = optCmd(COMLEADIN)) < 0)
 514                 return st;
 515         for (limit = 300; (limit > 0) && (test != 0x0f); limit--) {
 516                 if ((st = optGetQChannelInfo(&qInfo)) < 0)
 517                         return st;
 518                 switch (qInfo.pointIndex) {
 519                 case QINFO_FIRSTTRACK:
 520                         DiskInfo.first = bcd2bin(qInfo.diskTime.min);
 521 #ifdef DEBUG_TOC
 522                         printk("optcd: got first: %d\n", DiskInfo.first);
 523 #endif
 524                         test |= 0x01;
 525                         break;
 526                 case QINFO_LASTTRACK:
 527                         DiskInfo.last = bcd2bin(qInfo.diskTime.min);
 528 #ifdef DEBUG_TOC
 529                         printk("optcd: got last: %d\n", DiskInfo.last);
 530 #endif
 531                         test |= 0x02;
 532                         break;
 533                 case QINFO_DISKLENGTH:
 534                         DiskInfo.diskLength.min = qInfo.diskTime.min;
 535                         DiskInfo.diskLength.sec = qInfo.diskTime.sec-2;
 536                         DiskInfo.diskLength.frame = qInfo.diskTime.frame;
 537 #ifdef DEBUG_TOC
 538                         printk("optcd: got length: %x:%x.%x\n",
 539                                 DiskInfo.diskLength.min,
 540                                 DiskInfo.diskLength.sec,
 541                                 DiskInfo.diskLength.frame);
 542 #endif
 543                         test |= 0x04;
 544                         break;
 545                 default:
 546                         if ((test & 0x01)       /* Got no of first track */
 547                          && (qInfo.pointIndex == DiskInfo.first)) {
 548                                 /* StartTime of First Track */
 549                                 DiskInfo.firstTrack.min = qInfo.diskTime.min;
 550                                 DiskInfo.firstTrack.sec = qInfo.diskTime.sec;
 551                                 DiskInfo.firstTrack.frame = qInfo.diskTime.frame;
 552 #ifdef DEBUG_TOC
 553                         printk("optcd: got start: %x:%x.%x\n",
 554                                 DiskInfo.firstTrack.min,
 555                                 DiskInfo.firstTrack.sec,
 556                                 DiskInfo.firstTrack.frame);
 557 #endif
 558                                 test |= 0x08;
 559                         }
 560                 }
 561         }
 562 #ifdef DEBUG_TOC
 563         printk("optcd: exiting optGetDiskInfo\n");
 564 #endif
 565         if (test != 0x0f)
 566                 return -ERR_TOC_MISSINGINFO;
 567         return 0;
 568 }
 569 
 570 static int optGetToc(void) {    /* Presumes we have got DiskInfo */
     /* [previous][next][first][last][top][bottom][index][help] */
 571         int st, count, px, limit;
 572         struct opt_Toc qInfo;
 573 #ifdef DEBUG_TOC
 574         int i;
 575         printk("optcd: starting optGetToc\n");
 576 #endif
 577         for (count = 0; count < MAX_TRACKS; count++)
 578                 Toc[count].pointIndex = 0;
 579         if ((st = optCmd(COMLEADIN)) < 0)
 580                 return st;
 581         st = 0;
 582         count = DiskInfo.last + 3;
 583         for (limit = 300; (limit > 0) && (count > 0); limit--) {
 584                 if ((st = optGetQChannelInfo(&qInfo)) < 0)
 585                         break;
 586                 px = bcd2bin(qInfo.pointIndex);
 587                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
 588                         if (Toc[px].pointIndex == 0) {
 589                                 Toc[px] = qInfo;
 590                                 count--;
 591                         }
 592         }
 593         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
 594 #ifdef DEBUG_TOC
 595         printk("optcd: exiting optGetToc\n");
 596         for (i = 1; i <= DiskInfo.last + 1; i++)
 597                 printk("i = %3d ctl-adr = %02x track %2d px "
 598                         "%02x %02x:%02x.%02x %02x:%02x.%02x\n",
 599                         i, Toc[i].ctrl_addr,
 600                         Toc[i].track,
 601                         Toc[i].pointIndex,
 602                         Toc[i].trackTime.min,
 603                         Toc[i].trackTime.sec,
 604                         Toc[i].trackTime.frame,
 605                         Toc[i].diskTime.min,
 606                         Toc[i].diskTime.sec,
 607                         Toc[i].diskTime.frame);
 608         for (i = 100; i < 103; i++)
 609                 printk("i = %3d ctl-adr = %02x track %2d px "
 610                         "%02x %02x:%02x.%02x %02x:%02x.%02x\n",
 611                         i, Toc[i].ctrl_addr,
 612                         Toc[i].track,
 613                         Toc[i].pointIndex,
 614                         Toc[i].trackTime.min,
 615                         Toc[i].trackTime.sec,
 616                         Toc[i].trackTime.frame,
 617                         Toc[i].diskTime.min,
 618                         Toc[i].diskTime.sec,
 619                         Toc[i].diskTime.frame);
 620 #endif
 621         return count ? -ERR_TOC_MISSINGENTRY : 0;
 622 }
 623 
 624 static int optUpdateToc(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 625 #ifdef DEBUG_TOC
 626         printk("optcd: starting optUpdateToc\n");
 627 #endif
 628         if (optTocUpToDate)
 629                 return 0;
 630         if (optGetDiskInfo() < 0)
 631                 return -EIO;
 632         if (optGetToc() < 0)
 633                 return -EIO;
 634         optTocUpToDate = 1;
 635 #ifdef DEBUG_TOC
 636         printk("optcd: exiting optUpdateToc\n");
 637 #endif
 638         return 0;
 639 }
 640 
 641 
 642 /* Buffers */
 643 
 644 #define OPT_BUF_SIZ             16
 645 #define OPT_BLOCKSIZE           2048
 646 #define OPT_BLOCKSIZE_RAW       2336
 647 #define OPT_BLOCKSIZE_ALL       2646
 648 #define OPT_NOBUF               -1
 649 
 650 /* Buffer for block size conversion. */
 651 static char opt_buf[OPT_BLOCKSIZE*OPT_BUF_SIZ];
 652 static volatile int opt_buf_bn[OPT_BUF_SIZ], opt_next_bn;
 653 static volatile int opt_buf_in = 0, opt_buf_out = OPT_NOBUF;
 654 
 655 inline static void opt_invalidate_buffers(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 656         int i;
 657 #ifdef DEBUG_BUFFERS
 658         printk("optcd: executing opt_invalidate_buffers\n");
 659 #endif
 660         for (i = 0; i < OPT_BUF_SIZ; i++)
 661                 opt_buf_bn[i] = OPT_NOBUF;
 662         opt_buf_out = OPT_NOBUF;
 663 }
 664 
 665 /*
 666  * Take care of the different block sizes between cdrom and Linux.
 667  * When Linux gets variable block sizes this will probably go away.
 668  */
 669 static void opt_transfer(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 670 #if (defined DEBUG_BUFFERS) || (defined DEBUG_REQUEST)
 671         printk("optcd: executing opt_transfer\n");
 672 #endif
 673         if (!CURRENT_VALID)
 674                 return;
 675         while (CURRENT -> nr_sectors) {
 676                 int bn = CURRENT -> sector / 4;
 677                 int i, offs, nr_sectors;
 678                 for (i = 0; i < OPT_BUF_SIZ && opt_buf_bn[i] != bn; ++i);
 679 #ifdef DEBUG_REQUEST
 680                 printk("optcd: found %d\n", i);
 681 #endif
 682                 if (i >= OPT_BUF_SIZ) {
 683                         opt_buf_out = OPT_NOBUF;
 684                         break;
 685                 }
 686                 offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
 687                 nr_sectors = 4 - (CURRENT -> sector & 3);
 688                 if (opt_buf_out != i) {
 689                         opt_buf_out = i;
 690                         if (opt_buf_bn[i] != bn) {
 691                                 opt_buf_out = OPT_NOBUF;
 692                                 continue;
 693                         }
 694                 }
 695                 if (nr_sectors > CURRENT -> nr_sectors)
 696                         nr_sectors = CURRENT -> nr_sectors;
 697                 memcpy(CURRENT -> buffer, opt_buf + offs, nr_sectors * 512);
 698                 CURRENT -> nr_sectors -= nr_sectors;
 699                 CURRENT -> sector += nr_sectors;
 700                 CURRENT -> buffer += nr_sectors * 512;
 701         }
 702 }
 703 
 704 
 705 /* State machine for reading disk blocks */
 706 
 707 enum opt_state_e {
 708         OPT_S_IDLE,     /* 0 */
 709         OPT_S_START,    /* 1 */
 710         OPT_S_READ,     /* 2 */
 711         OPT_S_DATA,     /* 3 */
 712         OPT_S_STOP,     /* 4 */
 713         OPT_S_STOPPING  /* 5 */
 714 };
 715 
 716 static volatile enum opt_state_e opt_state = OPT_S_IDLE;
 717 #ifdef DEBUG_STATE
 718 static volatile enum opt_state_e opt_state_old = OPT_S_STOP;
 719 static volatile int opt_st_old = 0;
 720 static volatile long opt_state_n = 0;
 721 #endif
 722 
 723 static volatile int opt_transfer_is_active = 0;
 724 static volatile int opt_error = 0;      /* do something with this?? */
 725 static int optTries;                    /* ibid?? */
 726 
 727 static void opt_poll(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 728         static int optTimeout;
 729         static volatile int opt_read_count = 1;
 730         int st = 0;
 731         int loop_ctl = 1;
 732         int skip = 0;
 733 
 734         if (opt_error) {
 735                 printk("optcd: I/O error 0x%02x\n", opt_error);
 736                 opt_invalidate_buffers();
 737 #ifdef WARN_IF_READ_FAILURE
 738                 if (optTries == 5)
 739                         printk("optcd: read block %d failed; audio disk?\n",
 740                                 opt_next_bn);
 741 #endif
 742                 if (!optTries--) {
 743                         printk("optcd: read block %d failed; Giving up\n",
 744                                opt_next_bn);
 745                         if (opt_transfer_is_active) {
 746                                 optTries = 0;
 747                                 loop_ctl = 0;
 748                         }
 749                         if (CURRENT_VALID)
 750                                 end_request(0);
 751                         optTries = 5;
 752                 }
 753                 opt_error = 0;
 754                 opt_state = OPT_S_STOP;
 755         }
 756 
 757         while (loop_ctl)
 758         {
 759                 loop_ctl = 0; /* each case must flip this back to 1 if we want
 760                                  to come back up here */
 761 #ifdef DEBUG_STATE
 762                 if (opt_state == opt_state_old)
 763                         opt_state_n++;
 764                 else {
 765                         opt_state_old = opt_state;
 766                         if (++opt_state_n > 1)
 767                                 printk("optcd: %ld times in previous state\n",
 768                                         opt_state_n);
 769                         printk("optcd: state %d\n", opt_state);
 770                         opt_state_n = 0;
 771                 }
 772 #endif
 773                 switch (opt_state) {
 774                 case OPT_S_IDLE:
 775                         return;
 776                 case OPT_S_START:
 777                         if (optSendCmd(COMDRVST))
 778                                 return;
 779                         opt_state = OPT_S_READ;
 780                         optTimeout = 3000;
 781                         break;
 782                 case OPT_S_READ: {
 783                         struct opt_Play_msf msf;
 784                         if (!skip) {
 785                                 if ((st = optStatus()) < 0)
 786                                         break;
 787                                 if (st & ST_DSK_CHG) {
 788                                         optDiskChanged = 1;
 789                                         optTocUpToDate = 0;
 790                                         opt_invalidate_buffers();
 791                                 }
 792                         }
 793                         skip = 0;
 794                         if ((st & ST_DOOR_OPEN) || (st & ST_DRVERR)) {
 795                                 optDiskChanged = 1;
 796                                 optTocUpToDate = 0;
 797                                 printk((st & ST_DOOR_OPEN)
 798                                        ? "optcd: door open\n"
 799                                        : "optcd: disk removed\n");
 800                                 if (opt_transfer_is_active) {
 801                                         opt_state = OPT_S_START;
 802                                         loop_ctl = 1;
 803                                         break;
 804                                 }
 805                                 opt_state = OPT_S_IDLE;
 806                                 while (CURRENT_VALID)
 807                                         end_request(0);
 808                                 return;
 809                         }
 810                         if (!CURRENT_VALID) {
 811                                 opt_state = OPT_S_STOP;
 812                                 loop_ctl = 1;
 813                                 break;
 814                         }
 815                         opt_next_bn = CURRENT -> sector / 4;
 816                         hsg2msf(opt_next_bn, &msf.start);
 817                         opt_read_count = OPT_BUF_SIZ;
 818                         msf.end.min = 0;
 819                         msf.end.sec = 0;
 820                         msf.end.frame = opt_read_count;
 821 #ifdef DEBUG_REQUEST
 822                         printk("optcd: reading %x:%x.%x %x:%x.%x\n",
 823                                 msf.start.min,
 824                                 msf.start.sec,
 825                                 msf.start.frame,
 826                                 msf.end.min,
 827                                 msf.end.sec,
 828                                 msf.end.frame);
 829                         printk("optcd: opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n",
 830                                 opt_next_bn,
 831                                 opt_buf_in,
 832                                 opt_buf_out,
 833                                 opt_buf_bn[opt_buf_in]);
 834 #endif
 835                         optReadCmd(COMREAD, &msf);
 836                         opt_state = OPT_S_DATA;
 837                         optTimeout = READ_TIMEOUT;
 838                         break;
 839                 }
 840                 case OPT_S_DATA:
 841                         st = optFlags() & (FL_STEN|FL_DTEN);
 842 #ifdef DEBUG_STATE
 843                         if (st != opt_st_old) {
 844                                 opt_st_old = st;
 845                                 printk("optcd: st:%x\n", st);
 846                         }
 847                         if (st == FL_STEN)
 848                                 printk("timeout cnt: %d\n", optTimeout);
 849 #endif
 850                         switch (st) {
 851                         case FL_DTEN:
 852 #ifdef WARN_IF_READ_FAILURE
 853                                 if (optTries == 5)
 854                                         printk("optcd: read block %d failed; audio disk?\n",
 855                                                opt_next_bn);
 856 #endif
 857                                 if (!optTries--) {
 858                                         printk("optcd: read block %d failed; Giving up\n",
 859                                                opt_next_bn);
 860                                         if (opt_transfer_is_active) {
 861                                                 optTries = 0;
 862                                                 break;
 863                                         }
 864                                         if (CURRENT_VALID)
 865                                                 end_request(0);
 866                                         optTries = 5;
 867                                 }
 868                                 opt_state = OPT_S_START;
 869                                 optTimeout = READ_TIMEOUT;
 870                                 loop_ctl = 1;
 871                         case (FL_STEN|FL_DTEN):
 872                                 break;
 873                         default:
 874                                 optTries = 5;
 875                                 if (!CURRENT_VALID && opt_buf_in == opt_buf_out) {
 876                                         opt_state = OPT_S_STOP;
 877                                         loop_ctl = 1;
 878                                         break;
 879                                 }
 880                                 if (opt_read_count<=0)
 881                                         printk("optcd: warning - try to read 0 frames\n");
 882                                 while (opt_read_count) {
 883                                         opt_buf_bn[opt_buf_in] = OPT_NOBUF;
 884                                         if (dten_low()) { /* should be no waiting here!?? */
 885                                                 printk("read_count:%d CURRENT->nr_sectors:%ld opt_buf_in:%d\n",
 886                                                         opt_read_count,
 887                                                         CURRENT->nr_sectors,
 888                                                         opt_buf_in);
 889                                                 printk("opt_transfer_is_active:%x\n",
 890                                                         opt_transfer_is_active);
 891                                                 opt_read_count = 0;
 892                                                 opt_state = OPT_S_STOP;
 893                                                 loop_ctl = 1;
 894                                                 end_request(0);
 895                                                 break;
 896                                         }
 897                                         optReadData(opt_buf+OPT_BLOCKSIZE*opt_buf_in, OPT_BLOCKSIZE);
 898                                         opt_read_count--;
 899 #ifdef DEBUG_REQUEST
 900                                         printk("OPT_S_DATA; ---I've read data- read_count: %d\n",
 901                                                opt_read_count);
 902                                         printk("opt_next_bn:%d  opt_buf_in:%d opt_buf_out:%d  opt_buf_bn:%d\n",
 903                                                opt_next_bn,
 904                                                opt_buf_in,
 905                                                opt_buf_out,
 906                                                opt_buf_bn[opt_buf_in]);
 907 #endif
 908                                         opt_buf_bn[opt_buf_in] = opt_next_bn++;
 909                                         if (opt_buf_out == OPT_NOBUF)
 910                                                 opt_buf_out = opt_buf_in;
 911                                         opt_buf_in = opt_buf_in + 1 ==
 912                                                 OPT_BUF_SIZ ? 0 : opt_buf_in + 1;
 913                                 }
 914                                 if (!opt_transfer_is_active) {
 915                                         while (CURRENT_VALID) {
 916                                                 opt_transfer();
 917                                                 if (CURRENT -> nr_sectors == 0)
 918                                                         end_request(1);
 919                                                 else
 920                                                         break;
 921                                         }
 922                                 }
 923 
 924                                 if (CURRENT_VALID
 925                                     && (CURRENT -> sector / 4 < opt_next_bn ||
 926                                     CURRENT -> sector / 4 >
 927                                      opt_next_bn + OPT_BUF_SIZ)) {
 928                                         opt_state = OPT_S_STOP;
 929                                         loop_ctl = 1;
 930                                         break;
 931                                 }
 932                                 optTimeout = READ_TIMEOUT;
 933                                 if (opt_read_count == 0) {
 934                                         opt_state = OPT_S_STOP;
 935                                         loop_ctl = 1;
 936                                         break;
 937                                 }
 938                         }
 939                         break;
 940                 case OPT_S_STOP:
 941                         if (opt_read_count != 0)
 942                                 printk("optcd: discard data=%x frames\n",
 943                                         opt_read_count);
 944                         while (opt_read_count != 0) {
 945                                 optFlushData();
 946                                 opt_read_count--;
 947                         }
 948                         if (optSendCmd(COMDRVST))
 949                                 return;
 950                         opt_state = OPT_S_STOPPING;
 951                         optTimeout = 1000;
 952                         break;
 953                 case OPT_S_STOPPING:
 954                         if ((st = optStatus()) < 0 && optTimeout)
 955                                         break;
 956                         if ((st != -1) && (st & ST_DSK_CHG)) {
 957                                 optDiskChanged = 1;
 958                                 optTocUpToDate = 0;
 959                                 opt_invalidate_buffers();
 960                         }
 961                         if (CURRENT_VALID) {
 962                                 if (st != -1) {
 963                                         opt_state = OPT_S_READ;
 964                                         loop_ctl = 1;
 965                                         skip = 1;
 966                                         break;
 967                                 } else {
 968                                         opt_state = OPT_S_START;
 969                                         optTimeout = 1;
 970                                 }
 971                         } else {
 972                                 opt_state = OPT_S_IDLE;
 973                                 return;
 974                         }
 975                         break;
 976                 default:
 977                         printk("optcd: invalid state %d\n", opt_state);
 978                         return;
 979                 } /* case */
 980         } /* while */
 981 
 982         if (!optTimeout--) {
 983                 printk("optcd: timeout in state %d\n", opt_state);
 984                 opt_state = OPT_S_STOP;
 985                 if (optCmd(COMSTOP) < 0)
 986                         return;
 987         }
 988 
 989         SET_TIMER(opt_poll, 1);
 990 }
 991 
 992 
 993 static void do_optcd_request(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
 994 #ifdef DEBUG_REQUEST
 995         printk("optcd: do_optcd_request(%ld+%ld)\n",
 996                CURRENT -> sector, CURRENT -> nr_sectors);
 997 #endif
 998         opt_transfer_is_active = 1;
 999         while (CURRENT_VALID) {
1000                 if (CURRENT->bh) {
1001                         if (!CURRENT->bh->b_lock)
1002                                 panic(DEVICE_NAME ": block not locked");
1003                 }
1004                 opt_transfer(); /* First try to transfer block from buffers */
1005                 if (CURRENT -> nr_sectors == 0) {
1006                         end_request(1);
1007                 } else {        /* Want to read a block not in buffer */
1008                         opt_buf_out = OPT_NOBUF;
1009                         if (opt_state == OPT_S_IDLE) {
1010                                 /* Should this block the request queue?? */
1011                                 if (optUpdateToc() < 0) {
1012                                         while (CURRENT_VALID)
1013                                                 end_request(0);
1014                                         break;
1015                                 }
1016                                 /* Start state machine */
1017                                 opt_state = OPT_S_START;
1018                                 optTries = 5;
1019                                 SET_TIMER(opt_poll, 1); /* why not start right away?? */
1020                         }
1021                         break;
1022                 }
1023         }
1024         opt_transfer_is_active = 0;
1025 #ifdef DEBUG_REQUEST
1026         printk("opt_next_bn:%d  opt_buf_in:%d opt_buf_out:%d  opt_buf_bn:%d\n",
1027                opt_next_bn, opt_buf_in, opt_buf_out, opt_buf_bn[opt_buf_in]);
1028         printk("optcd: do_optcd_request ends\n");
1029 #endif
1030 }
1031 
1032 
1033 /* VFS calls */
1034 
1035 static int opt_ioctl(struct inode *ip, struct file *fp,
     /* [previous][next][first][last][top][bottom][index][help] */
1036                         unsigned int cmd, unsigned long arg) {
1037         static struct opt_Play_msf opt_Play;    /* pause position */
1038         int err;
1039 #ifdef DEBUG_VFS
1040         printk("optcd: starting opt_ioctl, command 0x%x\n", cmd);
1041 #endif
1042         if (!ip)
1043                 return -EINVAL;
1044         if (optGetStatus() < 0)
1045                 return -EIO;
1046         if ((err = optUpdateToc()) < 0)
1047                 return err;
1048 
1049         switch (cmd) {
1050         case CDROMPAUSE: {
1051                 struct opt_Toc qInfo;
1052 
1053                 if (optAudioStatus != CDROM_AUDIO_PLAY)
1054                         return -EINVAL;
1055                 if (optGetQChannelInfo(&qInfo) < 0) {
1056                         /* didn't get q channel info */
1057                         optAudioStatus = CDROM_AUDIO_NO_STATUS;
1058                         return 0;
1059                 }
1060                 opt_Play.start = qInfo.diskTime;        /* restart point */
1061                 if (optCmd(COMPAUSEON) < 0)
1062                         return -EIO;
1063                 optAudioStatus = CDROM_AUDIO_PAUSED;
1064                 break;
1065         }
1066         case CDROMRESUME:
1067                 if (optAudioStatus != CDROM_AUDIO_PAUSED)
1068                         return -EINVAL;
1069                 if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
1070                         optAudioStatus = CDROM_AUDIO_ERROR;
1071                         return -EIO;
1072                 }
1073                 optAudioStatus = CDROM_AUDIO_PLAY;
1074                 break;
1075         case CDROMPLAYMSF: {
1076                 int st;
1077                 struct cdrom_msf msf;
1078 
1079                 if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
1080                         return st;
1081                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1082                 opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
1083                 opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
1084                 opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
1085                 opt_Play.end.min = bin2bcd(msf.cdmsf_min1);
1086                 opt_Play.end.sec = bin2bcd(msf.cdmsf_sec1);
1087                 opt_Play.end.frame = bin2bcd(msf.cdmsf_frame1);
1088                 if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
1089                         optAudioStatus = CDROM_AUDIO_ERROR;
1090                         return -EIO;
1091                 }
1092                 optAudioStatus = CDROM_AUDIO_PLAY;
1093                 break;
1094         }
1095         case CDROMPLAYTRKIND: {
1096                 int st;
1097                 struct cdrom_ti ti;
1098 
1099                 if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof ti)))
1100                         return st;
1101                 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
1102                 if (ti.cdti_trk0 < DiskInfo.first
1103                         || ti.cdti_trk0 > DiskInfo.last
1104                         || ti.cdti_trk1 < ti.cdti_trk0)
1105                         return -EINVAL;
1106                 if (ti.cdti_trk1 > DiskInfo.last)
1107                         ti.cdti_trk1 = DiskInfo.last;
1108                 opt_Play.start = Toc[ti.cdti_trk0].diskTime;
1109                 opt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
1110 #ifdef DEBUG_VFS
1111                 printk("optcd: play %02x:%02x.%02x to %02x:%02x.%02x\n",
1112                         opt_Play.start.min,
1113                         opt_Play.start.sec,
1114                         opt_Play.start.frame,
1115                         opt_Play.end.min,
1116                         opt_Play.end.sec,
1117                         opt_Play.end.frame);
1118 #endif
1119                 if (optPlayCmd(COMPLAY, &opt_Play) < 0) {
1120                         optAudioStatus = CDROM_AUDIO_ERROR;
1121                         return -EIO;
1122                 }
1123                 optAudioStatus = CDROM_AUDIO_PLAY;
1124                 break;
1125         }
1126         case CDROMREADTOCHDR: {         /* Read the table of contents header. */
1127                 int st;
1128                 struct cdrom_tochdr tocHdr;
1129 
1130                 if ((st = verify_area(VERIFY_WRITE,(void *)arg,sizeof tocHdr)))
1131                         return st;
1132                 if (!optTocUpToDate)
1133                         optGetDiskInfo();
1134                 tocHdr.cdth_trk0 = DiskInfo.first;
1135                 tocHdr.cdth_trk1 = DiskInfo.last;
1136                 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
1137                 break;
1138         }
1139         case CDROMREADTOCENTRY: {       /* Read a table of contents entry. */
1140                 int st;
1141                 struct cdrom_tocentry entry;
1142                 struct opt_Toc *tocPtr;
1143 
1144                 if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof entry)))
1145                         return st;
1146                 if ((st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry)))
1147                         return st;
1148                 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
1149                 if (!optTocUpToDate)
1150                         optGetDiskInfo();
1151                 if (entry.cdte_track == CDROM_LEADOUT)
1152                         tocPtr = &Toc[DiskInfo.last + 1];
1153                 else if (entry.cdte_track > DiskInfo.last
1154                         || entry.cdte_track < DiskInfo.first)
1155                         return -EINVAL;
1156                 else
1157                         tocPtr = &Toc[entry.cdte_track];
1158                 entry.cdte_adr = tocPtr -> ctrl_addr;
1159                 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
1160                 switch (entry.cdte_format) {
1161                 case CDROM_LBA:
1162                         entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
1163                         break;
1164                 case CDROM_MSF:
1165                         entry.cdte_addr.msf.minute =
1166                                 bcd2bin(tocPtr -> diskTime.min);
1167                         entry.cdte_addr.msf.second =
1168                                 bcd2bin(tocPtr -> diskTime.sec);
1169                         entry.cdte_addr.msf.frame =
1170                                 bcd2bin(tocPtr -> diskTime.frame);
1171                         break;
1172                 default:
1173                         return -EINVAL;
1174                 }
1175                 memcpy_tofs((void *) arg, &entry, sizeof entry);
1176                 break;
1177         }
1178         case CDROMSTOP:
1179                 optCmd(COMSTOP);
1180                 optAudioStatus = CDROM_AUDIO_NO_STATUS;
1181                 break;
1182         case CDROMSTART:
1183                 optCmd(COMCLOSE);       /* What else can we do? */
1184                 break;
1185         case CDROMEJECT:
1186                 optCmd(COMUNLOCK);
1187                 optCmd(COMOPEN);
1188                 break;
1189         case CDROMVOLCTRL: {
1190                 int st;
1191                 struct cdrom_volctrl volctrl;
1192 
1193                 if ((st = verify_area(VERIFY_READ, (void *) arg,
1194                                 sizeof(volctrl))))
1195                         return st;
1196                 memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
1197                 opt_Play.start.min = 0x10;
1198                 opt_Play.start.sec = 0x32;
1199                 opt_Play.start.frame = volctrl.channel0;
1200                 opt_Play.end.min = volctrl.channel1;
1201                 opt_Play.end.sec = volctrl.channel2;
1202                 opt_Play.end.frame = volctrl.channel3;
1203                 if (optPlayCmd(COMCHCTRL, &opt_Play) < 0)
1204                         return -EIO;
1205                 break;
1206         }
1207         case CDROMSUBCHNL: {    /* Get subchannel info */
1208                 int st;
1209                 struct cdrom_subchnl subchnl;
1210                 struct opt_Toc qInfo;
1211 
1212                 if ((st = verify_area(VERIFY_READ,
1213                                 (void *) arg, sizeof subchnl)))
1214                         return st;
1215                 if ((st = verify_area(VERIFY_WRITE,
1216                                 (void *) arg, sizeof subchnl)))
1217                         return st;
1218                 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
1219                 if (optGetQChannelInfo(&qInfo) < 0)
1220                         return -EIO;
1221                 subchnl.cdsc_audiostatus = optAudioStatus;
1222                 subchnl.cdsc_adr = qInfo.ctrl_addr;
1223                 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
1224                 subchnl.cdsc_trk = bcd2bin(qInfo.track);
1225                 subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
1226                 switch (subchnl.cdsc_format) {
1227                 case CDROM_LBA:
1228                         subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
1229                         subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
1230                         break;
1231                 case CDROM_MSF:
1232                         subchnl.cdsc_absaddr.msf.minute =
1233                                 bcd2bin(qInfo.diskTime.min);
1234                         subchnl.cdsc_absaddr.msf.second =
1235                                 bcd2bin(qInfo.diskTime.sec);
1236                         subchnl.cdsc_absaddr.msf.frame =
1237                                 bcd2bin(qInfo.diskTime.frame);
1238                         subchnl.cdsc_reladdr.msf.minute =
1239                                 bcd2bin(qInfo.trackTime.min);
1240                         subchnl.cdsc_reladdr.msf.second =
1241                                 bcd2bin(qInfo.trackTime.sec);
1242                         subchnl.cdsc_reladdr.msf.frame =
1243                                 bcd2bin(qInfo.trackTime.frame);
1244                         break;
1245                 default:
1246                         return -EINVAL;
1247                 }
1248                 memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
1249                 break;
1250         }
1251         case CDROMREADMODE1: {
1252                 int st;
1253                 struct cdrom_msf msf;
1254                 char buf[OPT_BLOCKSIZE];
1255 
1256                 if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf)))
1257                         return st;
1258                 if ((st = verify_area(VERIFY_WRITE,(void *)arg,OPT_BLOCKSIZE)))
1259                         return st;
1260                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
1261                 opt_Play.start.min = bin2bcd(msf.cdmsf_min0);
1262                 opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0);
1263                 opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0);
1264                 opt_Play.end.min = 0;
1265                 opt_Play.end.sec = 0;
1266                 opt_Play.end.frame = 1; /* read only one frame */
1267                 st = optReadCmd(COMREAD, &opt_Play);
1268 #ifdef DEBUG_VFS
1269                 printk("optcd: COMREAD status 0x%x\n", st);
1270 #endif
1271                 sleep_dten_low();       /* error checking here?? */
1272                 optReadData(buf, OPT_BLOCKSIZE);
1273                 memcpy_tofs((void *) arg, &buf, OPT_BLOCKSIZE);
1274                 break;
1275         }
1276         case CDROMMULTISESSION:
1277                 return -EINVAL; /* unluckily, not implemented yet */
1278 
1279         default:
1280                 return -EINVAL;
1281         }
1282 #ifdef DEBUG_VFS
1283         printk("optcd: exiting opt_ioctl\n");
1284 #endif
1285         return 0;
1286 }
1287 
1288 static int optPresent = 0;
1289 static int opt_open_count = 0;
1290 
1291 /* Open device special file; check that a disk is in. */
1292 static int opt_open(struct inode *ip, struct file *fp) {
     /* [previous][next][first][last][top][bottom][index][help] */
1293 #ifdef DEBUG_VFS
1294         printk("optcd: starting opt_open\n");
1295 #endif
1296         if (!optPresent)
1297                 return -ENXIO;          /* no hardware */
1298         if (!opt_open_count && opt_state == OPT_S_IDLE) {
1299                 int st;
1300                 opt_invalidate_buffers();
1301                 if ((st = optGetStatus()) < 0)
1302                         return -EIO;
1303                 if (st & ST_DOOR_OPEN) {
1304                         optCmd(COMCLOSE);                       /* close door */
1305                         if ((st = optGetStatus()) < 0)          /* try again */
1306                                 return -EIO;
1307                 }
1308                 if (st & (ST_DOOR_OPEN|ST_DRVERR)) {
1309                         printk("optcd: no disk or door open\n");
1310                         return -EIO;
1311                 }
1312                 if (optUpdateToc() < 0)
1313                         return -EIO;
1314         }
1315         opt_open_count++;
1316         MOD_INC_USE_COUNT;
1317         optCmd(COMLOCK);                /* Lock door */
1318 #ifdef DEBUG_VFS
1319         printk("optcd: exiting opt_open\n");
1320 #endif
1321         return 0;
1322 }
1323 
1324 /* Release device special file; flush all blocks from the buffer cache */
1325 static void opt_release(struct inode *ip, struct file *fp) {
     /* [previous][next][first][last][top][bottom][index][help] */
1326 #ifdef DEBUG_VFS
1327         printk("optcd: executing opt_release\n");
1328         printk("inode: %p, inode -> i_rdev: 0x%x, file: %p\n",
1329                 ip, ip -> i_rdev, fp);
1330 #endif
1331         if (!--opt_open_count) {
1332                 opt_invalidate_buffers();
1333                 sync_dev(ip -> i_rdev);
1334                 invalidate_buffers(ip -> i_rdev);
1335                 CLEAR_TIMER;
1336                 optCmd(COMUNLOCK);      /* Unlock door */
1337         }
1338         MOD_DEC_USE_COUNT;
1339 }
1340 
1341 
1342 /* Initialisation */
1343 
1344 static int version_ok(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
1345         char devname[100];
1346         int count, i, ch;
1347 
1348         if (optCmd(COMVERSION) < 0)
1349                 return 0;
1350         if ((count = optGetData()) < 0)
1351                 return 0;
1352         for (i = 0, ch = -1; count > 0; count--) {
1353                 if ((ch = optGetData()) < 0)
1354                         break;
1355                 if (i < 99)
1356                         devname[i++] = ch;
1357         }
1358         devname[i] = '\0';
1359         if (ch < 0)
1360                 return 0;
1361         printk("optcd: Device %s detected\n", devname);
1362         return ((devname[0] == 'D')
1363              && (devname[1] == 'O')
1364              && (devname[2] == 'L')
1365              && (devname[3] == 'P')
1366              && (devname[4] == 'H')
1367              && (devname[5] == 'I')
1368              && (devname[6] == 'N'));
1369 }
1370 
1371 
1372 static struct file_operations opt_fops = {
1373         NULL,           /* lseek - default */
1374         block_read,     /* read - general block-dev read */
1375         block_write,    /* write - general block-dev write */
1376         NULL,           /* readdir - bad */
1377         NULL,           /* select */
1378         opt_ioctl,      /* ioctl */
1379         NULL,           /* mmap */
1380         opt_open,       /* open */
1381         opt_release,    /* release */
1382         NULL,           /* fsync */
1383         NULL,           /* fasync */
1384         NULL,           /* media change */
1385         NULL            /* revalidate */
1386 };
1387 
1388 
1389 /* Get kernel parameter when used as a kernel driver */
1390 void optcd_setup(char *str, int *ints) {
     /* [previous][next][first][last][top][bottom][index][help] */
1391         if (ints[0] > 0)
1392                 optcd_port = ints[1];
1393 }
1394 
1395 /*
1396  * Test for presence of drive and initialize it. Called at boot time.
1397  */
1398 
1399 int optcd_init(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
1400         if (optcd_port <= 0) {
1401                 printk("optcd: no Optics Storage CDROM Initialization\n");
1402                 return -EIO;
1403         }
1404         if (check_region(optcd_port, 4)) {
1405                 printk("optcd: conflict, I/O port 0x%x already used\n",
1406                         optcd_port);
1407                 return -EIO;
1408         }
1409 
1410         if (!check_region(ISP16_DRIVE_SET_PORT, 5)) {
1411         /* If someone else has'nt already reserved these ports,
1412            probe for an ISP16 interface card, and enable SONY mode
1413            with no interrupts and no DMA. (As far as I know, all optics
1414            drives come with a SONY interface.) */
1415   if ( (isp16_type=isp16_detect()) < 0 )
1416     printk( "No ISP16 cdrom interface found.\n" );
1417   else {
1418     u_char expected_drive;
1419 
1420     printk( "ISP16 cdrom interface (%s optional IDE) detected.\n",
1421       (isp16_type==2)?"with":"without" );
1422 
1423     expected_drive = (isp16_type?ISP16_SANYO1:ISP16_SANYO0);
1424 
1425     if ( isp16_config( optcd_port, ISP16_SONY, 0, 0 ) < 0 ) {
1426       printk( "ISP16 cdrom interface has not been properly configured.\n" );
1427       return -EIO;
1428     }
1429   }
1430         }
1431 
1432         if (!optResetDrive()) {
1433                 printk("optcd: drive at 0x%x not ready\n", optcd_port);
1434                 return -EIO;
1435         }
1436         if (!version_ok()) {
1437                 printk("optcd: unknown drive detected; aborting\n");
1438                 return -EIO;
1439         }
1440         if (optCmd(COMINITDOUBLE) < 0) {
1441                 printk("optcd: cannot init double speed mode\n");
1442                 return -EIO;
1443         }
1444         if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0)
1445         {
1446                 printk("optcd: unable to get major %d\n", MAJOR_NR);
1447                 return -EIO;
1448         }
1449         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1450         read_ahead[MAJOR_NR] = 4;
1451         request_region(optcd_port, 4, "optcd");
1452         optPresent = 1;
1453         printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port);
1454         return 0;
1455 }
1456 
1457 #ifdef MODULE
1458 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1459 {
1460         return optcd_init();
1461 }
1462 
1463 void cleanup_module(void) {
     /* [previous][next][first][last][top][bottom][index][help] */
1464         if ((unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL)) {
1465                 printk("optcd: what's that: can't unregister\n");
1466                 return;
1467         }
1468         release_region(optcd_port, 4);
1469         printk("optcd: module released.\n");
1470 }
1471 #endif MODULE
1472 
1473 
1474 /*
1475  * -- ISP16 detection and configuration
1476  *
1477  *    Copyright (c) 1995, Eric van der Maarel <maarel@marin.nl>
1478  *
1479  *    Version 0.5
1480  *
1481  *    Detect cdrom interface on ISP16 soundcard.
1482  *    Configure cdrom interface.
1483  *
1484  *    Algorithm for the card with no IDE support option taken
1485  *    from the CDSETUP.SYS driver for MSDOS,
1486  *    by OPTi Computers, version 2.03.
1487  *    Algorithm for the IDE supporting ISP16 as communicated
1488  *    to me by Vadim Model and Leo Spiekman.
1489  *
1490  *    Use, modifification or redistribution of this software is
1491  *    allowed under the terms of the GPL.
1492  *
1493  */
1494 
1495 
1496 #define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p))
1497 #define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p))
1498 
1499 static short
1500 isp16_detect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1501 {
1502 
1503   if ( !( isp16_with_ide__detect() < 0 ) )
1504     return(2);
1505   else
1506     return( isp16_no_ide__detect() );
1507 }
1508 
1509 static short
1510 isp16_no_ide__detect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1511 {
1512   u_char ctrl;
1513   u_char enable_cdrom;
1514   u_char io;
1515   short i = -1;
1516 
1517   isp16_ctrl = ISP16_NO_IDE__CTRL;
1518   isp16_enable_cdrom_port = ISP16_NO_IDE__ENABLE_CDROM_PORT;
1519 
1520   /* read' and write' are a special read and write, respectively */
1521 
1522   /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */
1523   ctrl = ISP16_IN( ISP16_CTRL_PORT ) & 0xFC;
1524   ISP16_OUT( ISP16_CTRL_PORT, ctrl );
1525 
1526   /* read' 3,4 and 5-bit from the cdrom enable port */
1527   enable_cdrom = ISP16_IN( ISP16_NO_IDE__ENABLE_CDROM_PORT ) & 0x38;
1528 
1529   if ( !(enable_cdrom & 0x20) ) {  /* 5-bit not set */
1530     /* read' last 2 bits of ISP16_IO_SET_PORT */
1531     io = ISP16_IN( ISP16_IO_SET_PORT ) & 0x03;
1532     if ( ((io&0x01)<<1) == (io&0x02) ) {  /* bits are the same */
1533       if ( io == 0 ) {  /* ...the same and 0 */
1534         i = 0;
1535         enable_cdrom |= 0x20;
1536       }
1537       else {  /* ...the same and 1 */  /* my card, first time 'round */
1538         i = 1;
1539         enable_cdrom |= 0x28;
1540       }
1541       ISP16_OUT( ISP16_NO_IDE__ENABLE_CDROM_PORT, enable_cdrom );
1542     }
1543     else {  /* bits are not the same */
1544       ISP16_OUT( ISP16_CTRL_PORT, ctrl );
1545       return(i); /* -> not detected: possibly incorrect conclusion */
1546     }
1547   }
1548   else if ( enable_cdrom == 0x20 )
1549     i = 0;
1550   else if ( enable_cdrom == 0x28 )  /* my card, already initialised */
1551     i = 1;
1552 
1553   ISP16_OUT( ISP16_CTRL_PORT, ctrl );
1554 
1555   return(i);
1556 }
1557 
1558 static short
1559 isp16_with_ide__detect(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1560 {
1561   u_char ctrl;
1562   u_char tmp;
1563 
1564   isp16_ctrl = ISP16_IDE__CTRL;
1565   isp16_enable_cdrom_port = ISP16_IDE__ENABLE_CDROM_PORT;
1566 
1567   /* read' and write' are a special read and write, respectively */
1568 
1569   /* read' ISP16_CTRL_PORT and save */
1570   ctrl = ISP16_IN( ISP16_CTRL_PORT );
1571 
1572   /* write' zero to the ctrl port and get response */
1573   ISP16_OUT( ISP16_CTRL_PORT, 0 );
1574   tmp = ISP16_IN( ISP16_CTRL_PORT );
1575 
1576   if ( tmp != 2 )  /* isp16 with ide option not detected */
1577     return(-1);
1578 
1579   /* restore ctrl port value */
1580   ISP16_OUT( ISP16_CTRL_PORT, ctrl );
1581   
1582   return(2);
1583 }
1584 
1585 static short
1586 isp16_config( int base, u_char drive_type, int irq, int dma )
     /* [previous][next][first][last][top][bottom][index][help] */
1587 {
1588   u_char base_code;
1589   u_char irq_code;
1590   u_char dma_code;
1591   u_char i;
1592 
1593   if ( (drive_type == ISP16_MITSUMI) && (dma != 0) )
1594     printk( "Mitsumi cdrom drive has no dma support.\n" );
1595 
1596   switch (base) {
1597   case 0x340: base_code = ISP16_BASE_340; break;
1598   case 0x330: base_code = ISP16_BASE_330; break;
1599   case 0x360: base_code = ISP16_BASE_360; break;
1600   case 0x320: base_code = ISP16_BASE_320; break;
1601   default:
1602     printk( "Base address 0x%03X not supported by cdrom interface on ISP16.\n", base );
1603     return(-1);
1604   }
1605   switch (irq) {
1606   case 0: irq_code = ISP16_IRQ_X; break; /* disable irq */
1607   case 5: irq_code = ISP16_IRQ_5;
1608           printk( "Irq 5 shouldn't be used by cdrom interface on ISP16,"
1609             " due to possible conflicts with the soundcard.\n");
1610           break;
1611   case 7: irq_code = ISP16_IRQ_7;
1612           printk( "Irq 7 shouldn't be used by cdrom interface on ISP16,"
1613             " due to possible conflicts with the soundcard.\n");
1614           break;
1615   case 3: irq_code = ISP16_IRQ_3; break;
1616   case 9: irq_code = ISP16_IRQ_9; break;
1617   case 10: irq_code = ISP16_IRQ_10; break;
1618   case 11: irq_code = ISP16_IRQ_11; break;
1619   default:
1620     printk( "Irq %d not supported by cdrom interface on ISP16.\n", irq );
1621     return(-1);
1622   }
1623   switch (dma) {
1624   case 0: dma_code = ISP16_DMA_X; break;  /* disable dma */
1625   case 1: printk( "Dma 1 cannot be used by cdrom interface on ISP16,"
1626             " due to conflict with the soundcard.\n");
1627           return(-1); break;
1628   case 3: dma_code = ISP16_DMA_3; break;
1629   case 5: dma_code = ISP16_DMA_5; break;
1630   case 6: dma_code = ISP16_DMA_6; break;
1631   case 7: dma_code = ISP16_DMA_7; break;
1632   default:
1633     printk( "Dma %d not supported by cdrom interface on ISP16.\n", dma );
1634     return(-1);
1635   }
1636 
1637   if ( drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 &&
1638     drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 &&
1639     drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI &&
1640     drive_type != ISP16_DRIVE_X ) {
1641     printk( "Drive type (code 0x%02X) not supported by cdrom"
1642      " interface on ISP16.\n", drive_type );
1643     return(-1);
1644   }
1645 
1646   /* set type of interface */
1647   i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK;  /* clear some bits */
1648   ISP16_OUT( ISP16_DRIVE_SET_PORT, i|drive_type );
1649 
1650   /* enable cdrom on interface with ide support */
1651   if ( isp16_type > 1 )
1652     ISP16_OUT( isp16_enable_cdrom_port, ISP16_ENABLE_CDROM );
1653 
1654   /* set base address, irq and dma */
1655   i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK;  /* keep some bits */
1656   ISP16_OUT( ISP16_IO_SET_PORT, i|base_code|irq_code|dma_code );
1657 
1658   return(0);
1659 }

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