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

📄 cm206.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
      del_timer(&cd->timer);      wake_up_interruptible(&cd->uart);    }  }  /* data ready in fifo? */  else if (cd->intr_ds & ds_data_ready) {     if (cd->background) ++cd->adapter_last;    if (waitqueue_active(&cd->data) && (cd->wait_back || !cd->background)) {      del_timer(&cd->timer);      wake_up_interruptible(&cd->data);    }    stats(data_ready);  }  /* ready to issue a write command? */  else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) {    outw(dc_normal | (inw(r_data_status) & 0x7f), r_data_control);    outw(cd->command, r_uart_transmit);    cd->command=0;    if (!cd->background) wake_up_interruptible(&cd->uart);  }  /* now treat errors (at least, identify them for debugging) */  else if (cd->intr_ds & ds_fifo_overflow) {    debug(("Fifo overflow at sectors 0x%x\n", cd->sector_first));    fool = inw(r_fifo_output_buffer);	/* de-assert the interrupt */    cd->fifo_overflowed=1;	/* signal one word less should be read */    stats(fifo_overflow);  }  else if (cd->intr_ds & ds_data_error) {    debug(("Data error at sector 0x%x\n", cd->sector_first));    stats(data_error);  }  else if (cd->intr_ds & ds_crc_error) {    debug(("CRC error at sector 0x%x\n", cd->sector_first));    stats(crc_error);  }  else if (cd->intr_ds & ds_sync_error) {    debug(("Sync at sector 0x%x\n", cd->sector_first));    stats(sync_error);  }  else if (cd->intr_ds & ds_toc_ready) {    /* do something appropriate */  }  /* couldn't see why this interrupt, maybe due to init */  else {			    outw(dc_normal | READ_AHEAD, r_data_control);    stats(lost_intr);  }  if (cd->background && (cd->adapter_last-cd->adapter_first == cd->max_sectors			 || cd->fifo_overflowed))    mark_bh(CM206_BH);	/* issue a stop read command */  stats(interrupt);}/* we have put the address of the wait queue in who */void cm206_timeout(unsigned long who){  cd->timed_out = 1;  debug(("Timing out\n"));  wake_up_interruptible((wait_queue_head_t *)who);}/* This function returns 1 if a timeout occurred, 0 if an interrupt   happened */int sleep_or_timeout(wait_queue_head_t *wait, int timeout){  cd->timed_out=0;  cd->timer.data=(unsigned long) wait;  cd->timer.expires = jiffies + timeout;  add_timer(&cd->timer);  debug(("going to sleep\n"));  interruptible_sleep_on(wait);  del_timer(&cd->timer);  if (cd->timed_out) {    cd->timed_out = 0;    return 1;  }  else return 0;}void cm206_delay(int nr_jiffies) {  DECLARE_WAIT_QUEUE_HEAD(wait);  sleep_or_timeout(&wait, nr_jiffies);}void send_command(int command){  debug(("Sending 0x%x\n", command));  if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) {    cd->command = command;    cli();			/* don't interrupt before sleep */    outw(dc_mask_sync_error | dc_no_stop_on_error | 	 (inw(r_data_status) & 0x7f), r_data_control);    /* interrupt routine sends command */    if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) {      debug(("Time out on write-buffer\n"));      stats(write_timeout);      outw(command, r_uart_transmit);    }    debug(("Write commmand delayed\n"));  }  else outw(command, r_uart_transmit);}uch receive_byte(int timeout){  uch ret;  cli();  debug(("cli\n"));  ret = cd->ur[cd->ur_r];  if (cd->ur_r != cd->ur_w) {    sti();    debug(("returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r]));    cd->ur_r++; cd->ur_r %= UR_SIZE;    return ret;  }   else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */    debug(("Time out on receive-buffer\n"));#ifdef STATISTICS    if (timeout==UART_TIMEOUT) stats(receive_timeout) /* no `;'! */    else stats(dsb_timeout);#endif    return 0xda;  }  ret = cd->ur[cd->ur_r];    debug(("slept; returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r]));  cd->ur_r++; cd->ur_r %= UR_SIZE;  return ret;}inline uch receive_echo(void){  return receive_byte(UART_TIMEOUT);}inline uch send_receive(int command){  send_command(command);  return receive_echo();}inline uch wait_dsb(void){  return receive_byte(DSB_TIMEOUT);}int type_0_command(int command, int expect_dsb){  int e;  clear_ur();  if (command != (e=send_receive(command))) {    debug(("command 0x%x echoed as 0x%x\n", command, e));    stats(echo);    return -1;  }  if (expect_dsb) {    cd->dsb = wait_dsb();	/* wait for command to finish */  }  return 0;}int type_1_command(int command, int bytes, uch * status) /* returns info */{  int i;  if (type_0_command(command,0)) return -1;  for(i=0; i<bytes; i++)     status[i] = send_receive(c_gimme);  return 0;}  /* This function resets the adapter card. We'd better not do this too * often, because it tends to generate `lost interrupts.' */void reset_cm260(void){  outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control);  udelay(10);			/* 3.3 mu sec minimum */  outw(dc_normal | READ_AHEAD, r_data_control);}/* fsm: frame-sec-min from linear address; one of many */void fsm(int lba, uch * fsm) {  fsm[0] = lba % 75;  lba /= 75; lba += 2;  fsm[1] = lba % 60; fsm[2] = lba / 60;}inline int fsm2lba(uch * fsm) {  return fsm[0] + 75*(fsm[1]-2 + 60*fsm[2]);}inline int f_s_m2lba(uch f, uch s, uch m){  return f + 75*(s-2 + 60*m);}int start_read(int start) {  uch read_sector[4] = {c_read_data, };  int i, e;  fsm(start, &read_sector[1]);  clear_ur();  for (i=0; i<4; i++)     if (read_sector[i] != (e=send_receive(read_sector[i]))) {      debug(("read_sector: %x echoes %x\n", read_sector[i], e));      stats(echo);      if (e==0xff) {		/* this seems to happen often */	e = receive_echo();	debug(("Second try %x\n", e));	if (e!=read_sector[i]) return -1;      }    }  return 0;}int stop_read(void){  int e;  type_0_command(c_stop,0);  if((e=receive_echo()) != 0xff) {    debug(("c_stop didn't send 0xff, but 0x%x\n", e));    stats(stop_0xff);    return -1;  }  return 0;}  /* This function starts to read sectors in adapter memory, the   interrupt routine should stop the read. In fact, the bottom_half   routine takes care of this. Set a flag `background' in the cd   struct to indicate the process. */int read_background(int start, int reading){  if (cd->background) return -1; /* can't do twice */  outw(dc_normal | BACK_AHEAD, r_data_control);  if (!reading && start_read(start)) return -2;  cd->adapter_first = cd->adapter_last = start;   cd->background = 1;		/* flag a read is going on */  return 0;}#ifdef USE_INSW#define transport_data insw#else/* this routine implements insw(,,). There was a time i had the   impression that there would be any difference in error-behaviour. */void transport_data(int port, ush * dest, int count) {  int i;  ush * d;  for (i=0, d=dest; i<count; i++, d++)     *d = inw(port);}#endif#define MAX_TRIES 100int read_sector(int start){  int tries=0;  if (cd->background) {    cd->background=0;    cd->adapter_last = -1;	/* invalidate adapter memory */    stop_read();  }  cd->fifo_overflowed=0;  reset_cm260();		/* empty fifo etc. */  if (start_read(start)) return -1;  do {    if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {      debug(("Read timed out sector 0x%x\n", start));      stats(read_timeout);      stop_read();      return -3;		    }     tries++;  } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES);  if (tries>1) debug(("Took me some tries\n"))  else if (tries == MAX_TRIES)     debug(("MAX_TRIES tries for read sector\n"));  transport_data(r_fifo_output_buffer, cd->sector, 		 READ_AHEAD*RAW_SECTOR_SIZE/2);  if (read_background(start+READ_AHEAD,1)) stats(read_background);  cd->sector_first = start; cd->sector_last = start+READ_AHEAD;  stats(read_restarted);  return 0;}/* The function of bottom-half is to send a stop command to the drive   This isn't easy because the routine is not `owned' by any process;   we can't go to sleep! The variable cd->background gives the status:   0 no read pending   1 a read is pending   2 c_stop waits for write_buffer_empty   3 c_stop waits for receive_buffer_full: echo   4 c_stop waits for receive_buffer_full: 0xff*/void cm206_bh(void){  debug(("bh: %d\n", cd->background));  switch (cd->background) {  case 1:    stats(bh);    if (!(cd->intr_ls & ls_transmitter_buffer_empty)) {      cd->command = c_stop;      outw(dc_mask_sync_error | dc_no_stop_on_error | 	   (inw(r_data_status) & 0x7f), r_data_control);      cd->background=2;      break;			/* we'd better not time-out here! */    }    else outw(c_stop, r_uart_transmit);    /* fall into case 2: */  case 2:			    /* the write has been satisfied by interrupt routine */    cd->background=3;    break;  case 3:    if (cd->ur_r != cd->ur_w) {      if (cd->ur[cd->ur_r] != c_stop) {	debug(("cm206_bh: c_stop echoed 0x%x\n", cd->ur[cd->ur_r]));	stats(echo);      }      cd->ur_r++; cd->ur_r %= UR_SIZE;    }    cd->background++;    break;  case 4:    if (cd->ur_r != cd->ur_w) {      if (cd->ur[cd->ur_r] != 0xff) {	debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r]));	stats(stop_0xff);      }      cd->ur_r++; cd->ur_r %= UR_SIZE;    }    cd->background=0;  }}/* This command clears the dsb_possible_media_change flag, so we must  * retain it. */void get_drive_status(void){  uch status[2];  type_1_command(c_drive_status, 2, status); /* this might be done faster */  cd->dsb=status[0];  cd->cc=status[1];  cd->media_changed |=     !!(cd->dsb & (dsb_possible_media_change | 		  dsb_drive_not_ready | dsb_tray_not_closed));}void get_disc_status(void){  if (type_1_command(c_disc_status, 7, cd->disc_status)) {    debug(("get_disc_status: error\n"));  }}/* The new open. The real opening strategy is defined in cdrom.c. */static int cm206_open(struct cdrom_device_info * cdi, int purpose) {  MOD_INC_USE_COUNT;  if (!cd->openfiles) {		/* reset only first time */    cd->background=0;    reset_cm260();

⌨️ 快捷键说明

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