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