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

📄 sjcd.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
    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 + -