📄 sjcd.c
字号:
#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 + -