linux-bk/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
  75#include <asm/io.h>
  76#include <linux/blkdev.h>
  77
  78#include <linux/cdrom.h>
  79#include "optcd.h"
  80
  81#include <asm/uaccess.h>
  82
  83#define MAJOR_NR OPTICS_CDROM_MAJOR
  84#define QUEUE (opt_queue)
  85#define CURRENT elv_next_request(opt_queue)
  86
  87
  88/* Debug support */
  89
  90
  91/* Don't forget to add new debug flags here. */
  92#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \
  93    DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS
  94#define DEBUG(x) debug x
  95static void debug(int debug_this, const char* fmt, ...)
  96{
  97        char s[1024];
  98        va_list args;
  99
 100        if (!debug_this)
 101                return;
 102
 103        va_start(args, fmt);
 104        vsprintf(s, fmt, args);
 105        printk(KERN_DEBUG "optcd: %s\n", s);
 106        va_end(args);
 107}
 108#else
 109#define DEBUG(x)
 110#endif
 111
 112
 113/* Drive hardware/firmware characteristics
 114   Identifiers in accordance with Optics Storage documentation */
 115
 116
 117#define optcd_port optcd                        /* Needed for the modutils. */
 118static short optcd_port = OPTCD_PORTBASE;       /* I/O base of drive. */
 119MODULE_PARM(optcd_port, "h");
 120/* Drive registers, read */
 121#define DATA_PORT       optcd_port      /* Read data/status */
 122#define STATUS_PORT     optcd_port+1    /* Indicate data/status availability */
 123
 124/* Drive registers, write */
 125#define COMIN_PORT      optcd_port      /* For passing command/parameter */
 126#define RESET_PORT      optcd_port+1    /* Write anything and wait 0.5 sec */
 127#define HCON_PORT       optcd_port+2    /* Host Xfer Configuration */
 128
 129
 130/* Command completion/status read from DATA register */
 131#define ST_DRVERR               0x80
 132#define ST_DOOR_OPEN            0x40
 133#define ST_MIXEDMODE_DISK       0x20
 134#define ST_MODE_BITS            0x1c
 135#define ST_M_STOP               0x00
 136#define ST_M_READ               0x04
 137#define ST_M_AUDIO              0x04
 138#define ST_M_PAUSE              0x08
 139#define ST_M_INITIAL            0x0c
 140#define ST_M_ERROR              0x10
 141#define ST_M_OTHERS             0x14
 142#define ST_MODE2TRACK           0x02
 143#define ST_DSK_CHG              0x01
 144#define ST_L_LOCK               0x01
 145#define ST_CMD_OK               0x00
 146#define ST_OP_OK                0x01
 147#define ST_PA_OK                0x02
 148#define ST_OP_ERROR             0x05
 149#define ST_PA_ERROR             0x06
 150
 151
 152/* Error codes (appear as command completion code from DATA register) */
 153/* Player related errors */
 154#define ERR_ILLCMD      0x11    /* Illegal command to player module */
 155#define ERR_ILLPARM     0x12    /* Illegal parameter to player module */
 156#define ERR_SLEDGE      0x13
 157#define ERR_FOCUS       0x14
 158#define ERR_MOTOR       0x15
 159#define ERR_RADIAL      0x16
 160#define ERR_PLL         0x17    /* PLL lock error */
 161#define ERR_SUB_TIM     0x18    /* Subcode timeout error */
 162#define ERR_SUB_NF      0x19    /* Subcode not found error */
 163#define ERR_TRAY        0x1a
 164#define ERR_TOC         0x1b    /* Table of Contents read error */
 165#define ERR_JUMP        0x1c
 166/* Data errors */
 167#define ERR_MODE        0x21
 168#define ERR_FORM        0x22
 169#define ERR_HEADADDR    0x23    /* Header Address not found */
 170#define ERR_CRC         0x24
 171#define ERR_ECC         0x25    /* Uncorrectable ECC error */
 172#define ERR_CRC_UNC     0x26    /* CRC error and uncorrectable error */
 173#define ERR_ILLBSYNC    0x27    /* Illegal block sync error */
 174#define ERR_VDST        0x28    /* VDST not found */
 175/* Timeout errors */
 176#define ERR_READ_TIM    0x31    /* Read timeout error */
 177#define ERR_DEC_STP     0x32    /* Decoder stopped */
 178#define ERR_DEC_TIM     0x33    /* Decoder interrupt timeout error */
 179/* Function abort codes */
 180#define ERR_KEY         0x41    /* Key -Detected abort */
 181#define ERR_READ_FINISH 0x42    /* Read Finish */
 182/* Second Byte diagnostic codes */
 183#define ERR_NOBSYNC     0x01    /* No block sync */
 184#define ERR_SHORTB      0x02    /* Short block */
 185#define ERR_LONGB       0x03    /* Long block */
 186#define ERR_SHORTDSP    0x04    /* Short DSP word */
 187#define ERR_LONGDSP     0x05    /* Long DSP word */
 188
 189
 190/* Status availability flags read from STATUS register */
 191#define FL_EJECT        0x20
 192#define FL_WAIT         0x10    /* active low */
 193#define FL_EOP          0x08    /* active low */
 194#define FL_STEN         0x04    /* Status available when low */
 195#define FL_DTEN         0x02    /* Data available when low */
 196#define FL_DRQ          0x01    /* active low */
 197#define FL_RESET        0xde    /* These bits are high after a reset */
 198#define FL_STDT         (FL_STEN|FL_DTEN)
 199
 200
 201/* Transfer mode, written to HCON register */
 202#define HCON_DTS        0x08
 203#define HCON_SDRQB      0x04
 204#define HCON_LOHI       0x02
 205#define HCON_DMA16      0x01
 206
 207
 208/* Drive command set, written to COMIN register */
 209/* Quick response commands */
 210#define COMDRVST        0x20    /* Drive Status Read */
 211#define COMERRST        0x21    /* Error Status Read */
 212#define COMIOCTLISTAT   0x22    /* Status Read; reset disk changed bit */
 213#define COMINITSINGLE   0x28    /* Initialize Single Speed */
 214#define COMINITDOUBLE   0x29    /* Initialize Double Speed */
 215#define COMUNLOCK       0x30    /* Unlock */
 216#define COMLOCK         0x31    /* Lock */
 217#define COMLOCKST       0x32    /* Lock/Unlock Status */
 218#define COMVERSION      0x40    /* Get Firmware Revision */
 219#define COMVOIDREADMODE 0x50    /* Void Data Read Mode */
 220/* Read commands */
 221#define COMFETCH        0x60    /* Prefetch Data */
 222#define COMREAD         0x61    /* Read */
 223#define COMREADRAW      0x62    /* Read Raw Data */
 224#define COMREADALL      0x63    /* Read All 2646 Bytes */
 225/* Player control commands */
 226#define COMLEADIN       0x70    /* Seek To Lead-in */
 227#define COMSEEK         0x71    /* Seek */
 228#define COMPAUSEON      0x80    /* Pause On */
 229#define COMPAUSEOFF     0x81    /* Pause Off */
 230#define COMSTOP         0x82    /* Stop */
 231#define COMOPEN         0x90    /* Open Tray Door */
 232#define COMCLOSE        0x91    /* Close Tray Door */
 233#define COMPLAY         0xa0    /* Audio Play */
 234#define COMPLAY_TNO     0xa2    /* Audio Play By Track Number */
 235#define COMSUBQ         0xb0    /* Read Sub-q Code */
 236#define COMLOCATION     0xb1    /* Read Head Position */
 237/* Audio control commands */
 238#define COMCHCTRL       0xc0    /* Audio Channel Control */
 239/* Miscellaneous (test) commands */
 240#define COMDRVTEST      0xd0    /* Write Test Bytes */
 241#define COMTEST         0xd1    /* Diagnostic Test */
 242
 243/* Low level drive interface. Only here we do actual I/O
 244   Waiting for status / data available */
 245
 246
 247/* Busy wait until FLAG goes low. Return 0 on timeout. */
 248inline static int flag_low(int flag, unsigned long timeout)
 249{
 250        int flag_high;
 251        unsigned long count = 0;
 252
 253        while ((flag_high = (inb(STATUS_PORT) & flag)))
 254                if (++count >= timeout)
 255                        break;
 256
 257        DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s",
 258                flag, count, flag_high ? " timeout" : ""));
 259        return !flag_high;
 260}
 261
 262
 263/* Timed waiting for status or data */
 264static int sleep_timeout;       /* max # of ticks to sleep */
 265static DECLARE_WAIT_QUEUE_HEAD(waitq);
 266static void sleep_timer(unsigned long data);
 267static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0);
 268static spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED;
 269static struct request_queue *opt_queue;
 270
 271/* Timer routine: wake up when desired flag goes low,
 272   or when timeout expires. */
 273static void sleep_timer(unsigned long data)
 274{
 275        int flags = inb(STATUS_PORT) & FL_STDT;
 276
 277        if (flags == FL_STDT && --sleep_timeout > 0) {
 278                mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */
 279        } else
 280                wake_up(&waitq);
 281}
 282
 283
 284/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */
 285static int sleep_flag_low(int flag, unsigned long timeout)
 286{
 287        int flag_high;
 288
 289        DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low"));
 290
 291        sleep_timeout = timeout;
 292        flag_high = inb(STATUS_PORT) & flag;
 293        if (flag_high && sleep_timeout > 0) {
 294                mod_timer(&delay_timer, jiffies + HZ/100);
 295                sleep_on(&waitq);
 296                flag_high = inb(STATUS_PORT) & flag;
 297        }
 298
 299        DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s",
 300                flag, timeout, flag_high ? " timeout" : ""));
 301        return !flag_high;
 302}
 303
 304/* Low level drive interface. Only here we do actual I/O
 305   Sending commands and parameters */
 306
 307
 308/* Errors in the command protocol */
 309#define ERR_IF_CMD_TIMEOUT      0x100
 310#define ERR_IF_ERR_TIMEOUT      0x101
 311#define ERR_IF_RESP_TIMEOUT     0x102
 312#define ERR_IF_DATA_TIMEOUT     0x103
 313#define ERR_IF_NOSTAT           0x104
 314
 315
 316/* Send command code. Return <0 indicates error */
 317static int send_cmd(int cmd)
 318{
 319        unsigned char ack;
 320
 321        DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd));
 322
 323        outb(HCON_DTS, HCON_PORT);      /* Enable Suspend Data Transfer */
 324        outb(cmd, COMIN_PORT);          /* Send command code */
 325        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 326                return -ERR_IF_CMD_TIMEOUT;
 327        ack = inb(DATA_PORT);           /* read command acknowledge */
 328        outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 329        return ack==ST_OP_OK ? 0 : -ack;
 330}
 331
 332
 333/* Send command parameters. Return <0 indicates error */
 334static int send_params(struct cdrom_msf *params)
 335{
 336        unsigned char ack;
 337
 338        DEBUG((DEBUG_DRIVE_IF, "sending parameters"
 339                " %02x:%02x:%02x"
 340                " %02x:%02x:%02x",
 341                params->cdmsf_min0,
 342                params->cdmsf_sec0,
 343                params->cdmsf_frame0,
 344                params->cdmsf_min1,
 345                params->cdmsf_sec1,
 346                params->cdmsf_frame1));
 347
 348        outb(params->cdmsf_min0, COMIN_PORT);
 349        outb(params->cdmsf_sec0, COMIN_PORT);
 350        outb(params->cdmsf_frame0, COMIN_PORT);
 351        outb(params->cdmsf_min1, COMIN_PORT);
 352        outb(params->cdmsf_sec1, COMIN_PORT);
 353        outb(params->cdmsf_frame1, COMIN_PORT);
 354        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 355                return -ERR_IF_CMD_TIMEOUT;
 356        ack = inb(DATA_PORT);           /* read command acknowledge */
 357        return ack==ST_PA_OK ? 0 : -ack;
 358}
 359
 360
 361/* Send parameters for SEEK command. Return <0 indicates error */
 362static int send_seek_params(struct cdrom_msf *params)
 363{
 364        unsigned char ack;
 365
 366        DEBUG((DEBUG_DRIVE_IF, "sending seek parameters"
 367                " %02x:%02x:%02x",
 368                params->cdmsf_min0,
 369                params->cdmsf_sec0,
 370                params->cdmsf_frame0));
 371
 372        outb(params->cdmsf_min0, COMIN_PORT);
 373        outb(params->cdmsf_sec0, COMIN_PORT);
 374        outb(params->cdmsf_frame0, COMIN_PORT);
 375        if (!flag_low(FL_STEN, BUSY_TIMEOUT))   /* Wait for status */
 376                return -ERR_IF_CMD_TIMEOUT;
 377        ack = inb(DATA_PORT);           /* read command acknowledge */
 378        return ack==ST_PA_OK ? 0 : -ack;
 379}
 380
 381
 382/* Wait for command execution status. Choice between busy waiting
 383   and sleeping. Return value <0 indicates timeout. */
 384inline static int get_exec_status(int busy_waiting)
 385{
 386        unsigned char exec_status;
 387
 388        if (busy_waiting
 389            ? !flag_low(FL_STEN, BUSY_TIMEOUT)
 390            : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT))
 391                return -ERR_IF_CMD_TIMEOUT;
 392
 393        exec_status = inb(DATA_PORT);
 394        DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status));
 395        return exec_status;
 396}
 397
 398
 399/* Wait busy for extra byte of data that a command returns.
 400   Return value <0 indicates timeout. */
 401inline static int get_data(int short_timeout)
 402{
 403        unsigned char data;
 404
 405        if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT))
 406                return -ERR_IF_DATA_TIMEOUT;
 407
 408        data = inb(DATA_PORT);
 409        DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data));
 410        return data;
 411}
 412
 413
 414/* Returns 0 if failed */
 415static int reset_drive(void)
 416{
 417        unsigned long count = 0;
 418        int flags;
 419
 420        DEBUG((DEBUG_DRIVE_IF, "reset drive"));
 421
 422        outb(0, RESET_PORT);
 423        while (++count < RESET_WAIT)
 424                inb(DATA_PORT);
 425
 426        count = 0;
 427        while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET)
 428                if (++count >= BUSY_TIMEOUT)
 429                        break;
 430
 431        DEBUG((DEBUG_DRIVE_IF, "reset %s",
 432                flags == FL_RESET ? "succeeded" : "failed"));
 433
 434        if (flags != FL_RESET)
 435                return 0;               /* Reset failed */
 436        outb(HCON_SDRQB, HCON_PORT);    /* Disable Suspend Data Transfer */
 437        return 1;                       /* Reset succeeded */
 438}
 439
 440
 441/* Facilities for asynchronous operation */
 442
 443/* Read status/data availability flags FL_STEN and FL_DTEN */
 444inline static int stdt_flags(void)
 445{
 446        return inb(STATUS_PORT) & FL_STDT;
 447}
 448
 449
 450/* Fetch status that has previously been waited for. <0 means not available */
 451inline static int fetch_status(void)
 452{
 453        unsigned char status;
 454
 455        if (inb(STATUS_PORT) & FL_STEN)
 456                return -ERR_IF_NOSTAT;
 457
 458        status = inb(DATA_PORT);
 459        DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status));
 460        return status;
 461}
 462
 463
 464/* Fetch data that has previously been waited for. */
 465inline static void fetch_data(char *buf, int n)
 466{
 467        insb(DATA_PORT, buf, n);
 468        DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n));
 469}
 470
 471
 472/* Flush status and data fifos */
 473inline static void flush_data(void)
 474{
 475        while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT)
 476                inb(DATA_PORT);
 477        DEBUG((DEBUG_DRIVE_IF, "flushed fifos"));
 478}
 479
 480/* Command protocol */
 481
 482
 483/* Send a simple command and wait for response. Command codes < COMFETCH
 484   are quick response commands */
 485inline static int exec_cmd(int cmd)
 486{
 487        int ack = send_cmd(cmd);
 488        if (ack < 0)
 489                return ack;
 490        return get_exec_status(cmd < COMFETCH);
 491}
 492
 493
 494/* Send a command with parameters. Don't wait for the response,
 495 * which consists of data blocks read from the CD. */
 496inline static int exec_read_cmd(int cmd, struct cdrom_msf *params)
 497{
 498        int ack = send_cmd(cmd);
 499        if (ack < 0)
 500                return ack;
 501        return send_params(params);
 502}
 503
 504
 505/* Send a seek command with parameters and wait for response */
 506inline static int exec_seek_cmd(int cmd, struct cdrom_msf *params)
 507{
 508        int ack = send_cmd(cmd);
 509        if (ack < 0)
 510                return ack;
 511        ack = send_seek_params(params);
 512        if (ack < 0)
 513                return ack;
 514        return 0;
 515}
 516
 517
 518/* Send a command with parameters and wait for response */
 519inline static int exec_long_cmd(int cmd, struct cdrom_msf *params)
 520{
 521        int ack = exec_read_cmd(cmd, params);
 522        if (ack < 0)
 523                return ack;
 524        return get_exec_status(0);
 525}
 526
 527/* Address conversion routines */
 528
 529
 530/* Binary to BCD (2 digits) */
 531inline static void single_bin2bcd(u_char *p)
 532{
 533        DEBUG((DEBUG_CONV, "bin2bcd %02d", *p));
 534        *p = (*p % 10) | ((*p / 10) << 4);
 535}
 536
 537
 538/* Convert entire msf struct */
 539static void bin2bcd(struct cdrom_msf *msf)
 540{
 541        single_bin2bcd(&msf->cdmsf_min0);
 542        single_bin2bcd(&msf->cdmsf_sec0);
 543        single_bin2bcd(&msf->cdmsf_frame0);
 544        single_bin2bcd(&msf->cdmsf_min1);
 545        single_bin2bcd(&msf->cdmsf_sec1);
 546        single_bin2bcd(&msf->cdmsf_frame1);
 547}
 548
 549
 550/* Linear block address to minute, second, frame form */
 551#define CD_FPM  (CD_SECS * CD_FRAMES)   /* frames per minute */
 552
 553static void lba2msf(int lba, struct cdrom_msf *msf)
 554{
 555        DEBUG((DEBUG_CONV, "lba2msf %d", lba));
 556        lba += CD_MSF_OFFSET;
 557        msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM;
 558        msf->cdmsf_sec0 = lba / CD_FRAMES;
 559        msf->cdmsf_frame0 = lba % CD_FRAMES;
 560        msf->cdmsf_min1 = 0;
 561        msf->cdmsf_sec1 = 0;
 562        msf->cdmsf_frame1 = 0;
 563        bin2bcd(msf);
 564}
 565
 566
 567/* Two BCD digits to binary */
 568inline static u_char bcd2bin(u_char bcd)
 569{
 570        DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd));
 571        return (bcd >> 4) * 10 + (bcd & 0x0f);
 572}
 573
 574
 575static void msf2lba(union cdrom_addr *addr)
 576{
 577        addr->lba = addr->msf.minute * CD_FPM
 578                    + addr->msf.second * CD_FRAMES
 579                    + addr->msf.frame - CD_MSF_OFFSET;
 580}
 581
 582
 583/* Minute, second, frame address BCD to binary or to linear address,
 584   depending on MODE */
 585static void msf_bcd2bin(union cdrom_addr *addr)
 586{
 587        addr->msf.minute = bcd2bin(addr->msf.minute);
 588        addr->msf.second = bcd2bin(addr->msf.second);
 589        addr->msf.frame = bcd2bin(addr->msf.frame);
 590}
 591
 592/* High level drive commands */
 593
 594
 595static int audio_status = CDROM_AUDIO_NO_STATUS;
 596static char toc_uptodate = 0;
 597static char disk_changed = 1;
 598
 599/* Get drive status, flagging completion of audio play and disk changes. */
 600static int drive_status(void)
 601{
 602        int status;
 603
 604        status = exec_cmd(COMIOCTLISTAT);
 605        DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status));
 606        if (status < 0)
 607                return status;
 608        if (status == 0xff)     /* No status available */
 609                return -ERR_IF_NOSTAT;
 610
 611        if (((status & ST_MODE_BITS) != ST_M_AUDIO) &&
 612                (audio_status == CDROM_AUDIO_PLAY)) {
 613                audio_status = CDROM_AUDIO_COMPLETED;
 614        }
 615
 616        if (status & ST_DSK_CHG) {
 617                toc_uptodate = 0;
 618                disk_changed = 1;
 619                audio_status = CDROM_AUDIO_NO_STATUS;
 620        }
 621
 622        return status;
 623}
 624
 625
 626/* Read the current Q-channel info. Also used for reading the
 627   table of contents. qp->cdsc_format must be set on entry to
 628   indicate the desired address format */
 629static int get_q_channel(struct cdrom_subchnl *qp)
 630{
 631        int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10;
 632
 633        status = drive_status();
 634        if (status < 0)
 635                return status;
 636        qp->cdsc_audiostatus = audio_status;
 637
 638        status = exec_cmd(COMSUBQ);
 639        if (status < 0)
 640                return status;
 641
 642        d1 = get_data(0);
 643        if (d1 < 0)
 644                return d1;
 645        qp->cdsc_adr = d1;
 646        qp->cdsc_ctrl = d1 >> 4;
 647
 648        d2 = get_data(0);
 649        if (d2 < 0)
 650                return d2;
 651        qp->cdsc_trk = bcd2bin(d2);
 652
 653        d3 = get_data(0);
 654        if (d3 < 0)
 655                return d3;
 656        qp->cdsc_ind = bcd2bin(d3);
 657
 658        d4 = get_data(0);
 659        if (d4 < 0)
 660                return d4;
 661        qp->cdsc_reladdr.msf.minute = d4;
 662
 663        d5 = get_data(0);
 664        if (d5 < 0)
 665                return d5;
 666        qp->cdsc_reladdr.msf.second = d5;
 667
 668        d6 = get_data(0);
 669        if (d6 < 0)
 670                return d6;
 671        qp->cdsc_reladdr.msf.frame = d6;
 672
 673        d7 = get_data(0);
 674        if (d7 < 0)
 675                return d7;
 676        /* byte not used */
 677
 678        d8 = get_data(0);
 679        if (d8 < 0)
 680                return d8;
 681        qp->cdsc_absaddr.msf.minute = d8;
 682
 683        d9 = get_data(0);
 684        if (d9 < 0)
 685                return d9;
 686        qp->cdsc_absaddr.msf.second = d9;
 687
 688        d10 = get_data(0);
 689        if (d10 < 0)
 690                return d10;
 691        qp->cdsc_absaddr.msf.frame = d10;
 692
 693        DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
 694                d1, d2, d3, d4, d5, d6, d7, d8, d9, d10));
 695
 696        msf_bcd2bin(&qp->cdsc_absaddr);
 697        msf_bcd2bin(&qp->cdsc_reladdr);
 698        if (qp->cdsc_format == CDROM_LBA) {
 699                msf2lba(&qp->cdsc_absaddr);
 700                msf2lba(&qp->cdsc_reladdr);
 701        }
 702
 703        return 0;
 704}
 705
 706/* Table of contents handling */
 707
 708
 709/* Errors in table of contents */
 710#define ERR_TOC_MISSINGINFO     0x120
 711#define ERR_TOC_MISSINGENTRY    0x121
 712
 713
 714struct cdrom_disk_info {
 715        unsigned char           first;
 716        unsigned char           last;
 717        struct cdrom_msf0       disk_length;
 718        struct cdrom_msf0       first_track;
 719        /* Multisession info: */
 720        unsigned char           next;
 721        struct cdrom_msf0       next_session;
 722        struct cdrom_msf0       last_session;
 723        unsigned char           multi;
 724        unsigned char           xa;
 725        unsigned char           audio;
 726};
 727static struct cdrom_disk_info disk_info;
 728
 729#define MAX_TRACKS              111
 730static struct cdrom_subchnl toc[MAX_TRACKS];
 731
 732#define QINFO_FIRSTTRACK        100 /* bcd2bin(0xa0) */
 733#define QINFO_LASTTRACK         101 /* bcd2bin(0xa1) */
 734#define QINFO_DISKLENGTH        102 /* bcd2bin(0xa2) */
 735#define QINFO_NEXTSESSION       110 /* bcd2bin(0xb0) */
 736
 737#define I_FIRSTTRACK    0x01
 738#define I_LASTTRACK     0x02
 739#define I_DISKLENGTH    0x04
 740#define I_NEXTSESSION   0x08
 741#define I_ALL   (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH)
 742
 743
 744#if DEBUG_TOC
 745static void toc_debug_info(int i)
 746{
 747        printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d"
 748                "  %2d:%02d.%02d %2d:%02d.%02d\n",
 749                i, toc[i].cdsc_ctrl, toc[i].cdsc_adr,
 750                toc[i].cdsc_trk, toc[i].cdsc_ind,
 751                toc[i].cdsc_reladdr.msf.minute,
 752                toc[i].cdsc_reladdr.msf.second,
 753                toc[i].cdsc_reladdr.msf.frame,
 754                toc[i].cdsc_absaddr.msf.minute,
 755                toc[i].cdsc_absaddr.msf.second,
 756                toc[i].cdsc_absaddr.msf.frame);
 757}
 758#endif
 759
 760
 761static int read_toc(void)
 762{
 763        int status, limit, count;
 764        unsigned char got_info = 0;
 765        struct cdrom_subchnl q_info;
 766#if DEBUG_TOC
 767        int i;
 768#endif
 769
 770        DEBUG((DEBUG_TOC, "starting read_toc"));
 771
 772        count = 0;
 773        for (limit = 60; limit > 0; limit--) {
 774                int index;
 775
 776                q_info.cdsc_format = CDROM_MSF;
 777                status = get_q_channel(&q_info);
 778                if (status < 0)
 779                        return status;
 780
 781                index = q_info.cdsc_ind;
 782                if (index > 0 && index < MAX_TRACKS
 783                    && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) {
 784                        toc[index] = q_info;
 785                        DEBUG((DEBUG_TOC, "got %d", index));
 786                        if (index < 100)
 787                                count++;
 788
 789                        switch (q_info.cdsc_ind) {
 790                        case QINFO_FIRSTTRACK:
 791                                got_info |= I_FIRSTTRACK;
 792                                break;
 793                        case QINFO_LASTTRACK:
 794                                got_info |= I_LASTTRACK;
 795                                break;
 796                        case QINFO_DISKLENGTH:
 797                                got_info |= I_DISKLENGTH;
 798                                break;
 799                        case QINFO_NEXTSESSION:
 800                                got_info |= I_NEXTSESSION;
 801                                break;
 802                        }
 803                }
 804
 805                if ((got_info & I_ALL) == I_ALL
 806                    && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 807                       >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 808                        break;
 809        }
 810
 811        /* Construct disk_info from TOC */
 812        if (disk_info.first == 0) {
 813                disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 814                disk_info.first_track.minute =
 815                        toc[disk_info.first].cdsc_absaddr.msf.minute;
 816                disk_info.first_track.second =
 817                        toc[disk_info.first].cdsc_absaddr.msf.second;
 818                disk_info.first_track.frame =
 819                        toc[disk_info.first].cdsc_absaddr.msf.frame;
 820        }
 821        disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute;
 822        disk_info.disk_length.minute =
 823                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute;
 824        disk_info.disk_length.second =
 825                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2;
 826        disk_info.disk_length.frame =
 827                        toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame;
 828        disk_info.next_session.minute =
 829                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute;
 830        disk_info.next_session.second =
 831                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second;
 832        disk_info.next_session.frame =
 833                        toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame;
 834        disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute;
 835        disk_info.last_session.minute =
 836                        toc[disk_info.next].cdsc_absaddr.msf.minute;
 837        disk_info.last_session.second =
 838                        toc[disk_info.next].cdsc_absaddr.msf.second;
 839        disk_info.last_session.frame =
 840                        toc[disk_info.next].cdsc_absaddr.msf.frame;
 841        toc[disk_info.last + 1].cdsc_absaddr.msf.minute =
 842                        disk_info.disk_length.minute;
 843        toc[disk_info.last + 1].cdsc_absaddr.msf.second =
 844                        disk_info.disk_length.second;
 845        toc[disk_info.last + 1].cdsc_absaddr.msf.frame =
 846                        disk_info.disk_length.frame;
 847#if DEBUG_TOC
 848        for (i = 1; i <= disk_info.last + 1; i++)
 849                toc_debug_info(i);
 850        toc_debug_info(QINFO_FIRSTTRACK);
 851        toc_debug_info(QINFO_LASTTRACK);
 852        toc_debug_info(QINFO_DISKLENGTH);
 853        toc_debug_info(QINFO_NEXTSESSION);
 854#endif
 855
 856        DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d",
 857                got_info, count));
 858        if ((got_info & I_ALL) != I_ALL
 859            || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count
 860               < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1)
 861                return -ERR_TOC_MISSINGINFO;
 862        return 0;
 863}
 864
 865
 866#ifdef MULTISESSION
 867static int get_multi_disk_info(void)
 868{
 869        int sessions, status;
 870        struct cdrom_msf multi_index;
 871
 872
 873        for (sessions = 2; sessions < 10 /* %%for now */; sessions++) {
 874                int count;
 875
 876                for (count = 100; count < MAX_TRACKS; count++) 
 877                        toc[count].cdsc_ind = 0;
 878
 879                multi_index.cdmsf_min0 = disk_info.next_session.minute;
 880                multi_index.cdmsf_sec0 = disk_info.next_session.second;
 881                multi_index.cdmsf_frame0 = disk_info.next_session.frame;
 882                if (multi_index.cdmsf_sec0 >= 20)
 883                        multi_index.cdmsf_sec0 -= 20;
 884                else {
 885                        multi_index.cdmsf_sec0 += 40;
 886                        multi_index.cdmsf_min0--;
 887                }
 888                DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions,
 889                        multi_index.cdmsf_min0,
 890                        multi_index.cdmsf_sec0,
 891                        multi_index.cdmsf_frame0));
 892                bin2bcd(&multi_index);
 893                multi_index.cdmsf_min1 = 0;
 894                multi_index.cdmsf_sec1 = 0;
 895                multi_index.cdmsf_frame1 = 1;
 896
 897                status = exec_read_cmd(COMREAD, &multi_index);
 898                if (status < 0) {
 899                        DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x",
 900                                -status));
 901                        break;
 902                }
 903                status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ?
 904                                0 : -ERR_TOC_MISSINGINFO;
 905                flush_data();
 906                if (status < 0) {
 907                        DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status));
 908                        break;
 909                }
 910
 911                status = read_toc();
 912                if (status < 0) {
 913                        DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 914                        break;
 915                }
 916
 917                disk_info.multi = 1;
 918        }
 919
 920        exec_cmd(COMSTOP);
 921
 922        if (status < 0)
 923                return -EIO;
 924        return 0;
 925}
 926#endif /* MULTISESSION */
 927
 928
 929static int update_toc(void)
 930{
 931        int status, count;
 932
 933        if (toc_uptodate)
 934                return 0;
 935
 936        DEBUG((DEBUG_TOC, "starting update_toc"));
 937
 938        disk_info.first = 0;
 939        for (count = 0; count < MAX_TRACKS; count++) 
 940                toc[count].cdsc_ind = 0;
 941
 942        status = exec_cmd(COMLEADIN);
 943        if (status < 0)
 944                return -EIO;
 945
 946        status = read_toc();
 947        if (status < 0) {
 948                DEBUG((DEBUG_TOC, "read_toc: %02x", -status));
 949                return -EIO;
 950        }
 951
 952        /* Audio disk detection. Look at first track. */
 953        disk_info.audio =
 954                (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1;
 955
 956        /* XA detection */
 957        disk_info.xa = drive_status() & ST_MODE2TRACK;
 958
 959        /* Multisession detection: if we want this, define MULTISESSION */
 960        disk_info.multi = 0;
 961#ifdef MULTISESSION
 962        if (disk_info.xa)
 963                get_multi_disk_info();  /* Here disk_info.multi is set */
 964#endif /* MULTISESSION */
 965        if (disk_info.multi)
 966                printk(KERN_WARNING "optcd: Multisession support experimental, "
 967                        "see Documentation/cdrom/optcd\n");
 968
 969        DEBUG((DEBUG_TOC, "exiting update_toc"));
 970
 971        toc_uptodate = 1;
 972        return 0;
 973}
 974
 975/* Request handling */
 976
 977static int current_valid(void)
 978{
 979        return CURRENT &&
 980                CURRENT->cmd == READ &&
 981                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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 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(CURRENT, 0);
1369                return;
1370        }
1371
1372        transfer_is_active = 1;
1373        while (current_valid()) {
1374                transfer();     /* First try to transfer block from buffers */
1375                if (CURRENT -> nr_sectors == 0) {
1376                        end_request(CURRENT, 1);
1377                } else {        /* Want to read a block not in buffer */
1378                        buf_out = NOBUF;
1379                        if (state == S_IDLE) {
1380                                /* %% Should this block the request queue?? */
1381                                if (update_toc() < 0) {
1382                                        while (current_valid())
1383                                                end_request(CURRENT, 0);
1384                                        break;
1385                                }
1386                                /* Start state machine */
1387                                state = S_START;
1388                                timeout = READ_TIMEOUT;
1389                                tries = 5;
1390                                /* %% why not start right away?? */
1391                                mod_timer(&req_timer, jiffies + HZ/100);
1392                        }
1393                        break;
1394                }
1395        }
1396        transfer_is_active = 0;
1397
1398        DEBUG((DEBUG_REQUEST, "next_bn:%d  buf_in:%d buf_out:%d  buf_bn:%d",
1399               next_bn, buf_in, buf_out, buf_bn[buf_in]));
1400        DEBUG((DEBUG_REQUEST, "do_optcd_request ends"));
1401}
1402
1403/* IOCTLs */
1404
1405
1406static char auto_eject = 0;
1407
1408static int cdrompause(void)
1409{
1410        int status;
1411
1412        if (audio_status != CDROM_AUDIO_PLAY)
1413                return -EINVAL;
1414
1415        status = exec_cmd(COMPAUSEON);
1416        if (status < 0) {
1417                DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status));
1418                return -EIO;
1419        }
1420        audio_status = CDROM_AUDIO_PAUSED;
1421        return 0;
1422}
1423
1424
1425static int cdromresume(void)
1426{
1427        int status;
1428
1429        if (audio_status != CDROM_AUDIO_PAUSED)
1430                return -EINVAL;
1431
1432        status = exec_cmd(COMPAUSEOFF);
1433        if (status < 0) {
1434                DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status));
1435                audio_status = CDROM_AUDIO_ERROR;
1436                return -EIO;
1437        }
1438        audio_status = CDROM_AUDIO_PLAY;
1439        return 0;
1440}
1441
1442
1443static int cdromplaymsf(void __user *arg)
1444{
1445        int status;
1446        struct cdrom_msf msf;
1447
1448        if (copy_from_user(&msf, arg, sizeof msf))
1449                return -EFAULT;
1450
1451        bin2bcd(&msf);
1452        status = exec_long_cmd(COMPLAY, &msf);
1453        if (status < 0) {
1454                DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1455                audio_status = CDROM_AUDIO_ERROR;
1456                return -EIO;
1457        }
1458
1459        audio_status = CDROM_AUDIO_PLAY;
1460        return 0;
1461}
1462
1463
1464static int cdromplaytrkind(void __user *arg)
1465{
1466        int status;
1467        struct cdrom_ti ti;
1468        struct cdrom_msf msf;
1469
1470        if (copy_from_user(&ti, arg, sizeof ti))
1471                return -EFAULT;
1472
1473        if (ti.cdti_trk0 < disk_info.first
1474            || ti.cdti_trk0 > disk_info.last
1475            || ti.cdti_trk1 < ti.cdti_trk0)
1476                return -EINVAL;
1477        if (ti.cdti_trk1 > disk_info.last)
1478                ti.cdti_trk1 = disk_info.last;
1479
1480        msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute;
1481        msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second;
1482        msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame;
1483        msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute;
1484        msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second;
1485        msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame;
1486
1487        DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d",
1488                msf.cdmsf_min0,
1489                msf.cdmsf_sec0,
1490                msf.cdmsf_frame0,
1491                msf.cdmsf_min1,
1492                msf.cdmsf_sec1,
1493                msf.cdmsf_frame1));
1494
1495        bin2bcd(&msf);
1496        status = exec_long_cmd(COMPLAY, &msf);
1497        if (status < 0) {
1498                DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status));
1499                audio_status = CDROM_AUDIO_ERROR;
1500                return -EIO;
1501        }
1502
1503        audio_status = CDROM_AUDIO_PLAY;
1504        return 0;
1505}
1506
1507
1508static int cdromreadtochdr(void __user *arg)
1509{
1510        struct cdrom_tochdr tochdr;
1511
1512        tochdr.cdth_trk0 = disk_info.first;
1513        tochdr.cdth_trk1 = disk_info.last;
1514
1515        return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0;
1516}
1517
1518
1519static int cdromreadtocentry(void __user *arg)
1520{
1521        struct cdrom_tocentry entry;
1522        struct cdrom_subchnl *tocptr;
1523
1524        if (copy_from_user(&entry, arg, sizeof entry))
1525                return -EFAULT;
1526
1527        if (entry.cdte_track == CDROM_LEADOUT)
1528                tocptr = &toc[disk_info.last + 1];
1529        else if (entry.cdte_track > disk_info.last
1530                || entry.cdte_track < disk_info.first)
1531                return -EINVAL;
1532        else
1533                tocptr = &toc[entry.cdte_track];
1534
1535        entry.cdte_adr = tocptr->cdsc_adr;
1536        entry.cdte_ctrl = tocptr->cdsc_ctrl;
1537        entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute;
1538        entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second;
1539        entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame;
1540        /* %% What should go into entry.cdte_datamode? */
1541
1542        if (entry.cdte_format == CDROM_LBA)
1543                msf2lba(&entry.cdte_addr);
1544        else if (entry.cdte_format != CDROM_MSF)
1545                return -EINVAL;
1546
1547        return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0;
1548}
1549
1550
1551static int cdromvolctrl(void __user *arg)
1552{
1553        int status;
1554        struct cdrom_volctrl volctrl;
1555        struct cdrom_msf msf;
1556
1557        if (copy_from_user(&volctrl, arg, sizeof volctrl))
1558                return -EFAULT;
1559
1560        msf.cdmsf_min0 = 0x10;
1561        msf.cdmsf_sec0 = 0x32;
1562        msf.cdmsf_frame0 = volctrl.channel0;
1563        msf.cdmsf_min1 = volctrl.channel1;
1564        msf.cdmsf_sec1 = volctrl.channel2;
1565        msf.cdmsf_frame1 = volctrl.channel3;
1566
1567        status = exec_long_cmd(COMCHCTRL, &msf);
1568        if (status < 0) {
1569                DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status));
1570                return -EIO;
1571        }
1572        return 0;
1573}
1574
1575
1576static int cdromsubchnl(void __user *arg)
1577{
1578        int status;
1579        struct cdrom_subchnl subchnl;
1580
1581        if (copy_from_user(&subchnl, arg, sizeof subchnl))
1582                return -EFAULT;
1583
1584        if (subchnl.cdsc_format != CDROM_LBA
1585            && subchnl.cdsc_format != CDROM_MSF)
1586                return -EINVAL;
1587
1588        status = get_q_channel(&subchnl);
1589        if (status < 0) {
1590                DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status));
1591                return -EIO;
1592        }
1593
1594        if (copy_to_user(arg, &subchnl, sizeof subchnl))
1595                return -EFAULT;
1596        return 0;
1597}
1598
1599
1600static struct gendisk *optcd_disk;
1601
1602
1603static int cdromread(void __user *arg, int blocksize, int cmd)
1604{
1605        int status;
1606        struct cdrom_msf msf;
1607
1608        if (copy_from_user(&msf, arg, sizeof msf))
1609                return -EFAULT;
1610
1611        bin2bcd(&msf);
1612        msf.cdmsf_min1 = 0;
1613        msf.cdmsf_sec1 = 0;
1614        msf.cdmsf_frame1 = 1;   /* read only one frame */
1615        status = exec_read_cmd(cmd, &msf);
1616
1617        DEBUG((DEBUG_VFS, "read cmd status 0x%x", status));
1618
1619        if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT))
1620                return -EIO;
1621
1622        fetch_data(optcd_disk->private_data, blocksize);
1623
1624        if (copy_to_user(arg, optcd_disk->private_data, blocksize))
1625                return -EFAULT;
1626
1627        return 0;
1628}
1629
1630
1631static int cdromseek(void __user *arg)
1632{
1633        int status;
1634        struct cdrom_msf msf;
1635
1636        if (copy_from_user(&msf, arg, sizeof msf))
1637                return -EFAULT;
1638
1639        bin2bcd(&msf);
1640        status = exec_seek_cmd(COMSEEK, &msf);
1641
1642        DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status));
1643
1644        if (status < 0)
1645                return -EIO;
1646        return 0;
1647}
1648
1649
1650#ifdef MULTISESSION
1651static int cdrommultisession(void __user *arg)
1652{
1653        struct cdrom_multisession ms;
1654
1655        if (copy_from_user(&ms, arg, sizeof ms))
1656                return -EFAULT;
1657
1658        ms.addr.msf.minute = disk_info.last_session.minute;
1659        ms.addr.msf.second = disk_info.last_session.second;
1660        ms.addr.msf.frame = disk_info.last_session.frame;
1661
1662        if (ms.addr_format != CDROM_LBA
1663           && ms.addr_format != CDROM_MSF)
1664                return -EINVAL;
1665        if (ms.addr_format == CDROM_LBA)
1666                msf2lba(&ms.addr);
1667
1668        ms.xa_flag = disk_info.xa;
1669
1670        if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession)))
1671                return -EFAULT;
1672
1673#if DEBUG_MULTIS
1674        if (ms.addr_format == CDROM_MSF)
1675                printk(KERN_DEBUG
1676                        "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n",
1677                        ms.xa_flag,
1678                        ms.addr.msf.minute,
1679                        ms.addr.msf.second,
1680                        ms.addr.msf.frame);
1681        else
1682                printk(KERN_DEBUG
1683                    "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n",
1684                        ms.xa_flag,
1685                        ms.addr.lba,
1686                        disk_info.last_session.minute,
1687                        disk_info.last_session.second,
1688                        disk_info.last_session.frame);
1689#endif /* DEBUG_MULTIS */
1690
1691        return 0;
1692}
1693#endif /* MULTISESSION */
1694
1695
1696static int cdromreset(void)
1697{
1698        if (state != S_IDLE) {
1699                error = 1;
1700                tries = 0;
1701        }
1702
1703        toc_uptodate = 0;
1704        disk_changed = 1;
1705        opt_invalidate_buffers();
1706        audio_status = CDROM_AUDIO_NO_STATUS;
1707
1708        if (!reset_drive())
1709                return -EIO;
1710        return 0;
1711}
1712
1713/* VFS calls */
1714
1715
1716static int opt_ioctl(struct inode *ip, struct file *fp,
1717                     unsigned int cmd, unsigned long arg)
1718{
1719        int status, err, retval = 0;
1720        void __user *argp = (void __user *)arg;
1721
1722        DEBUG((DEBUG_VFS, "starting opt_ioctl"));
1723
1724        if (!ip)
1725                return -EINVAL;
1726
1727        if (cmd == CDROMRESET)
1728                return cdromreset();
1729
1730        /* is do_optcd_request or another ioctl busy? */
1731        if (state != S_IDLE || in_vfs)
1732                return -EBUSY;
1733
1734        in_vfs = 1;
1735
1736        status = drive_status();
1737        if (status < 0) {
1738                DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1739                in_vfs = 0;
1740                return -EIO;
1741        }
1742
1743        if (status & ST_DOOR_OPEN)
1744                switch (cmd) {  /* Actions that can be taken with door open */
1745                case CDROMCLOSETRAY:
1746                        /* We do this before trying to read the toc. */
1747                        err = exec_cmd(COMCLOSE);
1748                        if (err < 0) {
1749                                DEBUG((DEBUG_VFS,
1750                                       "exec_cmd COMCLOSE: %02x", -err));
1751                                in_vfs = 0;
1752                                return -EIO;
1753                        }
1754                        break;
1755                default:        in_vfs = 0;
1756                                return -EBUSY;
1757                }
1758
1759        err = update_toc();
1760        if (err < 0) {
1761                DEBUG((DEBUG_VFS, "update_toc: %02x", -err));
1762                in_vfs = 0;
1763                return -EIO;
1764        }
1765
1766        DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd));
1767
1768        switch (cmd) {
1769        case CDROMPAUSE:        retval = cdrompause(); break;
1770        case CDROMRESUME:       retval = cdromresume(); break;
1771        case CDROMPLAYMSF:      retval = cdromplaymsf(argp); break;
1772        case CDROMPLAYTRKIND:   retval = cdromplaytrkind(argp); break;
1773        case CDROMREADTOCHDR:   retval = cdromreadtochdr(argp); break;
1774        case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break;
1775
1776        case CDROMSTOP:         err = exec_cmd(COMSTOP);
1777                                if (err < 0) {
1778                                        DEBUG((DEBUG_VFS,
1779                                                "exec_cmd COMSTOP: %02x",
1780                                                -err));
1781                                        retval = -EIO;
1782                                } else
1783                                        audio_status = CDROM_AUDIO_NO_STATUS;
1784                                break;
1785        case CDROMSTART:        break;  /* This is a no-op */
1786        case CDROMEJECT:        err = exec_cmd(COMUNLOCK);
1787                                if (err < 0) {
1788                                        DEBUG((DEBUG_VFS,
1789                                                "exec_cmd COMUNLOCK: %02x",
1790                                                -err));
1791                                        retval = -EIO;
1792                                        break;
1793                                }
1794                                err = exec_cmd(COMOPEN);
1795                                if (err < 0) {
1796                                        DEBUG((DEBUG_VFS,
1797                                                "exec_cmd COMOPEN: %02x",
1798                                                -err));
1799                                        retval = -EIO;
1800                                }
1801                                break;
1802
1803        case CDROMVOLCTRL:      retval = cdromvolctrl(argp); break;
1804        case CDROMSUBCHNL:      retval = cdromsubchnl(argp); break;
1805
1806        /* The drive detects the mode and automatically delivers the
1807           correct 2048 bytes, so we don't need these IOCTLs */
1808        case CDROMREADMODE2:    retval = -EINVAL; break;
1809        case CDROMREADMODE1:    retval = -EINVAL; break;
1810
1811        /* Drive doesn't support reading audio */
1812        case CDROMREADAUDIO:    retval = -EINVAL; break;
1813
1814        case CDROMEJECT_SW:     auto_eject = (char) arg;
1815                                break;
1816
1817#ifdef MULTISESSION
1818        case CDROMMULTISESSION: retval = cdrommultisession(argp); break;
1819#endif
1820
1821        case CDROM_GET_MCN:     retval = -EINVAL; break; /* not implemented */
1822        case CDROMVOLREAD:      retval = -EINVAL; break; /* not implemented */
1823
1824        case CDROMREADRAW:
1825                        /* this drive delivers 2340 bytes in raw mode */
1826                        retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW);
1827                        break;
1828        case CDROMREADCOOKED:
1829                        retval = cdromread(argp, CD_FRAMESIZE, COMREAD);
1830                        break;
1831        case CDROMREADALL:
1832                        retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL);
1833                        break;
1834
1835        case CDROMSEEK:         retval = cdromseek(argp); break;
1836        case CDROMPLAYBLK:      retval = -EINVAL; break; /* not implemented */
1837        case CDROMCLOSETRAY:    break;  /* The action was taken earlier */
1838        default:                retval = -EINVAL;
1839        }
1840        in_vfs = 0;
1841        return retval;
1842}
1843
1844
1845static int open_count = 0;
1846
1847/* Open device special file; check that a disk is in. */
1848static int opt_open(struct inode *ip, struct file *fp)
1849{
1850        DEBUG((DEBUG_VFS, "starting opt_open"));
1851
1852        if (!open_count && state == S_IDLE) {
1853                int status;
1854                char *buf;
1855
1856                buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL);
1857                if (!buf) {
1858                        printk(KERN_INFO "optcd: cannot allocate read buffer\n");
1859                        return -ENOMEM;
1860                }
1861                optcd_disk->private_data = buf;         /* save read buffer */
1862
1863                toc_uptodate = 0;
1864                opt_invalidate_buffers();
1865
1866                status = exec_cmd(COMCLOSE);    /* close door */
1867                if (status < 0) {
1868                        DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status));
1869                }
1870
1871                status = drive_status();
1872                if (status < 0) {
1873                        DEBUG((DEBUG_VFS, "drive_status: %02x", -status));
1874                        goto err_out;
1875                }
1876                DEBUG((DEBUG_VFS, "status: %02x", status));
1877                if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) {
1878                        printk(KERN_INFO "optcd: no disk or door open\n");
1879                        goto err_out;
1880                }
1881                status = exec_cmd(COMLOCK);             /* Lock door */
1882                if (status < 0) {
1883                        DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status));
1884                }
1885                status = update_toc();  /* Read table of contents */
1886                if (status < 0) {
1887                        DEBUG((DEBUG_VFS, "update_toc: %02x", -status));
1888                        status = exec_cmd(COMUNLOCK);   /* Unlock door */
1889                        if (status < 0) {
1890                                DEBUG((DEBUG_VFS,
1891                                       "exec_cmd COMUNLOCK: %02x", -status));
1892                        }
1893                        goto err_out;
1894                }
1895                open_count++;
1896        }
1897
1898        DEBUG((DEBUG_VFS, "exiting opt_open"));
1899
1900        return 0;
1901
1902err_out:
1903        return -EIO;
1904}
1905
1906
1907/* Release device special file; flush all blocks from the buffer cache */
1908static int opt_release(struct inode *ip, struct file *fp)
1909{
1910        int status;
1911
1912        DEBUG((DEBUG_VFS, "executing opt_release"));
1913        DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n",
1914                ip, ip->i_bdev->bd_disk->disk_name, fp));
1915
1916        if (!--open_count) {
1917                toc_uptodate = 0;
1918                opt_invalidate_buffers();
1919                status = exec_cmd(COMUNLOCK);   /* Unlock door */
1920                if (status < 0) {
1921                        DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status));
1922                }
1923                if (auto_eject) {
1924                        status = exec_cmd(COMOPEN);
1925                        DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status));
1926                }
1927                kfree(optcd_disk->private_data);
1928                del_timer(&delay_timer);
1929                del_timer(&req_timer);
1930        }
1931        return 0;
1932}
1933
1934
1935/* Check if disk has been changed */
1936static int opt_media_change(struct gendisk *disk)
1937{
1938        DEBUG((DEBUG_VFS, "executing opt_media_change"));
1939        DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n",
1940                        disk->disk_name, disk_changed));
1941
1942        if (disk_changed) {
1943                disk_changed = 0;
1944                return 1;
1945        }
1946        return 0;
1947}
1948
1949/* Driver initialisation */
1950
1951
1952/* Returns 1 if a drive is detected with a version string
1953   starting with "DOLPHIN". Otherwise 0. */
1954static int __init version_ok(void)
1955{
1956        char devname[100];
1957        int count, i, ch, status;
1958
1959        status = exec_cmd(COMVERSION);
1960        if (status < 0) {
1961                DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status));
1962                return 0;
1963        }
1964        if ((count = get_data(1)) < 0) {
1965                DEBUG((DEBUG_VFS, "get_data(1): %02x", -count));
1966                return 0;
1967        }
1968        for (i = 0, ch = -1; count > 0; count--) {
1969                if ((ch = get_data(1)) < 0) {
1970                        DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch));
1971                        break;
1972                }
1973                if (i < 99)
1974                        devname[i++] = ch;
1975        }
1976        devname[i] = '\0';
1977        if (ch < 0)
1978                return 0;
1979
1980        printk(KERN_INFO "optcd: Device %s detected\n", devname);
1981        return ((devname[0] == 'D')
1982             && (devname[1] == 'O')
1983             && (devname[2] == 'L')
1984             && (devname[3] == 'P')
1985             && (devname[4] == 'H')
1986             && (devname[5] == 'I')
1987             && (devname[6] == 'N'));
1988}
1989
1990
1991static struct block_device_operations opt_fops = {
1992        .owner          = THIS_MODULE,
1993        .open           = opt_open,
1994        .release        = opt_release,
1995        .ioctl          = opt_ioctl,
1996        .media_changed  = opt_media_change,
1997};
1998
1999#ifndef MODULE
2000/* Get kernel parameter when used as a kernel driver */
2001static int optcd_setup(char *str)
2002{
2003        int ints[4];
2004        (void)get_options(str, ARRAY_SIZE(ints), ints);
2005        
2006        if (ints[0] > 0)
2007                optcd_port = ints[1];
2008
2009        return 1;
2010}
2011
2012__setup("optcd=", optcd_setup);
2013
2014#endif /* MODULE */
2015
2016/* Test for presence of drive and initialize it. Called at boot time
2017   or during module initialisation. */
2018static int __init optcd_init(void)
2019{
2020        int status;
2021
2022        if (optcd_port <= 0) {
2023                printk(KERN_INFO
2024                        "optcd: no Optics Storage CDROM Initialization\n");
2025                return -EIO;
2026        }
2027        optcd_disk = alloc_disk(1);
2028        if (!optcd_disk) {
2029                printk(KERN_ERR "optcd: can't allocate disk\n");
2030                return -ENOMEM;
2031        }
2032        optcd_disk->major = MAJOR_NR;
2033        optcd_disk->first_minor = 0;
2034        optcd_disk->fops = &opt_fops;
2035        sprintf(optcd_disk->disk_name, "optcd");
2036        sprintf(optcd_disk->devfs_name, "optcd");
2037
2038        if (!request_region(optcd_port, 4, "optcd")) {
2039                printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
2040                        optcd_port);
2041                put_disk(optcd_disk);
2042                return -EIO;
2043        }
2044
2045        if (!reset_drive()) {
2046                printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port);
2047                release_region(optcd_port, 4);
2048                put_disk(optcd_disk);
2049                return -EIO;
2050        }
2051        if (!version_ok()) {
2052                printk(KERN_ERR "optcd: unknown drive detected; aborting\n");
2053                release_region(optcd_port, 4);
2054                put_disk(optcd_disk);
2055                return -EIO;
2056        }
2057        status = exec_cmd(COMINITDOUBLE);
2058        if (status < 0) {
2059                printk(KERN_ERR "optcd: cannot init double speed mode\n");
2060                release_region(optcd_port, 4);
2061                DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status));
2062                put_disk(optcd_disk);
2063                return -EIO;
2064        }
2065        if (register_blkdev(MAJOR_NR, "optcd")) {
2066                release_region(optcd_port, 4);
2067                put_disk(optcd_disk);
2068                return -EIO;
2069        }
2070
2071
2072        opt_queue = blk_init_queue(do_optcd_request, &optcd_lock);
2073        if (!opt_queue) {
2074                unregister_blkdev(MAJOR_NR, "optcd");
2075                release_region(optcd_port, 4);
2076                put_disk(optcd_disk);
2077                return -ENOMEM;
2078        }
2079
2080        blk_queue_hardsect_size(opt_queue, 2048);
2081        optcd_disk->queue = opt_queue;
2082        add_disk(optcd_disk);
2083
2084        printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port);
2085        return 0;
2086}
2087
2088
2089static void __exit optcd_exit(void)
2090{
2091        del_gendisk(optcd_disk);
2092        put_disk(optcd_disk);
2093        if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) {
2094                printk(KERN_ERR "optcd: what's that: can't unregister\n");
2095                return;
2096        }
2097        blk_cleanup_queue(opt_queue);
2098        release_region(optcd_port, 4);
2099        printk(KERN_INFO "optcd: module released.\n");
2100}
2101
2102module_init(optcd_init);
2103module_exit(optcd_exit);
2104
2105MODULE_LICENSE("GPL");
2106MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR);
2107
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.