at v2.6.21 2105 lines 52 kB view raw
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 vsnprintf(s, sizeof(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_param(optcd_port, short, 0); 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. */ 248static inline 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 DEFINE_TIMER(delay_timer, sleep_timer, 0, 0); 268static DEFINE_SPINLOCK(optcd_lock); 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. */ 384static inline 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. */ 401static inline 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 */ 444static inline 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 */ 451static inline 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. */ 465static inline 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 */ 473static inline 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 */ 485static inline 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. */ 496static inline 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 */ 506static inline 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 */ 519static inline 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) */ 531static inline 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 */ 568static inline 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 991static inline 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 2037 if (!request_region(optcd_port, 4, "optcd")) { 2038 printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n", 2039 optcd_port); 2040 put_disk(optcd_disk); 2041 return -EIO; 2042 } 2043 2044 if (!reset_drive()) { 2045 printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port); 2046 release_region(optcd_port, 4); 2047 put_disk(optcd_disk); 2048 return -EIO; 2049 } 2050 if (!version_ok()) { 2051 printk(KERN_ERR "optcd: unknown drive detected; aborting\n"); 2052 release_region(optcd_port, 4); 2053 put_disk(optcd_disk); 2054 return -EIO; 2055 } 2056 status = exec_cmd(COMINITDOUBLE); 2057 if (status < 0) { 2058 printk(KERN_ERR "optcd: cannot init double speed mode\n"); 2059 release_region(optcd_port, 4); 2060 DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status)); 2061 put_disk(optcd_disk); 2062 return -EIO; 2063 } 2064 if (register_blkdev(MAJOR_NR, "optcd")) { 2065 release_region(optcd_port, 4); 2066 put_disk(optcd_disk); 2067 return -EIO; 2068 } 2069 2070 2071 opt_queue = blk_init_queue(do_optcd_request, &optcd_lock); 2072 if (!opt_queue) { 2073 unregister_blkdev(MAJOR_NR, "optcd"); 2074 release_region(optcd_port, 4); 2075 put_disk(optcd_disk); 2076 return -ENOMEM; 2077 } 2078 2079 blk_queue_hardsect_size(opt_queue, 2048); 2080 optcd_disk->queue = opt_queue; 2081 add_disk(optcd_disk); 2082 2083 printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); 2084 return 0; 2085} 2086 2087 2088static void __exit optcd_exit(void) 2089{ 2090 del_gendisk(optcd_disk); 2091 put_disk(optcd_disk); 2092 if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { 2093 printk(KERN_ERR "optcd: what's that: can't unregister\n"); 2094 return; 2095 } 2096 blk_cleanup_queue(opt_queue); 2097 release_region(optcd_port, 4); 2098 printk(KERN_INFO "optcd: module released.\n"); 2099} 2100 2101module_init(optcd_init); 2102module_exit(optcd_exit); 2103 2104MODULE_LICENSE("GPL"); 2105MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR);