📄 cdu31a.c
字号:
{
outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg);
}
static inline void clear_data_ready(void)
{
outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT,
sony_cd_control_reg);
}
static inline void clear_param_reg(void)
{
outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg);
}
static inline unsigned char read_status_register(void)
{
return (inb(sony_cd_status_reg));
}
static inline unsigned char read_result_register(void)
{
return (inb(sony_cd_result_reg));
}
static inline unsigned char read_data_register(void)
{
return (inb(sony_cd_read_reg));
}
static inline void write_param(unsigned char param)
{
outb(param, sony_cd_param_reg);
}
static inline void write_cmd(unsigned char cmd)
{
outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT,
sony_cd_control_reg);
outb(cmd, sony_cd_cmd_reg);
}
static void cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char val;
if (abort_read_started) {
/* We might be waiting for an abort to finish. Don't
disable interrupts yet, though, because we handle
this one here. */
/* Clear out the result registers. */
while (is_result_reg_not_empty()) {
val = read_result_register();
}
clear_data_ready();
clear_result_ready();
/* Clear out the data */
while (is_data_requested()) {
val = read_data_register();
}
abort_read_started = 0;
/* If something was waiting, wake it up now. */
if (waitqueue_active(&cdu31a_irq_wait)) {
disable_interrupts();
wake_up(&cdu31a_irq_wait);
}
} else if (waitqueue_active(&cdu31a_irq_wait)) {
disable_interrupts();
wake_up(&cdu31a_irq_wait);
} else {
disable_interrupts();
printk
("CDU31A: Got an interrupt but nothing was waiting\n");
}
}
/*
* give more verbose error messages
*/
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 ";
}
sprintf(errbuf, "unknown 0x%02x ", err_code);
return errbuf;
}
/*
* Set the drive parameters so the drive will auto-spin-up when a
* disk is inserted.
*/
static void set_drive_params(int want_doublespeed)
{
unsigned char res_reg[12];
unsigned int res_size;
unsigned char params[3];
params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME;
params[1] = 0x00; /* Never spin down the drive. */
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
printk(" Unable to set spin-down time: 0x%2.2x\n",
res_reg[1]);
}
params[0] = SONY_SD_MECH_CONTROL;
params[1] = SONY_AUTO_SPIN_UP_BIT; /* Set auto spin up */
if (is_auto_eject)
params[1] |= SONY_AUTO_EJECT_BIT;
if (is_double_speed && want_doublespeed) {
params[1] |= SONY_DOUBLE_SPEED_BIT; /* Set the drive to double speed if
possible */
}
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params, 2, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
printk(" Unable to set mechanical parameters: 0x%2.2x\n",
res_reg[1]);
}
}
/*
* Uniform cdrom interface function
* select reading speed for data access
*/
static int scd_select_speed(struct cdrom_device_info *cdi, int speed)
{
if (speed == 0)
sony_speed = 1;
else
sony_speed = speed - 1;
set_drive_params(sony_speed);
return 0;
}
/*
* Uniform cdrom interface function
* lock or unlock eject button
*/
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 */
is_auto_eject = 1;
} else {
is_auto_eject = 0;
}
set_drive_params(sony_speed);
return 0;
}
/*
* This code will reset the drive and attempt to restore sane parameters.
*/
static void restart_on_error(void)
{
unsigned char res_reg[12];
unsigned int res_size;
unsigned int retry_count;
printk("cdu31a: Resetting drive on error\n");
reset_drive();
retry_count = jiffies + SONY_RESET_TIMEOUT;
while (time_before(jiffies, retry_count) && (!is_attention())) {
sony_sleep();
}
set_drive_params(sony_speed);
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {
printk("cdu31a: Unable to spin up drive: 0x%2.2x\n",
res_reg[1]);
}
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(2 * HZ);
sony_get_toc();
}
/*
* This routine writes data to the parameter register. Since this should
* happen fairly fast, it is polled with no OS waits between.
*/
static int write_params(unsigned char *params, int num_params)
{
unsigned int retry_count;
retry_count = SONY_READY_RETRIES;
while ((retry_count > 0) && (!is_param_write_rdy())) {
retry_count--;
}
if (!is_param_write_rdy()) {
return -EIO;
}
while (num_params > 0) {
write_param(*params);
params++;
num_params--;
}
return 0;
}
/*
* The following reads data from the command result register. It is a
* fairly complex routine, all status info flows back through this
* interface. The algorithm is stolen directly from the flowcharts in
* the drive manual.
*/
static void
get_result(unsigned char *result_buffer, unsigned int *result_size)
{
unsigned char a, b;
int i;
unsigned int retry_count;
while (handle_sony_cd_attention());
/* Wait for the result data to be ready */
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
while (time_before(jiffies, retry_count)
&& (is_busy() || (!(is_result_ready())))) {
sony_sleep();
while (handle_sony_cd_attention());
}
if (is_busy() || (!(is_result_ready()))) {
#if DEBUG
printk("CDU31A timeout out %d\n", __LINE__);
#endif
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
return;
}
/*
* Get the first two bytes. This determines what else needs
* to be done.
*/
clear_result_ready();
a = read_result_register();
*result_buffer = a;
result_buffer++;
/* Check for block error status result. */
if ((a & 0xf0) == 0x50) {
*result_size = 1;
return;
}
b = read_result_register();
*result_buffer = b;
result_buffer++;
*result_size = 2;
/*
* 0x20 means an error occurred. Byte 2 will have the error code.
* Otherwise, the command succeeded, byte 2 will have the count of
* how many more status bytes are coming.
*
* The result register can be read 10 bytes at a time, a wait for
* result ready to be asserted must be done between every 10 bytes.
*/
if ((a & 0xf0) != 0x20) {
if (b > 8) {
for (i = 0; i < 8; i++) {
*result_buffer = read_result_register();
result_buffer++;
(*result_size)++;
}
b = b - 8;
while (b > 10) {
retry_count = SONY_READY_RETRIES;
while ((retry_count > 0)
&& (!is_result_ready())) {
retry_count--;
}
if (!is_result_ready()) {
#if DEBUG
printk("CDU31A timeout out %d\n",
__LINE__);
#endif
result_buffer[0] = 0x20;
result_buffer[1] =
SONY_TIMEOUT_OP_ERR;
*result_size = 2;
return;
}
clear_result_ready();
for (i = 0; i < 10; i++) {
*result_buffer =
read_result_register();
result_buffer++;
(*result_size)++;
}
b = b - 10;
}
if (b > 0) {
retry_count = SONY_READY_RETRIES;
while ((retry_count > 0)
&& (!is_result_ready())) {
retry_count--;
}
if (!is_result_ready()) {
#if DEBUG
printk("CDU31A timeout out %d\n",
__LINE__);
#endif
result_buffer[0] = 0x20;
result_buffer[1] =
SONY_TIMEOUT_OP_ERR;
*result_size = 2;
return;
}
}
}
while (b > 0) {
*result_buffer = read_result_register();
result_buffer++;
(*result_size)++;
b--;
}
}
}
/*
* Do a command that does not involve data transfer. This routine must
* be re-entrant from the same task to support being called from the
* data operation code when an error occurs.
*/
static void
do_sony_cd_cmd(unsigned char cmd,
unsigned char *params,
unsigned int num_params,
unsigned char *result_buffer, unsigned int *result_size)
{
unsigned int retry_count;
int num_retries;
int recursive_call;
unsigned long flags;
save_flags(flags);
cli();
if (current != has_cd_task) { /* Allow recursive calls to this routine */
while (sony_inuse) {
interruptible_sleep_on(&sony_wait);
if (signal_pending(current)) {
result_buffer[0] = 0x20;
result_buffer[1] = SONY_SIGNAL_OP_ERR;
*result_size = 2;
restore_flags(flags);
return;
}
}
sony_inuse = 1;
has_cd_task = current;
recursive_call = 0;
} else {
recursive_call = 1;
}
num_retries = 0;
retry_cd_operation:
while (handle_sony_cd_attention());
sti();
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
while (time_before(jiffies, retry_count) && (is_busy())) {
sony_sleep();
while (handle_sony_cd_attention());
}
if (is_busy()) {
#if DEBUG
printk("CDU31A timeout out %d\n", __LINE__);
#endif
result_buffer[0] = 0x20;
result_buffer[1] = SONY_TIMEOUT_OP_ERR;
*result_size = 2;
} else {
clear_result_ready();
clear_param_reg();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -