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

📄 cm206.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
    cd->adapter_last = -1;	/* invalidate adapter memory */    cd->sector_last = -1;  }  ++cd->openfiles;  stats(open);  return 0;}static void cm206_release(struct cdrom_device_info * cdi){  if (cd->openfiles==1) {    if (cd->background) {      cd->background=0;      stop_read();    }    cd->sector_last = -1;	/* Make our internal buffer invalid */    FIRST_TRACK = 0;		/* No valid disc status */  }  --cd->openfiles;  MOD_DEC_USE_COUNT;}/* Empty buffer empties $sectors$ sectors of the adapter card buffer, * and then reads a sector in kernel memory.  */void empty_buffer(int sectors) {  while (sectors>=0) {    transport_data(r_fifo_output_buffer, cd->sector + cd->fifo_overflowed, 	 RAW_SECTOR_SIZE/2 - cd->fifo_overflowed);    --sectors;    ++cd->adapter_first;	/* update the current adapter sector */    cd->fifo_overflowed=0;	/* reset overflow bit */    stats(sector_transferred);  }   cd->sector_first=cd->adapter_first-1;  cd->sector_last=cd->adapter_first; /* update the buffer sector */}/* try_adapter. This function determines if the requested sector is   in adapter memory, or will appear there soon. Returns 0 upon   success */int try_adapter(int sector){  if (cd->adapter_first <= sector && sector < cd->adapter_last) {     /* sector is in adapter memory */    empty_buffer(sector - cd->adapter_first);    return 0;  }  else if (cd->background==1 && cd->adapter_first <= sector	   && sector < cd->adapter_first+cd->max_sectors) {    /* a read is going on, we can wait for it */    cd->wait_back=1;    while (sector >= cd->adapter_last) {      if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {	debug(("Timed out during background wait: %d %d %d %d\n", sector, 	       cd->adapter_last, cd->adapter_first, cd->background));	stats(back_read_timeout);	cd->wait_back=0;	return -1;      }    }    cd->wait_back=0;    empty_buffer(sector - cd->adapter_first);    return 0;  }  else return -2;}/* This is not a very smart implementation. We could optimize for    consecutive block numbers. I'm not convinced this would really   bring down the processor load. */static void do_cm206_request(request_queue_t * q){  long int i, cd_sec_no;  int quarter, error;   uch * source, * dest;    while(1) {	 /* repeat until all requests have been satisfied */    INIT_REQUEST;    if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)      return;    if (CURRENT->cmd != READ) {      debug(("Non-read command %d on cdrom\n", CURRENT->cmd));      end_request(0);      continue;    }    spin_unlock_irq(&io_request_lock);    error=0;    for (i=0; i<CURRENT->nr_sectors; i++) {      int e1, e2;      cd_sec_no = (CURRENT->sector+i)/BLOCKS_ISO; /* 4 times 512 bytes */      quarter = (CURRENT->sector+i) % BLOCKS_ISO;       dest = CURRENT->buffer + i*LINUX_BLOCK_SIZE;      /* is already in buffer memory? */      if (cd->sector_first <= cd_sec_no && cd_sec_no < cd->sector_last) {	source = ((uch *) cd->sector) + 16 + quarter*LINUX_BLOCK_SIZE 	  + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE; 	memcpy(dest, source, LINUX_BLOCK_SIZE);       }      else if (!(e1=try_adapter(cd_sec_no)) || 	       !(e2=read_sector(cd_sec_no))) {	source =  ((uch *) cd->sector)+16+quarter*LINUX_BLOCK_SIZE;	memcpy(dest, source, LINUX_BLOCK_SIZE);       }      else {	error=1;	debug(("cm206_request: %d %d\n", e1, e2));      }    }    spin_lock_irq(&io_request_lock);    end_request(!error);  }}/* Audio support. I've tried very hard, but the cm206 drive doesn't    seem to have a get_toc (table-of-contents) function, while i'm   pretty sure it must read the toc upon disc insertion. Therefore   this function has been implemented through a binary search    strategy. All track starts that happen to be found are stored in   cd->toc[], for future use.    I've spent a whole day on a bug that only shows under Workman---   I don't get it. Tried everything, nothing works. If workman asks   for track# 0xaa, it'll get the wrong time back. Any other program   receives the correct value. I'm stymied.*//* seek seeks to address lba. It does wait to arrive there. */void seek(int lba){  int i;  uch seek_command[4]={c_seek, };    fsm(lba, &seek_command[1]);  for (i=0; i<4; i++) type_0_command(seek_command[i], 0);  cd->dsb = wait_dsb();}uch bcdbin(unsigned char bcd)	/* stolen from mcd.c! */{  return (bcd >> 4)*10 + (bcd & 0xf);} inline uch normalize_track(uch track) {  if (track<1) return 1;  if (track>LAST_TRACK) return LAST_TRACK+1;  return track;}/* This function does a binary search for track start. It records all * tracks seen in the process. Input $track$ must be between 1 and * #-of-tracks+1.  Note that the start of the disc must be in toc[1].fsm.  */int get_toc_lba(uch track){  int max=74*60*75-150, min=fsm2lba(cd->toc[1].fsm);  int i, lba, l, old_lba=0;  uch * q = cd->q;  uch ct;			/* current track */  int binary=0;  const int skip = 3*60*75;		/* 3 minutes */  for (i=track; i>0; i--) if (cd->toc[i].track) {    min = fsm2lba(cd->toc[i].fsm);    break;  }  lba = min + skip;  do {    seek(lba);     type_1_command(c_read_current_q, 10, q);    ct = normalize_track(q[1]);    if (!cd->toc[ct].track) {      l = q[9]-bcdbin(q[5]) + 75*(q[8]-bcdbin(q[4])-2 + 				  60*(q[7]-bcdbin(q[3])));      cd->toc[ct].track=q[1];	/* lead out still 0xaa */      fsm(l, cd->toc[ct].fsm);      cd->toc[ct].q0 = q[0];	/* contains adr and ctrl info */      if (ct==track) return l;    }    old_lba=lba;    if (binary) {      if (ct < track) min = lba; else max = lba;      lba = (min+max)/2;     } else {      if(ct < track) lba += skip;      else {	binary=1;	max = lba; min = lba - skip;	lba = (min+max)/2;      }    }  } while (lba!=old_lba);  return lba;}void update_toc_entry(uch track) {  track = normalize_track(track);  if (!cd->toc[track].track) get_toc_lba(track);}/* return 0 upon success */int read_toc_header(struct cdrom_tochdr * hp){  if (!FIRST_TRACK) get_disc_status();  if (hp) {     int i;    hp->cdth_trk0 = FIRST_TRACK;    hp->cdth_trk1 = LAST_TRACK; 				/* fill in first track position */    for (i=0; i<3; i++) cd->toc[1].fsm[i] = cd->disc_status[3+i];    update_toc_entry(LAST_TRACK+1);		/* find most entries */    return 0;  }  return -1;}  void play_from_to_msf(struct cdrom_msf* msfp){  uch play_command[] = {c_play, 	   msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0,	   msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2, 2};  int i;  for (i=0; i<9; i++) type_0_command(play_command[i], 0);  for (i=0; i<3; i++)     PLAY_TO.fsm[i] = play_command[i+4];  PLAY_TO.track = 0;		/* say no track end */  cd->dsb = wait_dsb();}  void play_from_to_track(int from, int to){  uch play_command[8] = {c_play, };  int i;  if (from==0) {		/* continue paused play */    for (i=0; i<3; i++) {       play_command[i+1] = cd->audio_status[i+2];      play_command[i+4] = PLAY_TO.fsm[i];    }  } else {    update_toc_entry(from); update_toc_entry(to+1);    for (i=0; i<3; i++) {      play_command[i+1] = cd->toc[from].fsm[i];      PLAY_TO.fsm[i] = play_command[i+4] = cd->toc[to+1].fsm[i];    }    PLAY_TO.track = to;   }  for (i=0; i<7; i++) type_0_command(play_command[i],0);  for (i=0; i<2; i++) type_0_command(0x2, 0); /* volume */  cd->dsb = wait_dsb();}int get_current_q(struct cdrom_subchnl * qp){  int i;  uch * q = cd->q;  if (type_1_command(c_read_current_q, 10, q)) return 0;/*  q[0] = bcdbin(q[0]); Don't think so! */  for (i=2; i<6; i++) q[i]=bcdbin(q[i]);   qp->cdsc_adr = q[0] & 0xf; qp->cdsc_ctrl = q[0] >> 4;	/* from mcd.c */  qp->cdsc_trk = q[1];  qp->cdsc_ind = q[2];  if (qp->cdsc_format == CDROM_MSF) {    qp->cdsc_reladdr.msf.minute = q[3];    qp->cdsc_reladdr.msf.second = q[4];    qp->cdsc_reladdr.msf.frame = q[5];    qp->cdsc_absaddr.msf.minute = q[7];    qp->cdsc_absaddr.msf.second = q[8];    qp->cdsc_absaddr.msf.frame = q[9];  } else {    qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]);    qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]);  }  get_drive_status();  if (cd->dsb & dsb_play_in_progress)     qp->cdsc_audiostatus = CDROM_AUDIO_PLAY ;  else if (PAUSED)     qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED;  else qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS;  return 0;}void invalidate_toc(void){  memset(cd->toc, 0, sizeof(cd->toc));  memset(cd->disc_status, 0, sizeof(cd->disc_status));}/* cdrom.c guarantees that cdte_format == CDROM_MSF */void get_toc_entry(struct cdrom_tocentry * ep){  uch track = normalize_track(ep->cdte_track);  update_toc_entry(track);  ep->cdte_addr.msf.frame = cd->toc[track].fsm[0];  ep->cdte_addr.msf.second = cd->toc[track].fsm[1];  ep->cdte_addr.msf.minute = cd->toc[track].fsm[2];  ep->cdte_adr = cd->toc[track].q0 & 0xf;   ep->cdte_ctrl = cd->toc[track].q0 >> 4;  ep->cdte_datamode=0;}/* Audio ioctl.  Ioctl commands connected to audio are in such an * idiosyncratic i/o format, that we leave these untouched. Return 0 * upon success. Memory checking has been done by cdrom_ioctl(), the * calling function, as well as LBA/MSF sanitization.*/int cm206_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd, 		      void * arg)  {  switch (cmd) {  case CDROMREADTOCHDR:     return read_toc_header((struct cdrom_tochdr *) arg);  case CDROMREADTOCENTRY: 	    get_toc_entry((struct cdrom_tocentry *) arg);    return 0;  case CDROMPLAYMSF:     play_from_to_msf((struct cdrom_msf *) arg);    return 0;  case CDROMPLAYTRKIND:		/* admittedly, not particularly beautiful */    play_from_to_track(((struct cdrom_ti *)arg)->cdti_trk0, 		       ((struct cdrom_ti *)arg)->cdti_trk1);    return 0;  case CDROMSTOP:     PAUSED=0;    if (cd->dsb & dsb_play_in_progress) return type_0_command(c_stop, 1);    else return 0;  case CDROMPAUSE:     get_drive_status();    if (cd->dsb & dsb_play_in_progress) {      type_0_command(c_stop, 1);      type_1_command(c_audio_status, 5, cd->audio_status);      PAUSED=1;	/* say we're paused */    }    return 0;  case CDROMRESUME:    if (PAUSED) play_from_to_track(0,0);    PAUSED=0;    return 0;  case CDROMSTART:  case CDROMVOLCTRL:    return 0;  case CDROMSUBCHNL:     return get_current_q((struct cdrom_subchnl *)arg);  default:    return -EINVAL;  }}/* Ioctl. These ioctls are specific to the cm206 driver. I have made   some driver statistics accessible through ioctl calls. */static int cm206_ioctl(struct cdrom_device_info * cdi, unsigned int cmd, 		       unsigned long arg){  switch (cmd) {#ifdef STATISTICS  case CM206CTL_GET_STAT:    if (arg >= NR_STATS) return -EINVAL;    else return cd->stats[arg];  case CM206CTL_GET_LAST_STAT:    if (arg >= NR_STATS) return -EINVAL;    else return cd->last_stat[arg];#endif      default:    debug(("Unknown ioctl call 0x%x\n", cmd));    return -EINVAL;  }}     

⌨️ 快捷键说明

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