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

📄 sjcd.c

📁 cdrom device drive for linux.
💻 C
📖 第 1 页 / 共 3 页
字号:
#if defined( SJCD_TRACE )
	printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min,
	       sjcd_disk_length.sec, sjcd_disk_length.frame);
#endif
	return (0);
}

/*
 * Load subchannel information.
 */
static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp)
{
	int s;
#if defined( SJCD_TRACE )
	printk("SJCD: load sub q\n");
#endif
	sjcd_send_cmd(SCMD_GET_QINFO);
	s = sjcd_receive_status();
	if (s < 0 || sjcd_command_failed || !sjcd_status_valid) {
		sjcd_send_cmd(0xF2);
		s = sjcd_receive_status();
		if (s < 0 || sjcd_command_failed || !sjcd_status_valid)
			return (-1);
		sjcd_send_cmd(SCMD_GET_QINFO);
		s = sjcd_receive_status();
		if (s < 0 || sjcd_command_failed || !sjcd_status_valid)
			return (-1);
	}
	if (sjcd_media_is_available)
		if (sjcd_load_response(qp, sizeof(*qp)) == 0)
			return (0);
	return (-1);
}

/*
 * Start playing from the specified position.
 */
static int sjcd_play(struct sjcd_play_msf *mp)
{
	struct sjcd_play_msf msf;

	/*
	 * Turn the device to play mode.
	 */
	sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY);
	if (sjcd_receive_status() < 0)
		return (-1);

	/*
	 * Seek to the starting point.
	 */
	msf.start = mp->start;
	msf.end.min = msf.end.sec = msf.end.frame = 0x00;
	sjcd_send_6_cmd(SCMD_SEEK, &msf);
	if (sjcd_receive_status() < 0)
		return (-1);

	/*
	 * Start playing.
	 */
	sjcd_send_6_cmd(SCMD_PLAY, mp);
	return (sjcd_receive_status());
}

/*
 * Tray control functions.
 */
static int sjcd_tray_close(void)
{
#if defined( SJCD_TRACE )
	printk("SJCD: tray_close\n");
#endif
	sjcd_send_cmd(SCMD_CLOSE_TRAY);
	return (sjcd_receive_status());
}

static int sjcd_tray_lock(void)
{
#if defined( SJCD_TRACE )
	printk("SJCD: tray_lock\n");
#endif
	sjcd_send_cmd(SCMD_LOCK_TRAY);
	return (sjcd_receive_status());
}

static int sjcd_tray_unlock(void)
{
#if defined( SJCD_TRACE )
	printk("SJCD: tray_unlock\n");
#endif
	sjcd_send_cmd(SCMD_UNLOCK_TRAY);
	return (sjcd_receive_status());
}

static int sjcd_tray_open(void)
{
#if defined( SJCD_TRACE )
	printk("SJCD: tray_open\n");
#endif
	sjcd_send_cmd(SCMD_EJECT_TRAY);
	return (sjcd_receive_status());
}

/*
 * Do some user commands.
 */
static int sjcd_ioctl(struct inode *ip, struct file *fp,
		      unsigned int cmd, unsigned long arg)
{
#if defined( SJCD_TRACE )
	printk("SJCD:ioctl\n");
#endif

	if (ip == NULL)
		return (-EINVAL);

	sjcd_get_status();
	if (!sjcd_status_valid)
		return (-EIO);
	if (sjcd_update_toc() < 0)
		return (-EIO);

	switch (cmd) {
	case CDROMSTART:{
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: start\n");
#endif
			return (0);
		}

	case CDROMSTOP:{
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: stop\n");
#endif
			sjcd_send_cmd(SCMD_PAUSE);
			(void) sjcd_receive_status();
			sjcd_audio_status = CDROM_AUDIO_NO_STATUS;
			return (0);
		}

	case CDROMPAUSE:{
			struct sjcd_hw_qinfo q_info;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: pause\n");
#endif
			if (sjcd_audio_status == CDROM_AUDIO_PLAY) {
				sjcd_send_cmd(SCMD_PAUSE);
				(void) sjcd_receive_status();
				if (sjcd_get_q_info(&q_info) < 0) {
					sjcd_audio_status =
					    CDROM_AUDIO_NO_STATUS;
				} else {
					sjcd_audio_status =
					    CDROM_AUDIO_PAUSED;
					sjcd_playing.start = q_info.abs;
				}
				return (0);
			} else
				return (-EINVAL);
		}

	case CDROMRESUME:{
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: resume\n");
#endif
			if (sjcd_audio_status == CDROM_AUDIO_PAUSED) {
				/*
				 * continue play starting at saved location
				 */
				if (sjcd_play(&sjcd_playing) < 0) {
					sjcd_audio_status =
					    CDROM_AUDIO_ERROR;
					return (-EIO);
				} else {
					sjcd_audio_status =
					    CDROM_AUDIO_PLAY;
					return (0);
				}
			} else
				return (-EINVAL);
		}

	case CDROMPLAYTRKIND:{
			struct cdrom_ti ti;
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: playtrkind\n");
#endif
			if ((s =
			     verify_area(VERIFY_READ, (void *) arg,
					 sizeof(ti))) == 0) {
				copy_from_user(&ti, (void *) arg,
					       sizeof(ti));

				if (ti.cdti_trk0 < sjcd_first_track_no)
					return (-EINVAL);
				if (ti.cdti_trk1 > sjcd_last_track_no)
					ti.cdti_trk1 = sjcd_last_track_no;
				if (ti.cdti_trk0 > ti.cdti_trk1)
					return (-EINVAL);

				sjcd_playing.start =
				    sjcd_table_of_contents[ti.cdti_trk0].
				    un.track_msf;
				sjcd_playing.end =
				    (ti.cdti_trk1 <
				     sjcd_last_track_no) ?
				    sjcd_table_of_contents[ti.cdti_trk1 +
							   1].un.
				    track_msf : sjcd_table_of_contents[0].
				    un.track_msf;

				if (sjcd_play(&sjcd_playing) < 0) {
					sjcd_audio_status =
					    CDROM_AUDIO_ERROR;
					return (-EIO);
				} else
					sjcd_audio_status =
					    CDROM_AUDIO_PLAY;
			}
			return (s);
		}

	case CDROMPLAYMSF:{
			struct cdrom_msf sjcd_msf;
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: playmsf\n");
#endif
			if ((s =
			     verify_area(VERIFY_READ, (void *) arg,
					 sizeof(sjcd_msf))) == 0) {
				if (sjcd_audio_status == CDROM_AUDIO_PLAY) {
					sjcd_send_cmd(SCMD_PAUSE);
					(void) sjcd_receive_status();
					sjcd_audio_status =
					    CDROM_AUDIO_NO_STATUS;
				}

				copy_from_user(&sjcd_msf, (void *) arg,
					       sizeof(sjcd_msf));

				sjcd_playing.start.min =
				    bin2bcd(sjcd_msf.cdmsf_min0);
				sjcd_playing.start.sec =
				    bin2bcd(sjcd_msf.cdmsf_sec0);
				sjcd_playing.start.frame =
				    bin2bcd(sjcd_msf.cdmsf_frame0);
				sjcd_playing.end.min =
				    bin2bcd(sjcd_msf.cdmsf_min1);
				sjcd_playing.end.sec =
				    bin2bcd(sjcd_msf.cdmsf_sec1);
				sjcd_playing.end.frame =
				    bin2bcd(sjcd_msf.cdmsf_frame1);

				if (sjcd_play(&sjcd_playing) < 0) {
					sjcd_audio_status =
					    CDROM_AUDIO_ERROR;
					return (-EIO);
				} else
					sjcd_audio_status =
					    CDROM_AUDIO_PLAY;
			}
			return (s);
		}

	case CDROMREADTOCHDR:{
			struct cdrom_tochdr toc_header;
			int s;
#if defined (SJCD_TRACE )
			printk("SJCD: ioctl: readtocheader\n");
#endif
			if ((s =
			     verify_area(VERIFY_WRITE, (void *) arg,
					 sizeof(toc_header))) == 0) {
				toc_header.cdth_trk0 = sjcd_first_track_no;
				toc_header.cdth_trk1 = sjcd_last_track_no;
				copy_to_user((void *) arg, &toc_header,
					     sizeof(toc_header));
			}
			return (s);
		}

	case CDROMREADTOCENTRY:{
			struct cdrom_tocentry toc_entry;
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: readtocentry\n");
#endif
			if ((s =
			     verify_area(VERIFY_WRITE, (void *) arg,
					 sizeof(toc_entry))) == 0) {
				struct sjcd_hw_disk_info *tp;

				copy_from_user(&toc_entry, (void *) arg,
					       sizeof(toc_entry));

				if (toc_entry.cdte_track == CDROM_LEADOUT)
					tp = &sjcd_table_of_contents[0];
				else if (toc_entry.cdte_track <
					 sjcd_first_track_no)
					return (-EINVAL);
				else if (toc_entry.cdte_track >
					 sjcd_last_track_no)
					return (-EINVAL);
				else
					tp = &sjcd_table_of_contents
					    [toc_entry.cdte_track];

				toc_entry.cdte_adr =
				    tp->track_control & 0x0F;
				toc_entry.cdte_ctrl =
				    tp->track_control >> 4;

				switch (toc_entry.cdte_format) {
				case CDROM_LBA:
					toc_entry.cdte_addr.lba =
					    msf2hsg(&(tp->un.track_msf));
					break;
				case CDROM_MSF:
					toc_entry.cdte_addr.msf.minute =
					    bcd2bin(tp->un.track_msf.min);
					toc_entry.cdte_addr.msf.second =
					    bcd2bin(tp->un.track_msf.sec);
					toc_entry.cdte_addr.msf.frame =
					    bcd2bin(tp->un.track_msf.
						    frame);
					break;
				default:
					return (-EINVAL);
				}
				copy_to_user((void *) arg, &toc_entry,
					     sizeof(toc_entry));
			}
			return (s);
		}

	case CDROMSUBCHNL:{
			struct cdrom_subchnl subchnl;
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: subchnl\n");
#endif
			if ((s =
			     verify_area(VERIFY_WRITE, (void *) arg,
					 sizeof(subchnl))) == 0) {
				struct sjcd_hw_qinfo q_info;

				copy_from_user(&subchnl, (void *) arg,
					       sizeof(subchnl));
				if (sjcd_get_q_info(&q_info) < 0)
					return (-EIO);

				subchnl.cdsc_audiostatus =
				    sjcd_audio_status;
				subchnl.cdsc_adr =
				    q_info.track_control & 0x0F;
				subchnl.cdsc_ctrl =
				    q_info.track_control >> 4;
				subchnl.cdsc_trk =
				    bcd2bin(q_info.track_no);
				subchnl.cdsc_ind = bcd2bin(q_info.x);

				switch (subchnl.cdsc_format) {
				case CDROM_LBA:
					subchnl.cdsc_absaddr.lba =
					    msf2hsg(&(q_info.abs));
					subchnl.cdsc_reladdr.lba =
					    msf2hsg(&(q_info.rel));
					break;
				case CDROM_MSF:
					subchnl.cdsc_absaddr.msf.minute =
					    bcd2bin(q_info.abs.min);
					subchnl.cdsc_absaddr.msf.second =
					    bcd2bin(q_info.abs.sec);
					subchnl.cdsc_absaddr.msf.frame =
					    bcd2bin(q_info.abs.frame);
					subchnl.cdsc_reladdr.msf.minute =
					    bcd2bin(q_info.rel.min);
					subchnl.cdsc_reladdr.msf.second =
					    bcd2bin(q_info.rel.sec);
					subchnl.cdsc_reladdr.msf.frame =
					    bcd2bin(q_info.rel.frame);
					break;
				default:
					return (-EINVAL);
				}
				copy_to_user((void *) arg, &subchnl,
					     sizeof(subchnl));
			}
			return (s);
		}

	case CDROMVOLCTRL:{
			struct cdrom_volctrl vol_ctrl;
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: volctrl\n");
#endif
			if ((s =
			     verify_area(VERIFY_READ, (void *) arg,
					 sizeof(vol_ctrl))) == 0) {
				unsigned char dummy[4];

				copy_from_user(&vol_ctrl, (void *) arg,
					       sizeof(vol_ctrl));
				sjcd_send_4_cmd(SCMD_SET_VOLUME,
						vol_ctrl.channel0, 0xFF,
						vol_ctrl.channel1, 0xFF);
				if (sjcd_receive_status() < 0)
					return (-EIO);
				(void) sjcd_load_response(dummy, 4);
			}
			return (s);
		}

	case CDROMEJECT:{
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: eject\n");
#endif
			if (!sjcd_command_is_in_progress) {
				sjcd_tray_unlock();
				sjcd_send_cmd(SCMD_EJECT_TRAY);
				(void) sjcd_receive_status();
			}
			return (0);
		}

#if defined( SJCD_GATHER_STAT )
	case 0xABCD:{
			int s;
#if defined( SJCD_TRACE )
			printk("SJCD: ioctl: statistic\n");
#endif
			if ((s =
			     verify_area(VERIFY_WRITE, (void *) arg,
					 sizeof(statistic))) == 0)
				copy_to_user((void *) arg, &statistic,
					     sizeof(statistic));
			return (s);
		}
#endif

	default:
		return (-EINVAL);
	}
}

/*
 * Invalidate internal buffers of the driver.
 */
static void sjcd_invalidate_buffers(void)
{
	int i;
	for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1);
	sjcd_buf_out = -1;
}

/*
 * Take care of the different block sizes between cdrom and Linux.
 * When Linux gets variable block sizes this will probably go away.
 */

#define CURRENT_IS_VALID                                      \
    ( !QUEUE_EMPTY && MAJOR( CURRENT->rq_dev ) == MAJOR_NR && \
      CURRENT->cmd == READ && CURRENT->sector != -1 )

static void sjcd_transfer(void)
{
#if defined( SJCD_TRACE )
	printk("SJCD: transfer:\n");
#endif
	if (CURRENT_IS_VALID) {
		while (CURRENT->nr_sectors) {
			int i, bn = CURRENT->sector / 4;
			for (i = 0;
			     i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn;
			     i++);
			if (i < SJCD_BUF_SIZ) {
				int offs =
				    (i * 4 + (CURRENT->sector & 3)) * 512;
				int nr_sectors = 4 - (CURRENT->sector & 3);
				if (sjcd_buf_out != i) {
					sjcd_buf_out = i;
					if (sjcd_buf_bn[i] != bn) {
						sjcd_buf_out = -1;
						continue;
					}
				}
				if (nr_sectors > CURRENT->nr_sectors)
					nr_sectors = CURRENT->nr_sectors;
#if defined( SJCD_TRACE )
				printk("SJCD: copy out\n");
#endif
				memcpy(CURRENT->buffer, sjcd_buf + offs,
				       nr_sectors * 512);
				CURRENT->nr_sectors -= nr_sectors;
				CURRENT->sector += nr_sectors;
				CURRENT->buffer += nr_sectors * 512;
			} else {
				sjcd_buf_out = -1;
				break;
			}
		}
	}
#if defined( SJCD_TRACE )
	printk("SJCD: transfer: done\n");
#endif
}

static void sjcd_poll(void)
{
#if defined( SJCD_GATHER_STAT )
	/*
	 * Update total number of ticks.
	 */
	statistic.ticks++;
	statistic.tticks[sjcd_transfer_state]++;
#endif

      ReSwitch:switch (sjcd_transfer_state) {

	case SJCD_S_IDLE:{
#if defined( SJCD_GATHER_STAT )
			statistic.idle_ticks++;
#endif
#if defined( SJCD_TRACE )
			printk("SJCD_S_IDLE\n");
#endif
			return;
		}

	case SJCD_S_START:{
#if defined( SJCD_GATHER_STAT )
			statistic.start_ticks++;
#endif
			sjcd_send_cmd(SCMD_GET_STATUS);
			sjcd_transfer_state =
			    sjcd_mode ==
			    SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE;
			sjcd_transfer_timeout = 500;
#if defined( SJCD_TRACE )
			printk("SJCD_S_START: goto SJCD_S_%s mode\n",
			       sjcd_transfer_state ==
			       SJCD_S_READ ? "READ" : "MODE");
#endif
			break;
		}

	case SJCD_S_MODE:{
			if (sjcd_check_status()) {
				/*
				 * Previous command is completed.
				 */
				if (!sjcd_status_valid
				    || sjcd_command_failed) {
#if defined( SJCD_TRACE )
					printk
					    ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n");
#endif
					sjcd_transfer_state = SJCD_S_STOP;
					goto ReSwitch;
				}

				sjcd_mode = 0;	/* unknown mode; should not be valid when failed */
				sjcd_send_1_cmd(SCMD_SET_MODE,
						SCMD_MODE_COOKED);
				sjcd_transfer_state = SJCD_S_READ;
				sjcd_transfer_timeout = 1000;
#if defined( SJCD_TRACE )
				printk
				    ("SJCD_S_MODE: goto SJCD_S_READ mode\n");
#endif
			}
#if defined( SJCD_GATHER_STAT )
			else
				statistic.mode_ticks++;
#endif
			break;
		}

	case SJCD_S_READ:{
			if (sjcd_status_valid ? 1 : sjcd_check_status()) {
				/*
				 * Previous command is completed.
				 */
				if (!sjcd_status_valid
				    || sjcd_command_failed) {
#if defined( SJCD_TRACE )
					printk
					    ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n");
#endif
					sjcd_transfer_state = SJCD_S_STOP;
					goto ReSwitch;
				}
				if (!sjcd_media_is_available) {
#if defined( SJCD_TRACE )
					printk
					    ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n");
#endif
					sjcd_transfer_state = SJCD_S_STOP;
					goto ReSwitch;
				}
				if (sjcd_mode != SCMD_MODE_COOKED) {
					/*
					 * We seem to come from set mode. So discard one byte of result.
					 */
					if (sjcd_load_response
					    (&sjcd_mode, 1) != 0) {
#if defined( SJCD_TRACE )
						printk
						    ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n");

⌨️ 快捷键说明

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