⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sonycd535.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
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, &params[3]);					/*					 * Read the data.  If the drive was not spinning,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -