diff options
Diffstat (limited to 'drivers/cdrom/sonycd535.c')
-rw-r--r-- | drivers/cdrom/sonycd535.c | 1689 |
1 files changed, 0 insertions, 1689 deletions
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c deleted file mode 100644 index f77ada933ea0..000000000000 --- a/drivers/cdrom/sonycd535.c +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Sony CDU-535 interface device driver - * - * This is a modified version of the CDU-31A device driver (see below). - * Changes were made using documentation for the CDU-531 (which Sony - * assures me is very similar to the 535) and partial disassembly of the - * DOS driver. I used Minyard's driver and replaced the CDU-31A - * commands with the CDU-531 commands. This was complicated by a different - * interface protocol with the drive. The driver is still polled. - * - * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec. - * I tried polling without the sony_sleep during the data transfers but - * it did not speed things up any. - * - * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict - * with CDU-31A driver. This is the also the number from the Linux - * Device Driver Registry for the Sony Drive. Hope nobody else is using it. - * - * 1993-08-29 (rgj) remove the configuring of the interface board address - * from the top level configuration, you have to modify it in this file. - * - * 1995-01-26 Made module-capable (Joel Katz <Stimpson@Panix.COM>) - * - * 1995-05-20 - * Modified to support CDU-510/515 series - * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) - * Fixed to report verify_area() failures - * (Heiko Eissfeldt <heiko@colossus.escape.de>) - * - * 1995-06-01 - * More changes to support CDU-510/515 series - * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) - * - * November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen <tmm@image.dk> - * - * September 2003 - Fix SMP support by removing cli/sti calls. - * Using spinlocks with a wait_queue instead. - * Felipe Damasio <felipewd@terra.com.br> - * - * Things to do: - * - handle errors and status better, put everything into a single word - * - use interrupts (code mostly there, but a big hole still missing) - * - handle multi-session CDs? - * - use DMA? - * - * Known Bugs: - * - - * - * Ken Pizzini (ken@halcyon.com) - * - * Original by: - * Ron Jeppesen (ronj.an@site007.saic.com) - * - * - *------------------------------------------------------------------------ - * Sony CDROM interface device driver. - * - * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above) - * - * Colossians 3:17 - * - * The Sony interface device driver handles Sony interface CDROM - * drives and provides a complete block-level interface as well as an - * ioctl() interface compatible with the Sun (as specified in - * include/linux/cdrom.h). With this interface, CDROMs can be - * accessed and standard audio CDs can be played back normally. - * - * This interface is (unfortunately) a polled interface. This is - * because most Sony interfaces are set up with DMA and interrupts - * disables. Some (like mine) do not even have the capability to - * handle interrupts or DMA. For this reason you will see a bit of - * the following: - * - * snap = jiffies; - * while (jiffies-snap < SONY_JIFFIES_TIMEOUT) - * { - * if (some_condition()) - * break; - * sony_sleep(); - * } - * if (some_condition not met) - * { - * return an_error; - * } - * - * This ugly hack waits for something to happen, sleeping a little - * between every try. (The conditional is written so that jiffies - * wrap-around is handled properly.) - * - * One thing about these drives: They talk in MSF (Minute Second Frame) format. - * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a - * disk. The funny thing is that these are sent to the drive in BCD, but the - * interface wants to see them in decimal. A lot of conversion goes on. - * - * Copyright (C) 1993 Corey Minyard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -# include <linux/module.h> - -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/hdreg.h> -#include <linux/genhd.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/init.h> - -#define REALLY_SLOW_IO -#include <asm/system.h> -#include <asm/io.h> -#include <asm/uaccess.h> - -#include <linux/cdrom.h> - -#define MAJOR_NR CDU535_CDROM_MAJOR -#include <linux/blkdev.h> - -#define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ -#include "sonycd535.h" - -/* - * this is the base address of the interface card for the Sony CDU-535 - * CDROM drive. If your jumpers are set for an address other than - * this one (the default), change the following line to the - * proper address. - */ -#ifndef CDU535_ADDRESS -# define CDU535_ADDRESS 0x340 -#endif -#ifndef CDU535_INTERRUPT -# define CDU535_INTERRUPT 0 -#endif -#ifndef CDU535_HANDLE -# define CDU535_HANDLE "cdu535" -#endif -#ifndef CDU535_MESSAGE_NAME -# define CDU535_MESSAGE_NAME "Sony CDU-535" -#endif - -#define CDU535_BLOCK_SIZE 2048 - -#ifndef MAX_SPINUP_RETRY -# define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ -#endif -#ifndef RETRY_FOR_BAD_STATUS -# define RETRY_FOR_BAD_STATUS 100 /* in 10th of second */ -#endif - -#ifndef DEBUG -# define DEBUG 1 -#endif - -/* - * SONY535_BUFFER_SIZE determines the size of internal buffer used - * by the drive. It must be at least 2K and the larger the buffer - * the better the transfer rate. It does however take system memory. - * On my system I get the following transfer rates using dd to read - * 10 Mb off /dev/cdrom. - * - * 8K buffer 43 Kb/sec - * 16K buffer 66 Kb/sec - * 32K buffer 91 Kb/sec - * 64K buffer 111 Kb/sec - * 128K buffer 123 Kb/sec - * 512K buffer 123 Kb/sec - */ -#define SONY535_BUFFER_SIZE (64*1024) - -/* - * if LOCK_DOORS is defined then the eject button is disabled while - * the device is open. - */ -#ifndef NO_LOCK_DOORS -# define LOCK_DOORS -#endif - -static int read_subcode(void); -static void sony_get_toc(void); -static int cdu_open(struct inode *inode, struct file *filp); -static inline unsigned int int_to_bcd(unsigned int val); -static unsigned int bcd_to_int(unsigned int bcd); -static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], - Byte * response, int n_response, int ignoreStatusBit7); - -/* The base I/O address of the Sony Interface. This is a variable (not a - #define) so it can be easily changed via some future ioctl() */ -static unsigned int sony535_cd_base_io = CDU535_ADDRESS; -module_param(sony535_cd_base_io, int, 0); - -/* - * The following are I/O addresses of the various registers for the drive. The - * comment for the base address also applies here. - */ -static unsigned short select_unit_reg; -static unsigned short result_reg; -static unsigned short command_reg; -static unsigned short read_status_reg; -static unsigned short data_reg; - -static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */ -static struct request_queue *sonycd535_queue; - -static int initialized; /* Has the drive been initialized? */ -static int sony_disc_changed = 1; /* Has the disk been changed - since the last check? */ -static int sony_toc_read; /* Has the table of contents been - read? */ -static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead - buffer. */ -static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of - the read-ahead buffer. */ -static unsigned int sony_usage; /* How many processes have the - drive open. */ - -static int sony_first_block = -1; /* First OS block (512 byte) in - the read-ahead buffer */ -static int sony_last_block = -1; /* Last OS block (512 byte) in - the read-ahead buffer */ - -static struct s535_sony_toc *sony_toc; /* Points to the table of - contents. */ - -static struct s535_sony_subcode *last_sony_subcode; /* Points to the last - subcode address read */ -static Byte **sony_buffer; /* Points to the pointers - to the sector buffers */ - -static int sony_inuse; /* is the drive in use? Only one - open at a time allowed */ - -/* - * The audio status uses the values from read subchannel data as specified - * in include/linux/cdrom.h. - */ -static int sony_audio_status = CDROM_AUDIO_NO_STATUS; - -/* - * The following are a hack for pausing and resuming audio play. The drive - * does not work as I would expect it, if you stop it then start it again, - * the drive seeks back to the beginning and starts over. This holds the - * position during a pause so a resume can restart it. It uses the - * audio status variable above to tell if it is paused. - * I just kept the CDU-31A driver behavior rather than using the PAUSE - * command on the CDU-535. - */ -static Byte cur_pos_msf[3]; -static Byte final_pos_msf[3]; - -/* What IRQ is the drive using? 0 if none. */ -static int sony535_irq_used = CDU535_INTERRUPT; - -/* The interrupt handler will wake this queue up when it gets an interrupt. */ -static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); - - -/* - * This routine returns 1 if the disk has been changed since the last - * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. - */ -static int -cdu535_check_media_change(struct gendisk *disk) -{ - /* if driver is not initialized, always return 0 */ - int retval = initialized ? sony_disc_changed : 0; - sony_disc_changed = 0; - return retval; -} - -static inline void -enable_interrupts(void) -{ -#ifdef USE_IRQ - /* - * This code was taken from cdu31a.c; it will not - * directly work for the cdu535 as written... - */ - curr_control_reg |= ( SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -#endif -} - -static inline void -disable_interrupts(void) -{ -#ifdef USE_IRQ - /* - * This code was taken from cdu31a.c; it will not - * directly work for the cdu535 as written... - */ - curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -#endif -} - -static irqreturn_t -cdu535_interrupt(int irq, void *dev_id) -{ - disable_interrupts(); - if (waitqueue_active(&cdu535_irq_wait)) { - wake_up(&cdu535_irq_wait); - return IRQ_HANDLED; - } - printk(CDU535_MESSAGE_NAME - ": Got an interrupt but nothing was waiting\n"); - return IRQ_NONE; -} - - -/* - * Wait a little while. - */ -static inline void -sony_sleep(void) -{ - if (sony535_irq_used <= 0) { /* poll */ - yield(); - } else { /* Interrupt driven */ - DEFINE_WAIT(wait); - - spin_lock_irq(&sonycd535_lock); - enable_interrupts(); - prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irq(&sonycd535_lock); - schedule(); - finish_wait(&cdu535_irq_wait, &wait); - } -} - -/*------------------start of SONY CDU535 very specific ---------------------*/ - -/**************************************************************************** - * void select_unit( int unit_no ) - * - * Select the specified unit (0-3) so that subsequent commands reference it - ****************************************************************************/ -static void -select_unit(int unit_no) -{ - unsigned int select_mask = ~(1 << unit_no); - outb(select_mask, select_unit_reg); -} - -/*************************************************************************** - * int read_result_reg( Byte *data_ptr ) - * - * Read a result byte from the Sony CDU controller, store in location pointed - * to by data_ptr. Return zero on success, TIME_OUT if we did not receive - * data. - ***************************************************************************/ -static int -read_result_reg(Byte *data_ptr) -{ - unsigned long snap; - int read_status; - - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - read_status = inb(read_status_reg); - if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME - ": read_result_reg(): readStatReg = 0x%x\n", read_status); -#endif - *data_ptr = inb(result_reg); - return 0; - } else { - sony_sleep(); - } - } - printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n"); - return TIME_OUT; -} - -/**************************************************************************** - * int read_exec_status( Byte status[2] ) - * - * Read the execution status of the last command and put into status. - * Handles reading second status word if available. Returns 0 on success, - * TIME_OUT on failure. - ****************************************************************************/ -static int -read_exec_status(Byte status[2]) -{ - status[1] = 0; - if (read_result_reg(&(status[0])) != 0) - return TIME_OUT; - if ((status[0] & 0x80) != 0) { /* byte two follows */ - if (read_result_reg(&(status[1])) != 0) - return TIME_OUT; - } -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n", - status[0], status[1]); -#endif - return 0; -} - -/**************************************************************************** - * int check_drive_status( void ) - * - * Check the current drive status. Using this before executing a command - * takes care of the problem of unsolicited drive status-2 messages. - * Add a check of the audio status if we think the disk is playing. - ****************************************************************************/ -static int -check_drive_status(void) -{ - Byte status, e_status[2]; - int CDD, ATN; - Byte cmd; - - select_unit(0); - if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ - outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); - if (read_result_reg(&status) == 0) { - switch (status) { - case 0x0: - break; /* play in progress */ - case 0x1: - break; /* paused */ - case 0x3: /* audio play completed */ - case 0x5: /* play not requested */ - sony_audio_status = CDROM_AUDIO_COMPLETED; - read_subcode(); - break; - case 0x4: /* error during play */ - sony_audio_status = CDROM_AUDIO_ERROR; - break; - } - } - } - /* now check drive status */ - outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); - if (read_result_reg(&status) != 0) - return TIME_OUT; - -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status); -#endif - - if (status == 0) - return 0; - - ATN = status & 0xf; - CDD = (status >> 4) & 0xf; - - switch (ATN) { - case 0x0: - break; /* go on to CDD stuff */ - case SONY535_ATN_BUSY: - if (initialized) - printk(CDU535_MESSAGE_NAME " error: drive busy\n"); - return CD_BUSY; - case SONY535_ATN_EJECT_IN_PROGRESS: - printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); - sony_audio_status = CDROM_AUDIO_INVALID; - return CD_BUSY; - case SONY535_ATN_RESET_OCCURRED: - case SONY535_ATN_DISC_CHANGED: - case SONY535_ATN_RESET_AND_DISC_CHANGED: -#if DEBUG > 0 - printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n"); -#endif - sony_disc_changed = 1; - sony_toc_read = 0; - sony_audio_status = CDROM_AUDIO_NO_STATUS; - sony_first_block = -1; - sony_last_block = -1; - if (initialized) { - cmd = SONY535_SPIN_UP; - do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); - sony_get_toc(); - } - return 0; - default: - printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); - return CD_BUSY; - } - switch (CDD) { /* the 531 docs are not helpful in decoding this */ - case 0x0: /* just use the values from the DOS driver */ - case 0x2: - case 0xa: - break; /* no error */ - case 0xc: - printk(CDU535_MESSAGE_NAME - ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); - return CD_BUSY; /* ? */ - default: - return CD_BUSY; - } - return 0; -} /* check_drive_status() */ - -/***************************************************************************** - * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], - * Byte *response, int n_response, int ignore_status_bit7 ) - * - * Generic routine for executing commands. The command and its parameters - * should be placed in the cmd[] array, number of bytes in the command is - * stored in nCmd. The response from the command will be stored in the - * response array. The number of bytes you expect back (excluding status) - * should be passed in n_response. Finally, some - * commands set bit 7 of the return status even when there is no second - * status byte, on these commands set ignoreStatusBit7 TRUE. - * If the command was sent and data received back, then we return 0, - * else we return TIME_OUT. You still have to check the status yourself. - * You should call check_drive_status() before calling this routine - * so that you do not lose notifications of disk changes, etc. - ****************************************************************************/ -static int -do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], - Byte * response, int n_response, int ignore_status_bit7) -{ - int i; - - /* write out the command */ - for (i = 0; i < n_cmd; i++) - outb(cmd[i], command_reg); - - /* read back the status */ - if (read_result_reg(status) != 0) - return TIME_OUT; - if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { - /* get second status byte */ - if (read_result_reg(status + 1) != 0) - return TIME_OUT; - } else { - status[1] = 0; - } -#if DEBUG > 2 - printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", - *cmd, status[0], status[1]); -#endif - - /* do not know about when I should read set of data and when not to */ - if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) - return 0; - - /* else, read in rest of data */ - for (i = 0; 0 < n_response; n_response--, i++) - if (read_result_reg(response + i) != 0) - return TIME_OUT; - return 0; -} /* do_sony_cmd() */ - -/************************************************************************** - * int set_drive_mode( int mode, Byte status[2] ) - * - * Set the drive mode to the specified value (mode=0 is audio, mode=e0 - * is mode-1 CDROM - **************************************************************************/ -static int -set_drive_mode(int mode, Byte status[2]) -{ - Byte cmd_buff[2]; - Byte ret_buff[1]; - - cmd_buff[0] = SONY535_SET_DRIVE_MODE; - cmd_buff[1] = mode; - return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1); -} - -/*************************************************************************** - * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], - * Byte *data_buff, int buff_size ) - * - * Read n_blocks of data from the CDROM starting at position params[0:2], - * number of blocks in stored in params[3:5] -- both these are already - * int bcd format. - * Transfer the data into the buffer pointed at by data_buff. buff_size - * gives the number of bytes available in the buffer. - * The routine returns number of bytes read in if successful, otherwise - * it returns one of the standard error returns. - ***************************************************************************/ -static int -seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], - Byte **buff, int buf_size) -{ - Byte cmd_buff[7]; - int i; - int read_status; - unsigned long snap; - Byte *data_buff; - int sector_count = 0; - - if (buf_size < CDU535_BLOCK_SIZE * n_blocks) - return NO_ROOM; - - set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); - - /* send command to read the data */ - cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; - for (i = 0; i < 6; i++) - cmd_buff[i + 1] = params[i]; - for (i = 0; i < 7; i++) - outb(cmd_buff[i], command_reg); - - /* read back the data one block at a time */ - while (0 < n_blocks--) { - /* wait for data to be ready */ - int data_valid = 0; - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - read_status = inb(read_status_reg); - if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { - read_exec_status(status); - return BAD_STATUS; - } - if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { - /* data is ready, read it */ - data_buff = buff[sector_count++]; - for (i = 0; i < CDU535_BLOCK_SIZE; i++) - *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ - data_valid = 1; - break; /* exit the timeout loop */ - } - sony_sleep(); /* data not ready, sleep a while */ - } - if (!data_valid) - return TIME_OUT; /* if we reach this stage */ - } - - /* read all the data, now read the status */ - if ((i = read_exec_status(status)) != 0) - return i; - return CDU535_BLOCK_SIZE * sector_count; -} /* seek_and_read_N_blocks() */ - -/**************************************************************************** - * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) - * - * Read in the table of contents data. Converts all the bcd data - * into integers in the toc structure. - ****************************************************************************/ -static int -request_toc_data(Byte status[2], struct s535_sony_toc *toc) -{ - int to_status; - int i, j, n_tracks, track_no; - int first_track_num, last_track_num; - Byte cmd_no = 0xb2; - Byte track_address_buffer[5]; - - /* read the fixed portion of the table of contents */ - if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) - return to_status; - - /* convert the data into integers so we can use them */ - first_track_num = bcd_to_int(toc->first_track_num); - last_track_num = bcd_to_int(toc->last_track_num); - n_tracks = last_track_num - first_track_num + 1; - - /* read each of the track address descriptors */ - for (i = 0; i < n_tracks; i++) { - /* read the descriptor into a temporary buffer */ - for (j = 0; j < 5; j++) { - if (read_result_reg(track_address_buffer + j) != 0) - return TIME_OUT; - if (j == 1) /* need to convert from bcd */ - track_no = bcd_to_int(track_address_buffer[j]); - } - /* copy the descriptor to proper location - sonycd.c just fills */ - memcpy(toc->tracks + i, track_address_buffer, 5); - } - return 0; -} /* request_toc_data() */ - -/*************************************************************************** - * int spin_up_drive( Byte status[2] ) - * - * Spin up the drive (unless it is already spinning). - ***************************************************************************/ -static int -spin_up_drive(Byte status[2]) -{ - Byte cmd; - - /* first see if the drive is already spinning */ - cmd = SONY535_REQUEST_DRIVE_STATUS_1; - if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) - return TIME_OUT; - if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) - return 0; /* it's already spinning */ - - /* otherwise, give the spin-up command */ - cmd = SONY535_SPIN_UP; - return do_sony_cmd(&cmd, 1, status, NULL, 0, 0); -} - -/*--------------------end of SONY CDU535 very specific ---------------------*/ - -/* Convert from an integer 0-99 to BCD */ -static inline unsigned int -int_to_bcd(unsigned int val) -{ - int retval; - - retval = (val / 10) << 4; - retval = retval | val % 10; - return retval; -} - - -/* Convert from BCD to an integer from 0-99 */ -static unsigned int -bcd_to_int(unsigned int bcd) -{ - return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); -} - - -/* - * Convert a logical sector value (like the OS would want to use for - * a block device) to an MSF format. - */ -static void -log_to_msf(unsigned int log, Byte *msf) -{ - log = log + LOG_START_OFFSET; - msf[0] = int_to_bcd(log / 4500); - log = log % 4500; - msf[1] = int_to_bcd(log / 75); - msf[2] = int_to_bcd(log % 75); -} - - -/* - * Convert an MSF format to a logical sector. - */ -static unsigned int -msf_to_log(Byte *msf) -{ - unsigned int log; - - - log = bcd_to_int(msf[2]); - log += bcd_to_int(msf[1]) * 75; - log += bcd_to_int(msf[0]) * 4500; - log = log - LOG_START_OFFSET; - - return log; -} - - -/* - * Take in integer size value and put it into a buffer like - * the drive would want to see a number-of-sector value. - */ -static void -size_to_buf(unsigned int size, Byte *buf) -{ - buf[0] = size / 65536; - size = size % 65536; - buf[1] = size / 256; - buf[2] = size % 256; -} - - -/* - * The OS calls this to perform a read or write operation to the drive. - * Write obviously fail. Reads to a read ahead of sony_buffer_size - * bytes to help speed operations. This especially helps since the OS - * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most - * data access on a CD is done sequentially, this saves a lot of operations. - */ -static void -do_cdu535_request(request_queue_t * q) -{ - struct request *req; - unsigned int read_size; - int block; - int nsect; - int copyoff; - int spin_up_retry; - Byte params[10]; - Byte status[2]; - Byte cmd[2]; - - while (1) { - req = elv_next_request(q); - if (!req) - return; - - block = req->sector; - nsect = req->nr_sectors; - if (!blk_fs_request(req)) { - end_request(req, 0); - continue; - } - if (rq_data_dir(req) == WRITE) { - end_request(req, 0); - continue; - } - /* - * If the block address is invalid or the request goes beyond - * the end of the media, return an error. - */ - if (sony_toc->lead_out_start_lba <= (block/4)) { - end_request(req, 0); - return; - } - if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { - end_request(req, 0); - return; - } - while (0 < nsect) { - /* - * If the requested sector is not currently in - * the read-ahead buffer, it must be read in. - */ - if ((block < sony_first_block) || (sony_last_block < block)) { - sony_first_block = (block / 4) * 4; - log_to_msf(block / 4, params); - - /* - * If the full read-ahead would go beyond the end of the media, trim - * it back to read just till the end of the media. - */ - if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { - sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; - read_size = sony_toc->lead_out_start_lba - (block / 4); - } else { - sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; - read_size = sony_buffer_sectors; - } - size_to_buf(read_size, ¶ms[3]); - - /* - * Read the data. If the drive was not spinning, - * spin it up and try some more. - */ - for (spin_up_retry=0 ;; ++spin_up_retry) { - /* This loop has been modified to support the Sony - * CDU-510/515 series, thanks to Claudio Porfiri - * <C.Porfiri@nisms.tei.ericsson.se>. - */ - /* - * This part is to deal with very slow hardware. We - * try at most MAX_SPINUP_RETRY times to read the same - * block. A check for seek_and_read_N_blocks' result is - * performed; if the result is wrong, the CDROM's engine - * is restarted and the operation is tried again. - */ - /* - * 1995-06-01: The system got problems when downloading - * from Slackware CDROM, the problem seems to be: - * seek_and_read_N_blocks returns BAD_STATUS and we - * should wait for a while before retrying, so a new - * part was added to discriminate the return value from - * seek_and_read_N_blocks for the various cases. - */ - int readStatus = seek_and_read_N_blocks(params, read_size, - status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); - if (0 <= readStatus) /* Good data; common case, placed first */ - break; - if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { - /* give up */ - if (readStatus == NO_ROOM) - printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); - else - printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", - status[0]); - sony_first_block = -1; - sony_last_block = -1; - end_request(req, 0); - return; - } - if (readStatus == BAD_STATUS) { - /* Sleep for a while, then retry */ - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&sonycd535_lock); - schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); - spin_lock_irq(&sonycd535_lock); - } -#if DEBUG > 0 - printk(CDU535_MESSAGE_NAME - " debug: calling spin up when reading data!\n"); -#endif - cmd[0] = SONY535_SPIN_UP; - do_sony_cmd(cmd, 1, status, NULL, 0, 0); - } - } - /* - * The data is in memory now, copy it to the buffer and advance to the - * next block to read. - */ - copyoff = block - sony_first_block; - memcpy(req->buffer, - sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); - - block += 1; - nsect -= 1; - req->buffer += 512; - } - - end_request(req, 1); - } -} - -/* - * Read the table of contents from the drive and set sony_toc_read if - * successful. - */ -static void -sony_get_toc(void) -{ - Byte status[2]; - if (!sony_toc_read) { - /* do not call check_drive_status() from here since it can call this routine */ - if (request_toc_data(status, sony_toc) < 0) - return; - sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); - sony_toc_read = 1; - } -} - - -/* - * Search for a specific track in the table of contents. track is - * passed in bcd format - */ -static int -find_track(int track) -{ - int i; - int num_tracks; - - - num_tracks = bcd_to_int(sony_toc->last_track_num) - - bcd_to_int(sony_toc->first_track_num) + 1; - for (i = 0; i < num_tracks; i++) { - if (sony_toc->tracks[i].track == track) { - return i; - } - } - - return -1; -} - -/* - * Read the subcode and put it int last_sony_subcode for future use. - */ -static int -read_subcode(void) -{ - Byte cmd = SONY535_REQUEST_SUB_Q_DATA; - Byte status[2]; - int dsc_status; - - if (check_drive_status() != 0) - return -EIO; - - if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode, - sizeof(struct s535_sony_subcode), 1)) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n", - status[0], dsc_status); - return -EIO; - } - return 0; -} - - -/* - * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If - * the drive is playing, the subchannel needs to be read (since it would be - * changing). If the drive is paused or completed, the subcode information has - * already been stored, just use that. The ioctl call wants things in decimal - * (not BCD), so all the conversions are done. - */ -static int -sony_get_subchnl_info(void __user *arg) -{ - struct cdrom_subchnl schi; - - /* Get attention stuff */ - if (check_drive_status() != 0) - return -EIO; - - sony_get_toc(); - if (!sony_toc_read) { - return -EIO; - } - if (copy_from_user(&schi, arg, sizeof schi)) - return -EFAULT; - - switch (sony_audio_status) { - case CDROM_AUDIO_PLAY: - if (read_subcode() < 0) { - return -EIO; - } - break; - - case CDROM_AUDIO_PAUSED: - case CDROM_AUDIO_COMPLETED: - break; - - case CDROM_AUDIO_NO_STATUS: - schi.cdsc_audiostatus = sony_audio_status; - if (copy_to_user(arg, &schi, sizeof schi)) - return -EFAULT; - return 0; - break; - - case CDROM_AUDIO_INVALID: - case CDROM_AUDIO_ERROR: - default: - return -EIO; - } - - schi.cdsc_audiostatus = sony_audio_status; - schi.cdsc_adr = last_sony_subcode->address; - schi.cdsc_ctrl = last_sony_subcode->control; - schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); - schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); - if (schi.cdsc_format == CDROM_MSF) { - schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); - schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); - schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); - - schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); - schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); - schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); - } else if (schi.cdsc_format == CDROM_LBA) { - schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); - schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); - } - return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; -} - - -/* - * The big ugly ioctl handler. - */ -static int -cdu_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg) -{ - Byte status[2]; - Byte cmd_buff[10], params[10]; - int i; - int dsc_status; - void __user *argp = (void __user *)arg; - - if (check_drive_status() != 0) - return -EIO; - - switch (cmd) { - case CDROMSTART: /* Spin up the drive */ - if (spin_up_drive(status) < 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n", - status[0]); - return -EIO; - } - return 0; - break; - - case CDROMSTOP: /* Spin down the drive */ - cmd_buff[0] = SONY535_HOLD; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - - /* - * Spin the drive down, ignoring the error if the disk was - * already not spinning. - */ - sony_audio_status = CDROM_AUDIO_NO_STATUS; - cmd_buff[0] = SONY535_SPIN_DOWN; - dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) || - ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n", - status[0]); - return -EIO; - } - return 0; - break; - - case CDROMPAUSE: /* Pause the drive */ - cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */ - if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n", - status[0]); - return -EIO; - } - /* Get the current position and save it for resuming */ - if (read_subcode() < 0) { - return -EIO; - } - cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; - cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; - cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; - sony_audio_status = CDROM_AUDIO_PAUSED; - return 0; - break; - - case CDROMRESUME: /* Start the drive after being paused */ - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - if (sony_audio_status != CDROM_AUDIO_PAUSED) { - return -EINVAL; - } - spin_up_drive(status); - - /* Start the drive at the saved position. */ - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - cmd_buff[2] = cur_pos_msf[0]; - cmd_buff[3] = cur_pos_msf[1]; - cmd_buff[4] = cur_pos_msf[2]; - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - cmd_buff[7] = final_pos_msf[0]; - cmd_buff[8] = final_pos_msf[1]; - cmd_buff[9] = final_pos_msf[2]; - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n", - status[0]); - return -EIO; - } - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - break; - - case CDROMPLAYMSF: /* Play starting at the given MSF address. */ - if (copy_from_user(params, argp, 6)) - return -EFAULT; - spin_up_drive(status); - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - /* The parameters are given in int, must be converted */ - for (i = 0; i < 3; i++) { - cmd_buff[2 + i] = int_to_bcd(params[i]); - cmd_buff[7 + i] = int_to_bcd(params[i + 3]); - } - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - /* cmd_buff[2-4] are filled in for loop above */ - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - /* cmd_buff[7-9] are filled in for loop above */ - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n", - status[0]); - return -EIO; - } - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = cmd_buff[7]; - final_pos_msf[1] = cmd_buff[8]; - final_pos_msf[2] = cmd_buff[9]; - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - break; - - case CDROMREADTOCHDR: /* Read the table of contents header */ - { - struct cdrom_tochdr __user *hdr = argp; - struct cdrom_tochdr loc_hdr; - - sony_get_toc(); - if (!sony_toc_read) - return -EIO; - loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); - loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); - if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) - return -EFAULT; - } - return 0; - break; - - case CDROMREADTOCENTRY: /* Read a given table of contents entry */ - { - struct cdrom_tocentry __user *entry = argp; - struct cdrom_tocentry loc_entry; - int track_idx; - Byte *msf_val = NULL; - - sony_get_toc(); - if (!sony_toc_read) { - return -EIO; - } - - if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) - return -EFAULT; - - /* Lead out is handled separately since it is special. */ - if (loc_entry.cdte_track == CDROM_LEADOUT) { - loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ; - loc_entry.cdte_ctrl = sony_toc->control2; - msf_val = sony_toc->lead_out_start_msf; - } else { - track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); - if (track_idx < 0) - return -EINVAL; - loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ; - loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; - msf_val = sony_toc->tracks[track_idx].track_start_msf; - } - - /* Logical buffer address or MSF format requested? */ - if (loc_entry.cdte_format == CDROM_LBA) { - loc_entry.cdte_addr.lba = msf_to_log(msf_val); - } else if (loc_entry.cdte_format == CDROM_MSF) { - loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); - loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1)); - loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2)); - } - if (copy_to_user(entry, &loc_entry, sizeof *entry)) - return -EFAULT; - } - return 0; - break; - - case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - { - struct cdrom_ti ti; - int track_idx; - - sony_get_toc(); - if (!sony_toc_read) - return -EIO; - - if (copy_from_user(&ti, argp, sizeof ti)) - return -EFAULT; - if ((ti.cdti_trk0 < sony_toc->first_track_num) - || (sony_toc->last_track_num < ti.cdti_trk0) - || (ti.cdti_trk1 < ti.cdti_trk0)) { - return -EINVAL; - } - track_idx = find_track(int_to_bcd(ti.cdti_trk0)); - if (track_idx < 0) - return -EINVAL; - params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; - params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; - params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; - /* - * If we want to stop after the last track, use the lead-out - * MSF to do that. - */ - if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) { - log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1, - &(params[4])); - } else { - track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1)); - if (track_idx < 0) - return -EINVAL; - log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1, - &(params[4])); - } - params[0] = 0x03; - - spin_up_drive(status); - - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - /* Start the drive at the saved position. */ - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - cmd_buff[2] = params[1]; - cmd_buff[3] = params[2]; - cmd_buff[4] = params[3]; - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - cmd_buff[7] = params[4]; - cmd_buff[8] = params[5]; - cmd_buff[9] = params[6]; - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n", - status[0]); - printk("... Params: %x %x %x %x %x %x %x\n", - params[0], params[1], params[2], - params[3], params[4], params[5], params[6]); - return -EIO; - } - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = params[4]; - final_pos_msf[1] = params[5]; - final_pos_msf[2] = params[6]; - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - } - - case CDROMSUBCHNL: /* Get subchannel info */ - return sony_get_subchnl_info(argp); - - case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ - { - struct cdrom_volctrl volctrl; - - if (copy_from_user(&volctrl, argp, sizeof volctrl)) - return -EFAULT; - cmd_buff[0] = SONY535_SET_VOLUME; - cmd_buff[1] = volctrl.channel0; - cmd_buff[2] = volctrl.channel1; - if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n", - status[0]); - return -EIO; - } - } - return 0; - - case CDROMEJECT: /* Eject the drive */ - cmd_buff[0] = SONY535_STOP; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - cmd_buff[0] = SONY535_SPIN_DOWN; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - - sony_audio_status = CDROM_AUDIO_INVALID; - cmd_buff[0] = SONY535_EJECT_CADDY; - if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n", - status[0]); - return -EIO; - } - return 0; - break; - - default: - return -EINVAL; - } -} - - -/* - * Open the drive for operations. Spin the drive up and read the table of - * contents if these have not already been done. - */ -static int -cdu_open(struct inode *inode, - struct file *filp) -{ - Byte status[2], cmd_buff[2]; - - if (sony_inuse) - return -EBUSY; - if (check_drive_status() != 0) - return -EIO; - sony_inuse = 1; - - if (spin_up_drive(status) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n", - status[0]); - sony_inuse = 0; - return -EIO; - } - sony_get_toc(); - if (!sony_toc_read) { - cmd_buff[0] = SONY535_SPIN_DOWN; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - sony_inuse = 0; - return -EIO; - } - check_disk_change(inode->i_bdev); - sony_usage++; - -#ifdef LOCK_DOORS - /* disable the eject button while mounted */ - cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); -#endif - - return 0; -} - - -/* - * Close the drive. Spin it down if no task is using it. The spin - * down will fail if playing audio, so audio play is OK. - */ -static int -cdu_release(struct inode *inode, - struct file *filp) -{ - Byte status[2], cmd_no; - - sony_inuse = 0; - - if (0 < sony_usage) { - sony_usage--; - } - if (sony_usage == 0) { - check_drive_status(); - - if (sony_audio_status != CDROM_AUDIO_PLAY) { - cmd_no = SONY535_SPIN_DOWN; - do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); - } -#ifdef LOCK_DOORS - /* enable the eject button after umount */ - cmd_no = SONY535_ENABLE_EJECT_BUTTON; - do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); -#endif - } - return 0; -} - -static struct block_device_operations cdu_fops = -{ - .owner = THIS_MODULE, - .open = cdu_open, - .release = cdu_release, - .ioctl = cdu_ioctl, - .media_changed = cdu535_check_media_change, -}; - -static struct gendisk *cdu_disk; - -/* - * Initialize the driver. - */ -static int __init sony535_init(void) -{ - struct s535_sony_drive_config drive_config; - Byte cmd_buff[3]; - Byte ret_buff[2]; - Byte status[2]; - unsigned long snap; - int got_result = 0; - int tmp_irq; - int i; - int err; - - /* Setting the base I/O address to 0 will disable it. */ - if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) - return 0; - - /* Set up all the register locations */ - result_reg = sony535_cd_base_io; - command_reg = sony535_cd_base_io; - data_reg = sony535_cd_base_io + 1; - read_status_reg = sony535_cd_base_io + 2; - select_unit_reg = sony535_cd_base_io + 3; - -#ifndef USE_IRQ - sony535_irq_used = 0; /* polling only until this is ready... */ -#endif - /* we need to poll until things get initialized */ - tmp_irq = sony535_irq_used; - sony535_irq_used = 0; - -#if DEBUG > 0 - printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", - sony535_cd_base_io); -#endif - /* look for the CD-ROM, follows the procedure in the DOS driver */ - inb(select_unit_reg); - /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ - schedule_timeout_interruptible((HZ+17)*40/18); - inb(result_reg); - - outb(0, read_status_reg); /* does a reset? */ - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - select_unit(0); - if (inb(result_reg) != 0xff) { - got_result = 1; - break; - } - sony_sleep(); - } - - if (!got_result || check_drive_status() == TIME_OUT) - goto Enodev; - - /* CD-ROM drive responded -- get the drive configuration */ - cmd_buff[0] = SONY535_INQUIRY; - if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) - goto Enodev; - - /* was able to get the configuration, - * set drive mode as rest of init - */ -#if DEBUG > 0 - /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ - if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) - printk(CDU535_MESSAGE_NAME - "Inquiry command returned status = 0x%x\n", status[0]); -#endif - /* now ready to use interrupts, if available */ - sony535_irq_used = tmp_irq; - - /* A negative sony535_irq_used will attempt an autoirq. */ - if (sony535_irq_used < 0) { - unsigned long irq_mask, delay; - - irq_mask = probe_irq_on(); - enable_interrupts(); - outb(0, read_status_reg); /* does a reset? */ - delay = jiffies + HZ/10; - while (time_before(jiffies, delay)) ; - - sony535_irq_used = probe_irq_off(irq_mask); - disable_interrupts(); - } - if (sony535_irq_used > 0) { - if (request_irq(sony535_irq_used, cdu535_interrupt, - IRQF_DISABLED, CDU535_HANDLE, NULL)) { - printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME - " driver; polling instead.\n", sony535_irq_used); - sony535_irq_used = 0; - } - } - cmd_buff[0] = SONY535_SET_DRIVE_MODE; - cmd_buff[1] = 0x0; /* default audio */ - if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) - goto Enodev_irq; - - /* set the drive mode successful, we are set! */ - sony_buffer_size = SONY535_BUFFER_SIZE; - sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; - - printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", - drive_config.vendor_id, - drive_config.product_id, - drive_config.product_rev_level); - printk(" base address %03X, ", sony535_cd_base_io); - if (tmp_irq > 0) - printk("IRQ%d, ", tmp_irq); - printk("using %d byte buffer\n", sony_buffer_size); - - if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { - err = -EIO; - goto out1; - } - sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); - if (!sonycd535_queue) { - err = -ENOMEM; - goto out1a; - } - - blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); - sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); - err = -ENOMEM; - if (!sony_toc) - goto out2; - last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); - if (!last_sony_subcode) - goto out3; - sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); - if (!sony_buffer) - goto out4; - for (i = 0; i < sony_buffer_sectors; i++) { - sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); - if (!sony_buffer[i]) { - while (--i>=0) - kfree(sony_buffer[i]); - goto out5; - } - } - initialized = 1; - - cdu_disk = alloc_disk(1); - if (!cdu_disk) - goto out6; - cdu_disk->major = MAJOR_NR; - cdu_disk->first_minor = 0; - cdu_disk->fops = &cdu_fops; - sprintf(cdu_disk->disk_name, "cdu"); - - if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { - printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", - sony535_cd_base_io); - goto out7; - } - cdu_disk->queue = sonycd535_queue; - add_disk(cdu_disk); - return 0; - -out7: - put_disk(cdu_disk); -out6: - for (i = 0; i < sony_buffer_sectors; i++) - kfree(sony_buffer[i]); -out5: - kfree(sony_buffer); -out4: - kfree(last_sony_subcode); -out3: - kfree(sony_toc); -out2: - blk_cleanup_queue(sonycd535_queue); -out1a: - unregister_blkdev(MAJOR_NR, CDU535_HANDLE); -out1: - if (sony535_irq_used) - free_irq(sony535_irq_used, NULL); - return err; -Enodev_irq: - if (sony535_irq_used) - free_irq(sony535_irq_used, NULL); -Enodev: - printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); - return -EIO; -} - -#ifndef MODULE - -/* - * accept "kernel command line" parameters - * (added by emoenke@gwdg.de) - * - * use: tell LILO: - * sonycd535=0x320 - * - * the address value has to be the existing CDROM port address. - */ -static int __init -sonycd535_setup(char *strings) -{ - int ints[3]; - (void)get_options(strings, ARRAY_SIZE(ints), ints); - /* if IRQ change and default io base desired, - * then call with io base of 0 - */ - if (ints[0] > 0) - if (ints[1] != 0) - sony535_cd_base_io = ints[1]; - if (ints[0] > 1) - sony535_irq_used = ints[2]; - if ((strings != NULL) && (*strings != '\0')) - printk(CDU535_MESSAGE_NAME - ": Warning: Unknown interface type: %s\n", strings); - - return 1; -} - -__setup("sonycd535=", sonycd535_setup); - -#endif /* MODULE */ - -static void __exit -sony535_exit(void) -{ - int i; - - release_region(sony535_cd_base_io, 4); - for (i = 0; i < sony_buffer_sectors; i++) - kfree(sony_buffer[i]); - kfree(sony_buffer); - kfree(last_sony_subcode); - kfree(sony_toc); - del_gendisk(cdu_disk); - put_disk(cdu_disk); - blk_cleanup_queue(sonycd535_queue); - if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) - printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); - else - printk(KERN_INFO CDU535_HANDLE " module released\n"); -} - -module_init(sony535_init); -module_exit(sony535_exit); - - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); |