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

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