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

📄 cdu31a.c

📁 cdrom device drive for linux.
💻 C
📖 第 1 页 / 共 5 页
字号:
{
	outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg);
}

static inline void clear_data_ready(void)
{
	outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT,
	     sony_cd_control_reg);
}

static inline void clear_param_reg(void)
{
	outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg);
}

static inline unsigned char read_status_register(void)
{
	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 void
get_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 void
do_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();

⌨️ 快捷键说明

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