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

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