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

📄 cdu31a.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 5 页
字号:
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, &params[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 + -