📄 cdu31a.c
字号:
static int handle_sony_cd_attention(void){ unsigned char atten_code; static int num_consecutive_attentions = 0; volatile int val;#if 0*DEBUG printk("Entering handle_sony_cd_attention\n");#endif if (is_attention()) { if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS) { printk ("cdu31a: Too many consecutive attentions: %d\n", num_consecutive_attentions); num_consecutive_attentions = 0;#if DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);#endif return (0); } clear_attention(); atten_code = read_result_register(); switch (atten_code) { /* Someone changed the CD. Mark it as changed */ case SONY_MECH_LOADED_ATTN: disk_changed = 1; sony_toc_read = 0; sony_audio_status = CDROM_AUDIO_NO_STATUS; sony_blocks_left = 0; break; case SONY_SPIN_DOWN_COMPLETE_ATTN: /* Mark the disk as spun down. */ sony_spun_up = 0; break; case SONY_AUDIO_PLAY_DONE_ATTN: sony_audio_status = CDROM_AUDIO_COMPLETED; read_subcode(); break; case SONY_EJECT_PUSHED_ATTN: if (is_auto_eject) { sony_audio_status = CDROM_AUDIO_INVALID; } break; case SONY_LEAD_IN_ERR_ATTN: case SONY_LEAD_OUT_ERR_ATTN: case SONY_DATA_TRACK_ERR_ATTN: case SONY_AUDIO_PLAYBACK_ERR_ATTN: sony_audio_status = CDROM_AUDIO_ERROR; break; } num_consecutive_attentions++;#if DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);#endif return (1); } else if (abort_read_started) { 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 DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);#endif return (1); } num_consecutive_attentions = 0;#if 0*DEBUG printk("Leaving handle_sony_cd_attention at %d\n", __LINE__);#endif return (0);}/* 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, unsigned char *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(unsigned char *msf){ unsigned int log; log = msf[2]; log += msf[1] * 75; log += 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, unsigned char *buf){ buf[0] = size / 65536; size = size % 65536; buf[1] = size / 256; buf[2] = size % 256;}/* Starts a read operation. Returns 0 on success and 1 on failure. The read operation used here allows multiple sequential sectors to be read and status returned for each sector. The driver will read the output one at a time as the requests come and abort the operation if the requested sector is not the next one from the drive. */static intstart_request(unsigned int sector, unsigned int nsect, int read_nsect_only){ unsigned char params[6]; unsigned int read_size; unsigned int retry_count;#if DEBUG 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, ¶ms[3]); /* * Clear any outstanding attentions and wait for the drive to * complete any pending operations. */ while (handle_sony_cd_attention()); retry_count = jiffies + SONY_JIFFIES_TIMEOUT; while (time_before(jiffies, retry_count) && (is_busy())) { sony_sleep(); while (handle_sony_cd_attention()); } if (is_busy()) { printk("CDU31A: Timeout while waiting to issue command\n");#if DEBUG printk("Leaving start_request at %d\n", __LINE__);#endif return (1); } else { /* Issue the command */ clear_result_ready(); clear_param_reg(); write_params(params, 6); write_cmd(SONY_READ_BLKERR_STAT_CMD); sony_blocks_left = read_size * 4; sony_next_block = sector * 4; readahead_dataleft = 0; readahead_bad = 0;#if DEBUG printk("Leaving start_request at %d\n", __LINE__);#endif return (0); }#if DEBUG printk("Leaving start_request at %d\n", __LINE__);#endif}/* Abort a pending read operation. Clear all the drive status and readahead variables. */static void abort_read(void){ unsigned char result_reg[2]; int result_size; volatile int val; do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size); if ((result_reg[0] & 0xf0) == 0x20) { printk("CDU31A: Error aborting read, %s error\n", translate_error(result_reg[1])); } 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(); } sony_blocks_left = 0; readahead_dataleft = 0; readahead_bad = 0;}/* Called when the timer times out. This will abort the pending read operation. */static void handle_abort_timeout(unsigned long data){ unsigned long flags;#if DEBUG printk("Entering handle_abort_timeout\n");#endif save_flags(flags); cli(); /* If it is in use, ignore it. */ if (!sony_inuse) { /* We can't use abort_read(), because it will sleep or schedule in the timer interrupt. Just start the operation, finish it on the next access to the drive. */ clear_result_ready(); clear_param_reg(); write_cmd(SONY_ABORT_CMD); sony_blocks_left = 0; readahead_dataleft = 0; readahead_bad = 0; abort_read_started = 1; } restore_flags(flags);#if DEBUG printk("Leaving handle_abort_timeout\n");#endif}/* Actually get data and status from the drive. */static voidinput_data(char *buffer, unsigned int bytesleft, unsigned int nblocks, unsigned int offset, unsigned int skip){ int i; volatile unsigned char val;#if DEBUG printk("Entering input_data\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(); } } 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(); } }#if DEBUG printk("Leaving input_data at %d\n", __LINE__);#endif}/* read data from the drive. Note the nsect must be <= 4. */static voidread_data_block(char *buffer, unsigned int block, unsigned int nblocks, unsigned char res_reg[], int *res_size){ unsigned int retry_count; unsigned int bytesleft; unsigned int offset; unsigned int skip;#if DEBUG printk("Entering read_data_block\n");#endif res_reg[0] = 0; res_reg[1] = 0; *res_size = 0; /* Make sure that bytesleft doesn't exceed the buffer size */ if (nblocks > 4) nblocks = 4; 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; while (time_before(jiffies, retry_count) && !(is_data_ready())) { while (handle_sony_cd_attention()); sony_sleep(); } if (!(is_data_ready())) { if (is_result_ready()) { get_result(res_reg, res_size); if ((res_reg[0] & 0xf0) != 0x20) { printk ("CDU31A: Got result that should have been error: %d\n", res_reg[0]); res_reg[0] = 0x20; res_reg[1] = SONY_BAD_DATA_ERR; *res_size = 2; } abort_read(); } else {#if DEBUG printk("CDU31A timeout out %d\n", __LINE__);#endif res_reg[0] = 0x20; res_reg[1] = SONY_TIMEOUT_OP_ERR; *res_size = 2; abort_read(); } } else { input_data(buffer, bytesleft, nblocks, offset, skip); /* Wait for the status from the drive. */ retry_count = jiffies + SONY_JIFFIES_TIMEOUT; while (time_before(jiffies, retry_count) && !(is_result_ready())) { while (handle_sony_cd_attention()); sony_sleep(); } if (!is_result_ready()) {#if DEBUG printk("CDU31A timeout out %d\n", __LINE__);#endif res_reg[0] = 0x20; res_reg[1] = SONY_TIMEOUT_OP_ERR; *res_size = 2; abort_read(); } else { get_result(res_reg, res_size); /* If we got a buffer status, handle that. */ if ((res_reg[0] & 0xf0) == 0x50) { if ((res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT) || (res_reg[0] == 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -