📄 sjcd.c
字号:
if( !sjcd_command_failed ){ if( sjcd_load_response( &sjcd_table_of_contents[ i ], sizeof( struct sjcd_hw_disk_info ) ) != 0 ){ printk( "SJCD: cannot load info for %d track\n", i ); return( -1 ); } } else { printk( "SJCD: get info %d failed\n", i ); return( -1 ); } } /* * Get the disk length info. */ sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE ); sjcd_receive_status(); if( !sjcd_status_valid ){ printk( "SJCD: cannot load status.\n" ); return( -1 ); } if( !sjcd_media_is_available ){ printk( "SJCD: no disk in drive\n" ); return( -1 ); } if( !sjcd_command_failed ){ if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){ printk( "SJCD: cannot load response about disk size.\n" ); return( -1 ); } sjcd_disk_length.min = info.un.track_msf.min; sjcd_disk_length.sec = info.un.track_msf.sec; sjcd_disk_length.frame = info.un.track_msf.frame; } else { printk( "SJCD: get size failed\n" ); return( 1 ); }#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" );#endif sjcd_transfer_state = SJCD_S_STOP; goto ReSwitch;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -