📄 cdu31a.c
字号:
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 voidget_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 voiddo_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(); write_params(params, num_params); write_cmd(cmd); get_result(result_buffer, result_size); } if (((result_buffer[0] & 0xf0) == 0x20) && (num_retries < MAX_CDU31A_RETRIES)) { num_retries++; current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ / 10); /* Wait .1 seconds on retries */ goto retry_cd_operation; } if (!recursive_call) { has_cd_task = NULL; sony_inuse = 0; wake_up_interruptible(&sony_wait); } restore_flags(flags);}/* * Handle an attention from the drive. This will return 1 if it found one * or 0 if not (if one is found, the caller might want to call again). * * This routine counts the number of consecutive times it is called * (since this is always called from a while loop until it returns * a 0), and returns a 0 if it happens too many times. This will help * prevent a lockup. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -