Commit 41e0feb7 authored by Ondrej Zary's avatar Ondrej Zary Committed by Linus Torvalds

[PATCH] make cdu31a work on at least one system

I've got a Sony CDU33A drive with COR334 controller.  The Linux cdu31a
driver was not updated for 2.6 kernel so it does not work.

Here are patches that try to make the driver working with 2.6
kernel:
  - fix the timeout values in header file
  - Make the driver work in 2.6.X
  - Added workaround to fix hard lockups on eject
  - Fixed door locking problem after mounting empty drive
  - Set double-speed drives to double speed by default
  - Removed all readahead things - not needed anymore

It does work on my system. I also know that it's still broken - it uses 
cli(), MODULE_PARM and it's also not very fast (I _never_ reached full
300KB/s with it, but I know that it's possible in Windows) and probably 
many other things (I'm new to Linux kernel) - so I'm waiting for comments.
parent 69abbfd9
......@@ -65,14 +65,6 @@
* This section describes features beyond the normal audio and CD-ROM
* functions of the drive.
*
* 2048 byte buffer mode
*
* If a disk is mounted with -o block=2048, data is copied straight
* from the drive data port to the buffer. Otherwise, the readahead
* buffer must be involved to hold the other 1K of data when a 1K
* block operation is done. Note that with 2048 byte blocks you
* cannot execute files from the CD.
*
* XA compatibility
*
* The driver should support XA disks for both the CDU31A and CDU33A.
......@@ -147,6 +139,13 @@
* Removed init_module & cleanup_module in favor of
* module_init & module_exit.
* Torben Mathiasen <tmm@image.dk>
*
* 22 October 2004 -- Make the driver work in 2.6.X
* Added workaround to fix hard lockups on eject
* Fixed door locking problem after mounting empty drive
* Set double-speed drives to double speed by default
* Removed all readahead things - not needed anymore
* Ondrej Zary <rainbow@rainbow-software.org>
*/
#include <linux/major.h>
......@@ -179,10 +178,9 @@
#define MAJOR_NR CDU31A_CDROM_MAJOR
#include <linux/blkdev.h>
#define CDU31A_READAHEAD 4 /* 128 sector, 64kB, 32 reads read-ahead */
#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
#define DEBUG 0
#define DEBUG 1
/* Define the following if you have data corruption problems. */
#undef SONY_POLL_EACH_BYTE
......@@ -279,7 +277,6 @@ static struct task_struct *has_cd_task = NULL; /* The task that is currently
NULL if none. */
static int is_double_speed = 0; /* does the drive support double speed ? */
static int is_a_cdu31a = 1; /* Is the drive a CDU31A? */
static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */
......@@ -314,12 +311,8 @@ static int curr_control_reg = 0; /* Current value of the control register */
it will be cleared. */
static char disk_changed;
/* Variable for using the readahead buffer. The readahead buffer
is used for raw sector reads and for blocksizes that are smaller
than 2048 bytes. */
static char readahead_buffer[CD_FRAMESIZE_RAW];
static int readahead_dataleft = 0;
static int readahead_bad = 0;
/* This was readahead_buffer once... Now it's used only for audio reads */
static char audio_buffer[CD_FRAMESIZE_RAW];
/* Used to time a short period to abort an operation after the
drive has been idle for a while. This keeps the light on
......@@ -440,7 +433,6 @@ static inline int is_result_reg_not_empty(void)
static inline void reset_drive(void)
{
curr_control_reg = 0;
readahead_dataleft = 0;
sony_toc_read = 0;
outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg);
}
......@@ -556,82 +548,47 @@ static unsigned char *translate_error(unsigned char err_code)
static unsigned char errbuf[80];
switch (err_code) {
case 0x10:
return "illegal command ";
case 0x11:
return "illegal parameter ";
case 0x20:
return "not loaded ";
case 0x21:
return "no disc ";
case 0x22:
return "not spinning ";
case 0x23:
return "spinning ";
case 0x25:
return "spindle servo ";
case 0x26:
return "focus servo ";
case 0x29:
return "eject mechanism ";
case 0x2a:
return "audio playing ";
case 0x2c:
return "emergency eject ";
case 0x30:
return "focus ";
case 0x31:
return "frame sync ";
case 0x32:
return "subcode address ";
case 0x33:
return "block sync ";
case 0x34:
return "header address ";
case 0x40:
return "illegal track read ";
case 0x41:
return "mode 0 read ";
case 0x42:
return "illegal mode read ";
case 0x43:
return "illegal block size read ";
case 0x44:
return "mode read ";
case 0x45:
return "form read ";
case 0x46:
return "leadout read ";
case 0x47:
return "buffer overrun ";
case 0x53:
return "unrecoverable CIRC ";
case 0x57:
return "unrecoverable LECC ";
case 0x60:
return "no TOC ";
case 0x61:
return "invalid subcode data ";
case 0x63:
return "focus on TOC read ";
case 0x64:
return "frame sync on TOC read ";
case 0x65:
return "TOC data ";
case 0x70:
return "hardware failure ";
case 0x91:
return "leadin ";
case 0x92:
return "leadout ";
case 0x93:
return "data track ";
case 0x10: return "illegal command ";
case 0x11: return "illegal parameter ";
case 0x20: return "not loaded ";
case 0x21: return "no disc ";
case 0x22: return "not spinning ";
case 0x23: return "spinning ";
case 0x25: return "spindle servo ";
case 0x26: return "focus servo ";
case 0x29: return "eject mechanism ";
case 0x2a: return "audio playing ";
case 0x2c: return "emergency eject ";
case 0x30: return "focus ";
case 0x31: return "frame sync ";
case 0x32: return "subcode address ";
case 0x33: return "block sync ";
case 0x34: return "header address ";
case 0x40: return "illegal track read ";
case 0x41: return "mode 0 read ";
case 0x42: return "illegal mode read ";
case 0x43: return "illegal block size read ";
case 0x44: return "mode read ";
case 0x45: return "form read ";
case 0x46: return "leadout read ";
case 0x47: return "buffer overrun ";
case 0x53: return "unrecoverable CIRC ";
case 0x57: return "unrecoverable LECC ";
case 0x60: return "no TOC ";
case 0x61: return "invalid subcode data ";
case 0x63: return "focus on TOC read ";
case 0x64: return "frame sync on TOC read ";
case 0x65: return "TOC data ";
case 0x70: return "hardware failure ";
case 0x91: return "leadin ";
case 0x92: return "leadout ";
case 0x93: return "data track ";
}
sprintf(errbuf, "unknown 0x%02x ", err_code);
return errbuf;
......@@ -696,8 +653,7 @@ static int scd_select_speed(struct cdrom_device_info *cdi, int speed)
*/
static int scd_lock_door(struct cdrom_device_info *cdi, int lock)
{
if (lock == 0 && sony_usage == 1) {
/* Unlock the door, only if nobody is using the drive */
if (lock == 0) {
is_auto_eject = 1;
} else {
is_auto_eject = 0;
......@@ -1143,10 +1099,9 @@ static void size_to_buf(unsigned int size, unsigned char *buf)
operation if the requested sector is not the next one from the
drive. */
static int
start_request(unsigned int sector, unsigned int nsect, int read_nsect_only)
start_request(unsigned int sector, unsigned int nsect)
{
unsigned char params[6];
unsigned int read_size;
unsigned long retry_count;
......@@ -1154,22 +1109,7 @@ start_request(unsigned int sector, unsigned int nsect, int read_nsect_only)
printk("Entering start_request\n");
#endif
log_to_msf(sector, params);
/* If requested, read exactly what was asked. */
if (read_nsect_only) {
read_size = nsect;
}
/*
* 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.
*/
else if ((sector + nsect) >= sony_toc.lead_out_start_lba) {
read_size = sony_toc.lead_out_start_lba - sector;
}
/* Read the full readahead amount. */
else {
read_size = CDU31A_READAHEAD / 4;
}
size_to_buf(read_size, &params[3]);
size_to_buf(nsect, &params[3]);
/*
* Clear any outstanding attentions and wait for the drive to
......@@ -1198,10 +1138,8 @@ start_request(unsigned int sector, unsigned int nsect, int read_nsect_only)
write_params(params, 6);
write_cmd(SONY_READ_BLKERR_STAT_CMD);
sony_blocks_left = read_size * 4;
sony_blocks_left = nsect * 4;
sony_next_block = sector * 4;
readahead_dataleft = 0;
readahead_bad = 0;
#if DEBUG
printk("Leaving start_request at %d\n", __LINE__);
#endif
......@@ -1212,8 +1150,7 @@ start_request(unsigned int sector, unsigned int nsect, int read_nsect_only)
#endif
}
/* Abort a pending read operation. Clear all the drive status and
readahead variables. */
/* Abort a pending read operation. Clear all the drive status variables. */
static void abort_read(void)
{
unsigned char result_reg[2];
......@@ -1238,8 +1175,6 @@ static void abort_read(void)
}
sony_blocks_left = 0;
readahead_dataleft = 0;
readahead_bad = 0;
}
/* Called when the timer times out. This will abort the
......@@ -1264,8 +1199,6 @@ static void handle_abort_timeout(unsigned long data)
write_cmd(SONY_ABORT_CMD);
sony_blocks_left = 0;
readahead_dataleft = 0;
readahead_bad = 0;
abort_read_started = 1;
}
restore_flags(flags);
......@@ -1274,60 +1207,30 @@ static void handle_abort_timeout(unsigned long data)
#endif
}
/* Actually get data and status from the drive. */
/* Actually get one sector of data from the drive. */
static void
input_data(char *buffer,
unsigned int bytesleft,
unsigned int nblocks, unsigned int offset, unsigned int skip)
input_data_sector(char *buffer)
{
int i;
volatile unsigned char val;
#if DEBUG
printk("Entering input_data\n");
printk("Entering input_data_sector\n");
#endif
/* If an XA disk on a CDU31A, skip the first 12 bytes of data from
the disk. The real data is after that. */
if (sony_xa_mode) {
for (i = 0; i < CD_XA_HEAD; i++) {
val = read_data_register();
}
}
the disk. The real data is after that. We can use audio_buffer. */
if (sony_xa_mode)
insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD);
clear_data_ready();
if (bytesleft == 2048) { /* 2048 byte direct buffer transfer */
insb(sony_cd_read_reg, buffer, 2048);
readahead_dataleft = 0;
} else {
/* If the input read did not align with the beginning of the block,
skip the necessary bytes. */
if (skip != 0) {
insb(sony_cd_read_reg, readahead_buffer, skip);
}
/* Get the data into the buffer. */
insb(sony_cd_read_reg, &buffer[offset], bytesleft);
/* Get the rest of the data into the readahead buffer at the
proper location. */
readahead_dataleft = (2048 - skip) - bytesleft;
insb(sony_cd_read_reg,
readahead_buffer + bytesleft, readahead_dataleft);
}
sony_blocks_left -= nblocks;
sony_next_block += nblocks;
/* If an XA disk, we have to clear out the rest of the unused
error correction data. */
if (sony_xa_mode) {
for (i = 0; i < CD_XA_TAIL; i++) {
val = read_data_register();
}
}
error correction data. We can use audio_buffer for that. */
if (sony_xa_mode)
insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL);
#if DEBUG
printk("Leaving input_data at %d\n", __LINE__);
printk("Leaving input_data_sector\n");
#endif
}
......@@ -1339,10 +1242,6 @@ read_data_block(char *buffer,
unsigned char res_reg[], int *res_size)
{
unsigned long retry_count;
unsigned int bytesleft;
unsigned int offset;
unsigned int skip;
#if DEBUG
printk("Entering read_data_block\n");
......@@ -1351,67 +1250,6 @@ read_data_block(char *buffer,
res_reg[0] = 0;
res_reg[1] = 0;
*res_size = 0;
bytesleft = nblocks * 512;
offset = 0;
/* If the data in the read-ahead does not match the block offset,
then fix things up. */
if (((block % 4) * 512) != ((2048 - readahead_dataleft) % 2048)) {
sony_next_block += block % 4;
sony_blocks_left -= block % 4;
skip = (block % 4) * 512;
} else {
skip = 0;
}
/* We have readahead data in the buffer, get that first before we
decide if a read is necessary. */
if (readahead_dataleft != 0) {
if (bytesleft > readahead_dataleft) {
/* The readahead will not fill the requested buffer, but
get the data out of the readahead into the buffer. */
memcpy(buffer,
readahead_buffer + (2048 -
readahead_dataleft),
readahead_dataleft);
bytesleft -= readahead_dataleft;
offset += readahead_dataleft;
readahead_dataleft = 0;
} else {
/* The readahead will fill the whole buffer, get the data
and return. */
memcpy(buffer,
readahead_buffer + (2048 -
readahead_dataleft),
bytesleft);
readahead_dataleft -= bytesleft;
bytesleft = 0;
sony_blocks_left -= nblocks;
sony_next_block += nblocks;
/* If the data in the readahead is bad, return an error so the
driver will abort the buffer. */
if (readahead_bad) {
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
*res_size = 2;
}
if (readahead_dataleft == 0) {
readahead_bad = 0;
}
/* Final transfer is done for read command, get final result. */
if (sony_blocks_left == 0) {
get_result(res_reg, res_size);
}
#if DEBUG
printk("Leaving read_data_block at %d\n",
__LINE__);
#endif
return;
}
}
/* Wait for the drive to tell us we have something */
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
......@@ -1442,7 +1280,9 @@ read_data_block(char *buffer,
abort_read();
}
} else {
input_data(buffer, bytesleft, nblocks, offset, skip);
input_data_sector(buffer);
sony_blocks_left -= nblocks;
sony_next_block += nblocks;
/* Wait for the status from the drive. */
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
......@@ -1473,16 +1313,7 @@ read_data_block(char *buffer,
SONY_NO_LECC_ERR_BLK_STAT)
|| (res_reg[0] ==
SONY_RECOV_LECC_ERR_BLK_STAT)) {
/* The data was successful, but if data was read from
the readahead and it was bad, set the whole
buffer as bad. */
if (readahead_bad) {
readahead_bad = 0;
res_reg[0] = 0x20;
res_reg[1] =
SONY_BAD_DATA_ERR;
*res_size = 2;
}
/* nothing here */
} else {
printk
("CDU31A: Data block error: 0x%x\n",
......@@ -1490,12 +1321,6 @@ read_data_block(char *buffer,
res_reg[0] = 0x20;
res_reg[1] = SONY_BAD_DATA_ERR;
*res_size = 2;
/* Data is in the readahead buffer but an error was returned.
Make sure future requests don't use the data. */
if (bytesleft != 2048) {
readahead_bad = 1;
}
}
/* Final transfer is done for read command, get final result. */
......@@ -1531,11 +1356,9 @@ read_data_block(char *buffer,
static void do_cdu31a_request(request_queue_t * q)
{
struct request *req;
int block;
int nblock;
int block, nblock, num_retries;
unsigned char res_reg[12];
unsigned int res_size;
int num_retries;
unsigned long flags;
......@@ -1591,7 +1414,10 @@ static void do_cdu31a_request(request_queue_t * q)
block = req->sector;
nblock = req->nr_sectors;
#if DEBUG
printk("CDU31A: request at block %d, length %d blocks\n",
block, nblock);
#endif
if (!sony_toc_read) {
printk("CDU31A: TOC not read\n");
end_request(req, 0);
......@@ -1611,17 +1437,14 @@ static void do_cdu31a_request(request_queue_t * q)
* If the block address is invalid or the request goes beyond the end of
* the media, return an error.
*/
if ((block / 4) >= sony_toc.lead_out_start_lba) {
printk("CDU31A: Request past end of media\n");
end_request(req, 0);
continue;
}
if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) {
printk("CDU31A: Request past end of media\n");
end_request(req, 0);
continue;
}
if (nblock > 4)
nblock = 4;
num_retries = 0;
try_read_again:
......@@ -1636,7 +1459,7 @@ static void do_cdu31a_request(request_queue_t * q)
/* If no data is left to be read from the drive, start the
next request. */
if (sony_blocks_left == 0) {
if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) {
if (start_request(block / 4, nblock / 4)) {
end_request(req, 0);
continue;
}
......@@ -1655,7 +1478,7 @@ static void do_cdu31a_request(request_queue_t * q)
end_request(req, 0);
continue;
}
if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) {
if (start_request(block / 4, nblock / 4)) {
printk("CDU31a: start request failed\n");
end_request(req, 0);
continue;
......@@ -1665,7 +1488,12 @@ static void do_cdu31a_request(request_queue_t * q)
read_data_block(req->buffer, block, nblock, res_reg, &res_size);
if (res_reg[0] != 0x20) {
end_request(req, 1);
if (!end_that_request_first(req, 1, nblock)) {
spin_lock_irq(q->queue_lock);
blkdev_dequeue_request(req);
end_that_request_last(req);
spin_unlock_irq(q->queue_lock);
}
continue;
}
......@@ -1774,7 +1602,7 @@ static void sony_get_toc(void)
/* This seems to slow things down enough to make it work. This
* appears to be a problem in do_sony_cd_cmd. This printk seems
* to address the symptoms... -Erik */
#if 1
#if DEBUG
printk("cdu31a: Trying session %d\n", session);
#endif
parms[0] = session;
......@@ -2529,8 +2357,7 @@ static int read_audio(struct cdrom_read_audio *ra)
return. */
retval = 0;
/* start_request clears out any readahead data, so it should be safe. */
if (start_request(ra->addr.lba, ra->nframes, 1)) {
if (start_request(ra->addr.lba, ra->nframes)) {
retval = -EIO;
goto exit_read_audio;
}
......@@ -2538,7 +2365,7 @@ static int read_audio(struct cdrom_read_audio *ra)
/* For every requested frame. */
cframe = 0;
while (cframe < ra->nframes) {
read_audio_data(readahead_buffer, res_reg, &res_size);
read_audio_data(audio_buffer, res_reg, &res_size);
if ((res_reg[0] & 0xf0) == 0x20) {
if (res_reg[1] == SONY_BAD_DATA_ERR) {
printk
......@@ -2567,7 +2394,7 @@ static int read_audio(struct cdrom_read_audio *ra)
/* Restart the request on the current frame. */
if (start_request
(ra->addr.lba + cframe,
ra->nframes - cframe, 1)) {
ra->nframes - cframe)) {
retval = -EIO;
goto exit_read_audio;
}
......@@ -2575,7 +2402,7 @@ static int read_audio(struct cdrom_read_audio *ra)
/* Don't go back to the top because don't want to get into
and infinite loop. A lot of code gets duplicated, but
that's no big deal, I don't guess. */
read_audio_data(readahead_buffer, res_reg,
read_audio_data(audio_buffer, res_reg,
&res_size);
if ((res_reg[0] & 0xf0) == 0x20) {
if (res_reg[1] ==
......@@ -2596,7 +2423,7 @@ static int read_audio(struct cdrom_read_audio *ra)
} else if (copy_to_user(ra->buf +
(CD_FRAMESIZE_RAW
* cframe),
readahead_buffer,
audio_buffer,
CD_FRAMESIZE_RAW)) {
retval = -EFAULT;
goto exit_read_audio;
......@@ -2610,7 +2437,7 @@ static int read_audio(struct cdrom_read_audio *ra)
goto exit_read_audio;
}
} else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe),
(char *)readahead_buffer,
(char *)audio_buffer,
CD_FRAMESIZE_RAW)) {
retval = -EFAULT;
goto exit_read_audio;
......@@ -3061,12 +2888,18 @@ static int scd_spinup(void)
* Open the drive for operations. Spin the drive up and read the table of
* contents if these have not already been done.
*/
static int scd_open(struct cdrom_device_info *cdi, int openmode)
static int scd_open(struct cdrom_device_info *cdi, int purpose)
{
unsigned char res_reg[12];
unsigned int res_size;
unsigned char params[2];
if (purpose == 1) {
/* Open for IOCTLs only - no media check */
sony_usage++;
return 0;
}
if (sony_usage == 0) {
if (scd_spinup() != 0)
return -EIO;
......@@ -3151,8 +2984,7 @@ static struct cdrom_device_ops scd_dops = {
.dev_ioctl = scd_dev_ioctl,
.capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK |
CDC_SELECT_SPEED | CDC_MULTI_SESSION |
CDC_MULTI_SESSION | CDC_MCN |
CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS,
.n_minors = 1,
};
......@@ -3177,7 +3009,19 @@ static int scd_block_release(struct inode *inode, struct file *file)
static int scd_block_ioctl(struct inode *inode, struct file *file,
unsigned cmd, unsigned long arg)
{
/* The eject and close commands should be handled by Uniform CD-ROM
* driver - but I always got hard lockup instead of eject
* until I put this here.
*/
switch (cmd) {
case CDROMEJECT:
scd_lock_door(&scd_info, 0);
return scd_tray_move(&scd_info, 1);
case CDROMCLOSETRAY:
return scd_tray_move(&scd_info, 0);
default:
return cdrom_ioctl(file, &scd_info, inode, cmd, arg);
}
}
static int scd_block_media_changed(struct gendisk *disk)
......@@ -3372,6 +3216,7 @@ int __init cdu31a_init(void)
tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */
cdu31a_irq = 0;
sony_speed = is_double_speed; /* Set 2X drives to 2X by default */
set_drive_params(sony_speed);
cdu31a_irq = tmp_irq;
......@@ -3417,13 +3262,12 @@ int __init cdu31a_init(void)
strcat(msg, buf);
}
strcat(msg, "\n");
is_a_cdu31a =
strcmp("CD-ROM CDU31A", drive_config.product_id) == 0;
printk("%s",msg);
cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock);
if (!cdu31a_queue)
goto errout0;
blk_queue_hardsect_size(cdu31a_queue, 2048);
init_timer(&cdu31a_abort_timer);
cdu31a_abort_timer.function = handle_abort_timeout;
......
......@@ -72,10 +72,10 @@
from drive (in 1/100th's
of seconds). */
#define SONY_JIFFIES_TIMEOUT 1000 /* Maximum number of times the
#define SONY_JIFFIES_TIMEOUT (10*HZ) /* Maximum number of times the
drive will wait/try for an
operation */
#define SONY_RESET_TIMEOUT 100 /* Maximum number of times the
#define SONY_RESET_TIMEOUT HZ /* Maximum number of times the
drive will wait/try a reset
operation */
#define SONY_READY_RETRIES 20000 /* How many times to retry a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment