📄 sonycd535.c
字号:
check_drive_status(void){ Byte status, e_status[2]; int CDD, ATN; Byte cmd; select_unit(0); if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); if (read_result_reg(&status) == 0) { switch (status) { case 0x0: break; /* play in progress */ case 0x1: break; /* paused */ case 0x3: /* audio play completed */ case 0x5: /* play not requested */ sony_audio_status = CDROM_AUDIO_COMPLETED; read_subcode(); break; case 0x4: /* error during play */ sony_audio_status = CDROM_AUDIO_ERROR; break; } } } /* now check drive status */ outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); if (read_result_reg(&status) != 0) return TIME_OUT;#if DEBUG > 1 printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status);#endif if (status == 0) return 0; ATN = status & 0xf; CDD = (status >> 4) & 0xf; switch (ATN) { case 0x0: break; /* go on to CDD stuff */ case SONY535_ATN_BUSY: if (initialized) printk(CDU535_MESSAGE_NAME " error: drive busy\n"); return CD_BUSY; case SONY535_ATN_EJECT_IN_PROGRESS: printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); sony_audio_status = CDROM_AUDIO_INVALID; return CD_BUSY; case SONY535_ATN_RESET_OCCURRED: case SONY535_ATN_DISC_CHANGED: case SONY535_ATN_RESET_AND_DISC_CHANGED:#if DEBUG > 0 printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n");#endif sony_disc_changed = 1; sony_toc_read = 0; sony_audio_status = CDROM_AUDIO_NO_STATUS; sony_first_block = -1; sony_last_block = -1; if (initialized) { cmd = SONY535_SPIN_UP; do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); sony_get_toc(); } return 0; default: printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); return CD_BUSY; } switch (CDD) { /* the 531 docs are not helpful in decoding this */ case 0x0: /* just use the values from the DOS driver */ case 0x2: case 0xa: break; /* no error */ case 0xc: printk(CDU535_MESSAGE_NAME ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); return CD_BUSY; /* ? */ default: return CD_BUSY; } return 0;} /* check_drive_status() *//***************************************************************************** * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], * Byte *response, int n_response, int ignore_status_bit7 ) * * Generic routine for executing commands. The command and its parameters * should be placed in the cmd[] array, number of bytes in the command is * stored in nCmd. The response from the command will be stored in the * response array. The number of bytes you expect back (excluding status) * should be passed in n_response. Finally, some * commands set bit 7 of the return status even when there is no second * status byte, on these commands set ignoreStatusBit7 TRUE. * If the command was sent and data received back, then we return 0, * else we return TIME_OUT. You still have to check the status yourself. * You should call check_drive_status() before calling this routine * so that you do not lose notifications of disk changes, etc. ****************************************************************************/static intdo_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], Byte * response, int n_response, int ignore_status_bit7){ int i; /* write out the command */ for (i = 0; i < n_cmd; i++) outb(cmd[i], command_reg); /* read back the status */ if (read_result_reg(status) != 0) return TIME_OUT; if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { /* get second status byte */ if (read_result_reg(status + 1) != 0) return TIME_OUT; } else { status[1] = 0; }#if DEBUG > 2 printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", *cmd, status[0], status[1]);#endif /* do not know about when I should read set of data and when not to */ if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) return 0; /* else, read in rest of data */ for (i = 0; 0 < n_response; n_response--, i++) if (read_result_reg(response + i) != 0) return TIME_OUT; return 0;} /* do_sony_cmd() *//************************************************************************** * int set_drive_mode( int mode, Byte status[2] ) * * Set the drive mode to the specified value (mode=0 is audio, mode=e0 * is mode-1 CDROM **************************************************************************/static intset_drive_mode(int mode, Byte status[2]){ Byte cmd_buff[2]; Byte ret_buff[1]; cmd_buff[0] = SONY535_SET_DRIVE_MODE; cmd_buff[1] = mode; return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1);}/*************************************************************************** * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], * Byte *data_buff, int buff_size ) * * Read n_blocks of data from the CDROM starting at position params[0:2], * number of blocks in stored in params[3:5] -- both these are already * int bcd format. * Transfer the data into the buffer pointed at by data_buff. buff_size * gives the number of bytes available in the buffer. * The routine returns number of bytes read in if successful, otherwise * it returns one of the standard error returns. ***************************************************************************/static intseek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], Byte **buff, int buf_size){ Byte cmd_buff[7]; int i; int read_status; unsigned long snap; Byte *data_buff; int sector_count = 0; if (buf_size < CDU535_BLOCK_SIZE * n_blocks) return NO_ROOM; set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); /* send command to read the data */ cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; for (i = 0; i < 6; i++) cmd_buff[i + 1] = params[i]; for (i = 0; i < 7; i++) outb(cmd_buff[i], command_reg); /* read back the data one block at a time */ while (0 < n_blocks--) { /* wait for data to be ready */ int data_valid = 0; snap = jiffies; while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { read_status = inb(read_status_reg); if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { read_exec_status(status); return BAD_STATUS; } if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { /* data is ready, read it */ data_buff = buff[sector_count++]; for (i = 0; i < CDU535_BLOCK_SIZE; i++) *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ data_valid = 1; break; /* exit the timeout loop */ } sony_sleep(); /* data not ready, sleep a while */ } if (!data_valid) return TIME_OUT; /* if we reach this stage */ } /* read all the data, now read the status */ if ((i = read_exec_status(status)) != 0) return i; return CDU535_BLOCK_SIZE * sector_count;} /* seek_and_read_N_blocks() *//**************************************************************************** * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) * * Read in the table of contents data. Converts all the bcd data * into integers in the toc structure. ****************************************************************************/static intrequest_toc_data(Byte status[2], struct s535_sony_toc *toc){ int to_status; int i, j, n_tracks, track_no; int first_track_num, last_track_num; Byte cmd_no = 0xb2; Byte track_address_buffer[5]; /* read the fixed portion of the table of contents */ if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) return to_status; /* convert the data into integers so we can use them */ first_track_num = bcd_to_int(toc->first_track_num); last_track_num = bcd_to_int(toc->last_track_num); n_tracks = last_track_num - first_track_num + 1; /* read each of the track address descriptors */ for (i = 0; i < n_tracks; i++) { /* read the descriptor into a temporary buffer */ for (j = 0; j < 5; j++) { if (read_result_reg(track_address_buffer + j) != 0) return TIME_OUT; if (j == 1) /* need to convert from bcd */ track_no = bcd_to_int(track_address_buffer[j]); } /* copy the descriptor to proper location - sonycd.c just fills */ memcpy(toc->tracks + i, track_address_buffer, 5); } return 0;} /* request_toc_data() *//*************************************************************************** * int spin_up_drive( Byte status[2] ) * * Spin up the drive (unless it is already spinning). ***************************************************************************/static intspin_up_drive(Byte status[2]){ Byte cmd; /* first see if the drive is already spinning */ cmd = SONY535_REQUEST_DRIVE_STATUS_1; if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) return TIME_OUT; if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) return 0; /* it's already spinning */ /* otherwise, give the spin-up command */ cmd = SONY535_SPIN_UP; return do_sony_cmd(&cmd, 1, status, NULL, 0, 0);}/*--------------------end of SONY CDU535 very specific ---------------------*//* Convert from an integer 0-99 to BCD */static inline unsigned intint_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 intbcd_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 voidlog_to_msf(unsigned int log, Byte *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 intmsf_to_log(Byte *msf){ unsigned int log; log = bcd_to_int(msf[2]); log += bcd_to_int(msf[1]) * 75; log += bcd_to_int(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 voidsize_to_buf(unsigned int size, Byte *buf){ buf[0] = size / 65536; size = size % 65536; buf[1] = size / 256; buf[2] = size % 256;}/* * 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 * may use 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_cdu535_request(request_queue_t * q){ unsigned int dev; unsigned int read_size; int block; int nsect; int copyoff; int spin_up_retry; Byte params[10]; Byte status[2]; Byte cmd[2]; while (1) { /* * The beginning here is stolen from the hard disk driver. I hope * it's right. */ if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE) { return; } INIT_REQUEST; dev = MINOR(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (dev != 0) { end_request(0); continue; } 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 (sony_toc->lead_out_start_lba <= (block / 4)) { end_request(0); return; } if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { end_request(0); return; } while (0 < nsect) { /* * If the requested sector is not currently in the read-ahead buffer, * it must be read in. */ if ((block < sony_first_block) || (sony_last_block < block)) { sony_first_block = (block / 4) * 4; log_to_msf(block / 4, params); /* * 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. */ if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; read_size = sony_toc->lead_out_start_lba - (block / 4); } else { sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; read_size = sony_buffer_sectors; } size_to_buf(read_size, ¶ms[3]); /* * Read the data. If the drive was not spinning,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -