📄 cdu31a.c
字号:
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; 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); readahead_dataleft = 0; bytesleft -= readahead_dataleft; offset += readahead_dataleft; } 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) { readahead_bad = 0; res_reg[0] = 0x20; res_reg[1] = SONY_BAD_DATA_ERR; *res_size = 2; } } else { printk("CDU31A: Data block error: 0x%x\n", res_reg[0]); 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. */ if (sony_blocks_left == 0) { get_result(res_reg, res_size); } } else if ((res_reg[0] & 0xf0) != 0x20) { /* The drive gave me bad status, I don't know what to do. Reset the driver and return an error. */ printk("CDU31A: Invalid block status: 0x%x\n", res_reg[0]); restart_on_error(); res_reg[0] = 0x20; res_reg[1] = SONY_BAD_DATA_ERR; *res_size = 2; } } }#if DEBUG printk("Leaving read_data_block at %d\n", __LINE__);#endif}/* * 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 * uses 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 voiddo_cdu31a_request(void){ int block; int nblock; unsigned char res_reg[12]; unsigned int res_size; int num_retries; unsigned long flags;#if DEBUG printk("Entering do_cdu31a_request\n");#endif /* * Make sure no one else is using the driver; wait for them * to finish if it is so. */ save_flags(flags); cli(); while (sony_inuse) { interruptible_sleep_on(&sony_wait); if (signal_pending(current)) { restore_flags(flags); if (CURRENT && CURRENT->rq_status != RQ_INACTIVE) { end_request(0); } restore_flags(flags);#if DEBUG printk("Leaving do_cdu31a_request at %d\n", __LINE__);#endif return; } } sony_inuse = 1; has_cd_task = current; /* Get drive status before doing anything. */ while (handle_sony_cd_attention()) ; /* Make sure we have a valid TOC. */ sony_get_toc(); spin_unlock_irq(&io_request_lock); /* Make sure the timer is cancelled. */ del_timer(&cdu31a_abort_timer); while (1) {cdu31a_request_startover: /* * The beginning here is stolen from the hard disk driver. I hope * it's right. */ if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE) { goto end_do_cdu31a_request; } if (!sony_spun_up) { scd_spinup(); } /* I don't use INIT_REQUEST because it calls return, which would return without unlocking the device. It shouldn't matter, but just to be safe... */ if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) { panic(DEVICE_NAME ": request list destroyed"); } if (CURRENT->bh) { if (!buffer_locked(CURRENT->bh)) { panic(DEVICE_NAME ": block not locked"); } } block = CURRENT->sector; nblock = CURRENT->nr_sectors; if (!sony_toc_read) { printk("CDU31A: TOC not read\n"); end_request(0); goto cdu31a_request_startover; } switch(CURRENT->cmd) { case READ: /* * If the block address is invalid or the request goes beyond the end of * the media, return an error. */#if 0 if ((block / 4) < sony_toc.start_track_lba) { printk("CDU31A: Request before beginning of media\n"); end_request(0); goto cdu31a_request_startover; }#endif if ((block / 4) >= sony_toc.lead_out_start_lba) { printk("CDU31A: Request past end of media\n"); end_request(0); goto cdu31a_request_startover; } if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { printk("CDU31A: Request past end of media\n"); end_request(0); goto cdu31a_request_startover; } num_retries = 0;try_read_again: while (handle_sony_cd_attention()) ; if (!sony_toc_read) { printk("CDU31A: TOC not read\n"); end_request(0); goto cdu31a_request_startover; } /* 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)) { end_request(0); goto cdu31a_request_startover; } } /* If the requested block is not the next one waiting in the driver, abort the current operation and start a new one. */ else if (block != sony_next_block) {#if DEBUG printk("CDU31A Warning: Read for block %d, expected %d\n", block, sony_next_block);#endif abort_read(); if (!sony_toc_read) { printk("CDU31A: TOC not read\n"); end_request(0); goto cdu31a_request_startover; } if (start_request(block / 4, CDU31A_READAHEAD / 4, 0)) { printk("CDU31a: start request failed\n"); end_request(0); goto cdu31a_request_startover; } } read_data_block(CURRENT->buffer, block, nblock, res_reg, &res_size); if (res_reg[0] == 0x20) { if (num_retries > MAX_CDU31A_RETRIES) { end_request(0); goto cdu31a_request_startover; } num_retries++; if (res_reg[1] == SONY_NOT_SPIN_ERR) { do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); } else { printk("CDU31A: %s error for block %d, nblock %d\n", translate_error(res_reg[1]), block, nblock); } goto try_read_again; } else { end_request(1); } break; case WRITE:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -