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

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