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

📄 sonycd535.c

📁 cdrom device drive for linux.
💻 C
📖 第 1 页 / 共 4 页
字号:
					 * spin it up and try some more.
					 */
					for (spin_up_retry=0 ;; ++spin_up_retry) {
						/* This loop has been modified to support the Sony
						 * CDU-510/515 series, thanks to Claudio Porfiri 
						 * <C.Porfiri@nisms.tei.ericsson.se>.
						 */
						/*
						 * This part is to deal with very slow hardware.  We
						 * try at most MAX_SPINUP_RETRY times to read the same
						 * block.  A check for seek_and_read_N_blocks' result is
						 * performed; if the result is wrong, the CDROM's engine
						 * is restarted and the operation is tried again.
						 */
						/*
						 * 1995-06-01: The system got problems when downloading
						 * from Slackware CDROM, the problem seems to be:
						 * seek_and_read_N_blocks returns BAD_STATUS and we
						 * should wait for a while before retrying, so a new
						 * part was added to discriminate the return value from
						 * seek_and_read_N_blocks for the various cases.
						 */
						int readStatus = seek_and_read_N_blocks(params, read_size,
									status, sony_buffer, (read_size * CDU535_BLOCK_SIZE));
						if (0 <= readStatus)	/* Good data; common case, placed first */
							break;
						if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) {
							/* give up */
							if (readStatus == NO_ROOM)
								printk(CDU535_MESSAGE_NAME " No room to read from CD\n");
							else
								printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
										status[0]);
							sony_first_block = -1;
							sony_last_block = -1;
							end_request(0);
							return;
						}
						if (readStatus == BAD_STATUS) {
							/* Sleep for a while, then retry */
							current->state = TASK_INTERRUPTIBLE;
							schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10);
						}
#if DEBUG > 0
						printk(CDU535_MESSAGE_NAME
							" debug: calling spin up when reading data!\n");
#endif
						cmd[0] = SONY535_SPIN_UP;
						do_sony_cmd(cmd, 1, status, NULL, 0, 0);
					}
				}
				/*
				 * The data is in memory now, copy it to the buffer and advance to the
				 * next block to read.
				 */
				copyoff = block - sony_first_block;
				memcpy(CURRENT->buffer,
					   sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512);

				block += 1;
				nsect -= 1;
				CURRENT->buffer += 512;
			}

			end_request(1);
			break;

		case WRITE:
			end_request(0);
			break;

		default:
			panic("Unknown SONY CD cmd");
		}
	}
}


/*
 * Read the table of contents from the drive and set sony_toc_read if
 * successful.
 */
static void
sony_get_toc(void)
{
	Byte status[2];
	if (!sony_toc_read) {
		/* do not call check_drive_status() from here since it can call this routine */
		if (request_toc_data(status, sony_toc) < 0)
			return;
		sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf);
		sony_toc_read = 1;
	}
}


/*
 * Search for a specific track in the table of contents.  track is
 * passed in bcd format
 */
static int
find_track(int track)
{
	int i;
	int num_tracks;


	num_tracks = bcd_to_int(sony_toc->last_track_num) -
		bcd_to_int(sony_toc->first_track_num) + 1;
	for (i = 0; i < num_tracks; i++) {
		if (sony_toc->tracks[i].track == track) {
			return i;
		}
	}

	return -1;
}

/*
 * Read the subcode and put it int last_sony_subcode for future use.
 */
static int
read_subcode(void)
{
	Byte cmd = SONY535_REQUEST_SUB_Q_DATA;
	Byte status[2];
	int  dsc_status;

	if (check_drive_status() != 0)
		return -EIO;

	if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode,
							   sizeof(struct s535_sony_subcode), 1)) != 0) {
		printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n",
				status[0], dsc_status);
		return -EIO;
	}
	return 0;
}


/*
 * Get the subchannel info like the CDROMSUBCHNL command wants to see it.  If
 * the drive is playing, the subchannel needs to be read (since it would be
 * changing).  If the drive is paused or completed, the subcode information has
 * already been stored, just use that.  The ioctl call wants things in decimal
 * (not BCD), so all the conversions are done.
 */
static int
sony_get_subchnl_info(long arg)
{
	struct cdrom_subchnl schi;
	int err;

	/* Get attention stuff */
	if (check_drive_status() != 0)
		return -EIO;

	sony_get_toc();
	if (!sony_toc_read) {
		return -EIO;
	}
	err = verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof schi);
	if (err)
		return err;

	copy_from_user(&schi, (char *)arg, sizeof schi);

	switch (sony_audio_status) {
	case CDROM_AUDIO_PLAY:
		if (read_subcode() < 0) {
			return -EIO;
		}
		break;

	case CDROM_AUDIO_PAUSED:
	case CDROM_AUDIO_COMPLETED:
		break;

	case CDROM_AUDIO_NO_STATUS:
		schi.cdsc_audiostatus = sony_audio_status;
		copy_to_user((char *)arg, &schi, sizeof schi);
		return 0;
		break;

	case CDROM_AUDIO_INVALID:
	case CDROM_AUDIO_ERROR:
	default:
		return -EIO;
	}

	schi.cdsc_audiostatus = sony_audio_status;
	schi.cdsc_adr = last_sony_subcode->address;
	schi.cdsc_ctrl = last_sony_subcode->control;
	schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num);
	schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num);
	if (schi.cdsc_format == CDROM_MSF) {
		schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]);
		schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]);
		schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]);

		schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]);
		schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]);
		schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]);
	} else if (schi.cdsc_format == CDROM_LBA) {
		schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
		schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
	}
	copy_to_user((char *)arg, &schi, sizeof schi);
	return 0;
}


/*
 * The big ugly ioctl handler.
 */
static int
cdu_ioctl(struct inode *inode,
		  struct file *file,
		  unsigned int cmd,
		  unsigned long arg)
{
	unsigned int dev;
	Byte status[2];
	Byte cmd_buff[10], params[10];
	int  i;
	int  dsc_status;
	int  err;

	if (!inode) {
		return -EINVAL;
	}
	dev = MINOR(inode->i_rdev) >> 6;
	if (dev != 0) {
		return -EINVAL;
	}
	if (check_drive_status() != 0)
		return -EIO;

	switch (cmd) {
	case CDROMSTART:			/* Spin up the drive */
		if (spin_up_drive(status) < 0) {
			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n",
					status[0]);
			return -EIO;
		}
		return 0;
		break;

	case CDROMSTOP:			/* Spin down the drive */
		cmd_buff[0] = SONY535_HOLD;
		do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);

		/*
		 * Spin the drive down, ignoring the error if the disk was
		 * already not spinning.
		 */
		sony_audio_status = CDROM_AUDIO_NO_STATUS;
		cmd_buff[0] = SONY535_SPIN_DOWN;
		dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
		if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) ||
			((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) {
			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n",
					status[0]);
			return -EIO;
		}
		return 0;
		break;

	case CDROMPAUSE:			/* Pause the drive */
		cmd_buff[0] = SONY535_HOLD;		/* CDU-31 driver uses AUDIO_STOP, not pause */
		if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n",
					status[0]);
			return -EIO;
		}
		/* Get the current position and save it for resuming */
		if (read_subcode() < 0) {
			return -EIO;
		}
		cur_pos_msf[0] = last_sony_subcode->abs_msf[0];
		cur_pos_msf[1] = last_sony_subcode->abs_msf[1];
		cur_pos_msf[2] = last_sony_subcode->abs_msf[2];
		sony_audio_status = CDROM_AUDIO_PAUSED;
		return 0;
		break;

	case CDROMRESUME:			/* Start the drive after being paused */
		set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status);

		if (sony_audio_status != CDROM_AUDIO_PAUSED) {
			return -EINVAL;
		}
		spin_up_drive(status);

		/* Start the drive at the saved position. */
		cmd_buff[0] = SONY535_PLAY_AUDIO;
		cmd_buff[1] = 0;		/* play back starting at this address */
		cmd_buff[2] = cur_pos_msf[0];
		cmd_buff[3] = cur_pos_msf[1];
		cmd_buff[4] = cur_pos_msf[2];
		cmd_buff[5] = SONY535_PLAY_AUDIO;
		cmd_buff[6] = 2;		/* set ending address */
		cmd_buff[7] = final_pos_msf[0];
		cmd_buff[8] = final_pos_msf[1];
		cmd_buff[9] = final_pos_msf[2];
		if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
			(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n",
					status[0]);
			return -EIO;
		}
		sony_audio_status = CDROM_AUDIO_PLAY;
		return 0;
		break;

	case CDROMPLAYMSF:			/* Play starting at the given MSF address. */
		err = verify_area(VERIFY_READ, (char *)arg, 6);
		if (err)
			return err;
		spin_up_drive(status);
		set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status);
		copy_from_user(params, (void *)arg, 6);

		/* The parameters are given in int, must be converted */
		for (i = 0; i < 3; i++) {
			cmd_buff[2 + i] = int_to_bcd(params[i]);
			cmd_buff[7 + i] = int_to_bcd(params[i + 3]);
		}
		cmd_buff[0] = SONY535_PLAY_AUDIO;
		cmd_buff[1] = 0;		/* play back starting at this address */
		/* cmd_buff[2-4] are filled in for loop above */
		cmd_buff[5] = SONY535_PLAY_AUDIO;
		cmd_buff[6] = 2;		/* set ending address */
		/* cmd_buff[7-9] are filled in for loop above */
		if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
			(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n",
					status[0]);
			return -EIO;
		}
		/* Save the final position for pauses and resumes */
		final_pos_msf[0] = cmd_buff[7];
		final_pos_msf[1] = cmd_buff[8];
		final_pos_msf[2] = cmd_buff[9];
		sony_audio_status = CDROM_AUDIO_PLAY;
		return 0;
		break;

	case CDROMREADTOCHDR:		/* Read the table of contents header */
		{
			struct cdrom_tochdr *hdr;
			struct cdrom_tochdr loc_hdr;

			sony_get_toc();
			if (!sony_toc_read)
				return -EIO;
			hdr = (struct cdrom_tochdr *)arg;
			err = verify_area(VERIFY_WRITE, hdr, sizeof *hdr);
			if (err)
				return err;
			loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
			loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
			copy_to_user(hdr, &loc_hdr, sizeof *hdr);
		}
		return 0;
		break;

	case CDROMREADTOCENTRY:	/* Read a given table of contents entry */
		{
			struct cdrom_tocentry *entry;
			struct cdrom_tocentry loc_entry;
			int  track_idx;
			Byte *msf_val = NULL;

			sony_get_toc();
			if (!sony_toc_read) {
				return -EIO;
			}
			entry = (struct cdrom_tocentry *)arg;
			err = verify_area(VERIFY_WRITE /* and read */ , entry, sizeof *entry);
			if (err)
				return err;

			copy_from_user(&loc_entry, entry, sizeof loc_entry);

			/* Lead out is handled separately since it is special. */
			if (loc_entry.cdte_track == CDROM_LEADOUT) {
				loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ;
				loc_entry.cdte_ctrl = sony_toc->control2;
				msf_val = sony_toc->lead_out_start_msf;
			} else {
				track_idx = find_track(int_to_bcd(loc_entry.cdte_track));
				if (track_idx < 0)
					return -EINVAL;
				loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ;
				loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control;
				msf_val = sony_toc->tracks[track_idx].track_start_msf;
			}

			/* Logical buffer address or MSF format requested? */
			if (loc_entry.cdte_format == CDROM_LBA) {
				loc_entry.cdte_addr.lba = msf_to_log(msf_val);
			} else if (loc_entry.cdte_format == CDROM_MSF) {
				loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val);
				loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1));
				loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2));
			}
			copy_to_user(entry, &loc_entry, sizeof *entry);
		}
		return 0;
		break;

	case CDROMPLAYTRKIND:		/* Play a track.  This currently ignores index. */
		{
			struct cdrom_ti ti;
			int track_idx;

			sony_get_toc();
			if (!sony_toc_read)
				return -EIO;
			err = verify_area(VERIFY_READ, (char *)arg, sizeof ti);
			if (err)
				return err;

			copy_from_user(&ti, (char *)arg, sizeof ti);
			if ((ti.cdti_trk0 < sony_toc->first_track_num)
				|| (sony_toc->last_track_num < ti.cdti_trk0)

⌨️ 快捷键说明

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