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

📄 cdu31a.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 5 页
字号:
	return (inb(sony_cd_status_reg));}static inline unsigned char read_result_register(void){	return (inb(sony_cd_result_reg));}static inline unsigned char read_data_register(void){	return (inb(sony_cd_read_reg));}static inline void write_param(unsigned char param){	outb(param, sony_cd_param_reg);}static inline void write_cmd(unsigned char cmd){	outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT,	     sony_cd_control_reg);	outb(cmd, sony_cd_cmd_reg);}static void cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs){	unsigned char val;	if (abort_read_started) {		/* We might be waiting for an abort to finish.  Don't		   disable interrupts yet, though, because we handle		   this one here. */		/* Clear out the result registers. */		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 something was waiting, wake it up now. */		if (waitqueue_active(&cdu31a_irq_wait)) {			disable_interrupts();			wake_up(&cdu31a_irq_wait);		}	} else if (waitqueue_active(&cdu31a_irq_wait)) {		disable_interrupts();		wake_up(&cdu31a_irq_wait);	} else {		disable_interrupts();		printk		    ("CDU31A: Got an interrupt but nothing was waiting\n");	}}/* * give more verbose error messages */static unsigned char *translate_error(unsigned char err_code){	static unsigned char errbuf[80];	switch (err_code) {	case 0x10:		return "illegal command ";	case 0x11:		return "illegal parameter ";	case 0x20:		return "not loaded ";	case 0x21:		return "no disc ";	case 0x22:		return "not spinning ";	case 0x23:		return "spinning ";	case 0x25:		return "spindle servo ";	case 0x26:		return "focus servo ";	case 0x29:		return "eject mechanism ";	case 0x2a:		return "audio playing ";	case 0x2c:		return "emergency eject ";	case 0x30:		return "focus ";	case 0x31:		return "frame sync ";	case 0x32:		return "subcode address ";	case 0x33:		return "block sync ";	case 0x34:		return "header address ";	case 0x40:		return "illegal track read ";	case 0x41:		return "mode 0 read ";	case 0x42:		return "illegal mode read ";	case 0x43:		return "illegal block size read ";	case 0x44:		return "mode read ";	case 0x45:		return "form read ";	case 0x46:		return "leadout read ";	case 0x47:		return "buffer overrun ";	case 0x53:		return "unrecoverable CIRC ";	case 0x57:		return "unrecoverable LECC ";	case 0x60:		return "no TOC ";	case 0x61:		return "invalid subcode data ";	case 0x63:		return "focus on TOC read ";	case 0x64:		return "frame sync on TOC read ";	case 0x65:		return "TOC data ";	case 0x70:		return "hardware failure ";	case 0x91:		return "leadin ";	case 0x92:		return "leadout ";	case 0x93:		return "data track ";	}	sprintf(errbuf, "unknown 0x%02x ", err_code);	return errbuf;}/* * Set the drive parameters so the drive will auto-spin-up when a * disk is inserted. */static void set_drive_params(int want_doublespeed){	unsigned char res_reg[12];	unsigned int res_size;	unsigned char params[3];	params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME;	params[1] = 0x00;	/* Never spin down the drive. */	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,		       params, 2, res_reg, &res_size);	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {		printk("  Unable to set spin-down time: 0x%2.2x\n",		       res_reg[1]);	}	params[0] = SONY_SD_MECH_CONTROL;	params[1] = SONY_AUTO_SPIN_UP_BIT;	/* Set auto spin up */	if (is_auto_eject)		params[1] |= SONY_AUTO_EJECT_BIT;	if (is_double_speed && want_doublespeed) {		params[1] |= SONY_DOUBLE_SPEED_BIT;	/* Set the drive to double speed if 							   possible */	}	do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,		       params, 2, res_reg, &res_size);	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {		printk("  Unable to set mechanical parameters: 0x%2.2x\n",		       res_reg[1]);	}}/* * Uniform cdrom interface function * select reading speed for data access */static int scd_select_speed(struct cdrom_device_info *cdi, int speed){	if (speed == 0)		sony_speed = 1;	else		sony_speed = speed - 1;	set_drive_params(sony_speed);	return 0;}/* * Uniform cdrom interface function * lock or unlock eject button */static int scd_lock_door(struct cdrom_device_info *cdi, int lock){	if (lock == 0 && sony_usage == 1) {		/* Unlock the door, only if nobody is using the drive */		is_auto_eject = 1;	} else {		is_auto_eject = 0;	}	set_drive_params(sony_speed);	return 0;}/* * This code will reset the drive and attempt to restore sane parameters. */static void restart_on_error(void){	unsigned char res_reg[12];	unsigned int res_size;	unsigned int retry_count;	printk("cdu31a: Resetting drive on error\n");	reset_drive();	retry_count = jiffies + SONY_RESET_TIMEOUT;	while (time_before(jiffies, retry_count) && (!is_attention())) {		sony_sleep();	}	set_drive_params(sony_speed);	do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);	if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) {		printk("cdu31a: Unable to spin up drive: 0x%2.2x\n",		       res_reg[1]);	}	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(2 * HZ);	sony_get_toc();}/* * This routine writes data to the parameter register.  Since this should * happen fairly fast, it is polled with no OS waits between. */static int write_params(unsigned char *params, int num_params){	unsigned int retry_count;	retry_count = SONY_READY_RETRIES;	while ((retry_count > 0) && (!is_param_write_rdy())) {		retry_count--;	}	if (!is_param_write_rdy()) {		return -EIO;	}	while (num_params > 0) {		write_param(*params);		params++;		num_params--;	}	return 0;}/* * The following reads data from the command result register.  It is a * fairly complex routine, all status info flows back through this * interface.  The algorithm is stolen directly from the flowcharts in * the drive manual. */static voidget_result(unsigned char *result_buffer, unsigned int *result_size){	unsigned char a, b;	int i;	unsigned int retry_count;	while (handle_sony_cd_attention());	/* Wait for the result data to be ready */	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;	while (time_before(jiffies, retry_count)	       && (is_busy() || (!(is_result_ready())))) {		sony_sleep();		while (handle_sony_cd_attention());	}	if (is_busy() || (!(is_result_ready()))) {#if DEBUG		printk("CDU31A timeout out %d\n", __LINE__);#endif		result_buffer[0] = 0x20;		result_buffer[1] = SONY_TIMEOUT_OP_ERR;		*result_size = 2;		return;	}	/*	 * Get the first two bytes.  This determines what else needs	 * to be done.	 */	clear_result_ready();	a = read_result_register();	*result_buffer = a;	result_buffer++;	/* Check for block error status result. */	if ((a & 0xf0) == 0x50) {		*result_size = 1;		return;	}	b = read_result_register();	*result_buffer = b;	result_buffer++;	*result_size = 2;	/*	 * 0x20 means an error occurred.  Byte 2 will have the error code.	 * Otherwise, the command succeeded, byte 2 will have the count of	 * how many more status bytes are coming.	 *	 * The result register can be read 10 bytes at a time, a wait for	 * result ready to be asserted must be done between every 10 bytes.	 */	if ((a & 0xf0) != 0x20) {		if (b > 8) {			for (i = 0; i < 8; i++) {				*result_buffer = read_result_register();				result_buffer++;				(*result_size)++;			}			b = b - 8;			while (b > 10) {				retry_count = SONY_READY_RETRIES;				while ((retry_count > 0)				       && (!is_result_ready())) {					retry_count--;				}				if (!is_result_ready()) {#if DEBUG					printk("CDU31A timeout out %d\n",					       __LINE__);#endif					result_buffer[0] = 0x20;					result_buffer[1] =					    SONY_TIMEOUT_OP_ERR;					*result_size = 2;					return;				}				clear_result_ready();				for (i = 0; i < 10; i++) {					*result_buffer =					    read_result_register();					result_buffer++;					(*result_size)++;				}				b = b - 10;			}			if (b > 0) {				retry_count = SONY_READY_RETRIES;				while ((retry_count > 0)				       && (!is_result_ready())) {					retry_count--;				}				if (!is_result_ready()) {#if DEBUG					printk("CDU31A timeout out %d\n",					       __LINE__);#endif					result_buffer[0] = 0x20;					result_buffer[1] =					    SONY_TIMEOUT_OP_ERR;					*result_size = 2;					return;				}			}		}		while (b > 0) {			*result_buffer = read_result_register();			result_buffer++;			(*result_size)++;			b--;		}	}}/* * Do a command that does not involve data transfer.  This routine must * be re-entrant from the same task to support being called from the * data operation code when an error occurs. */static voiddo_sony_cd_cmd(unsigned char cmd,	       unsigned char *params,	       unsigned int num_params,	       unsigned char *result_buffer, unsigned int *result_size){	unsigned int retry_count;	int num_retries;	int recursive_call;	unsigned long flags;	save_flags(flags);	cli();	if (current != has_cd_task) {	/* Allow recursive calls to this routine */		while (sony_inuse) {			interruptible_sleep_on(&sony_wait);			if (signal_pending(current)) {				result_buffer[0] = 0x20;				result_buffer[1] = SONY_SIGNAL_OP_ERR;				*result_size = 2;				restore_flags(flags);				return;			}		}		sony_inuse = 1;		has_cd_task = current;		recursive_call = 0;	} else {		recursive_call = 1;	}	num_retries = 0;retry_cd_operation:	while (handle_sony_cd_attention());	sti();	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;	while (time_before(jiffies, retry_count) && (is_busy())) {		sony_sleep();		while (handle_sony_cd_attention());	}	if (is_busy()) {#if DEBUG		printk("CDU31A timeout out %d\n", __LINE__);#endif		result_buffer[0] = 0x20;		result_buffer[1] = SONY_TIMEOUT_OP_ERR;		*result_size = 2;	} else {		clear_result_ready();		clear_param_reg();		write_params(params, num_params);		write_cmd(cmd);		get_result(result_buffer, result_size);	}	if (((result_buffer[0] & 0xf0) == 0x20)	    && (num_retries < MAX_CDU31A_RETRIES)) {		num_retries++;		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(HZ / 10);	/* Wait .1 seconds on retries */		goto retry_cd_operation;	}	if (!recursive_call) {		has_cd_task = NULL;		sony_inuse = 0;		wake_up_interruptible(&sony_wait);	}	restore_flags(flags);}/* * Handle an attention from the drive.  This will return 1 if it found one * or 0 if not (if one is found, the caller might want to call again). * * This routine counts the number of consecutive times it is called * (since this is always called from a while loop until it returns * a 0), and returns a 0 if it happens too many times.  This will help * prevent a lockup. */

⌨️ 快捷键说明

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