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

📄 cdu31a.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 4 页
字号:
    * how many more status bytes are coming.    *    * The result register can be read 10 bytes at a time, a wait for    * result ready to be asserted must be done between every 10 bytes.    */   if ((a & 0xf0) != 0x20)   {      if (b > 8)      {         for (i=0; i<8; i++)         {            *result_buffer = read_result_register();            result_buffer++;            (*result_size)++;         }         b = b - 8;         while (b > 10)         {            retry_count = SONY_READY_RETRIES;            while ((retry_count > 0) && (!is_result_ready()))            {               retry_count--;            }            if (!is_result_ready())            {               result_buffer[0] = 0x20;               result_buffer[1] = SONY_TIMEOUT_OP_ERR;               *result_size = 2;               return;            }            clear_result_ready();                                            for (i=0; i<10; i++)            {               *result_buffer = read_result_register();               result_buffer++;               (*result_size)++;            }            b = b - 10;         }         if (b > 0)         {            retry_count = SONY_READY_RETRIES;            while ((retry_count > 0) && (!is_result_ready()))            {               retry_count--;            }            if (!is_result_ready())            {               result_buffer[0] = 0x20;               result_buffer[1] = SONY_TIMEOUT_OP_ERR;               *result_size = 2;               return;            }         }      }      while (b > 0)      {         *result_buffer = read_result_register();         result_buffer++;         (*result_size)++;         b--;      }   }}/* * Read in a 2048 byte block of data. */static voidread_data_block(unsigned char *data,                unsigned char *result_buffer,                unsigned int  *result_size){   int i;   unsigned int retry_count;   for (i=0; i<2048; i++)   {      retry_count = jiffies + SONY_JIFFIES_TIMEOUT;      while ((retry_count > jiffies) && (!is_data_requested()))      {         while (handle_sony_cd_attention())            ;                  sony_sleep();      }      if (!is_data_requested())      {         result_buffer[0] = 0x20;         result_buffer[1] = SONY_TIMEOUT_OP_ERR;         *result_size = 2;         return;      }            *data = read_data_register();      data++;   }}/* * This routine issues a read data command and gets the data.  I don't * really like the way this is done (I would prefer for do_sony_cmd() to * handle it automatically) but I found that the drive returns status * when it finishes reading (not when the host has read all the data) * or after it gets an error.  This means that the status can be * received at any time and should be handled immediately (at least * between every 2048 byte block) to check for errors, we can't wait * until all the data is read. * * This routine returns the total number of sectors read.  It will * not return an error if it reads at least one sector successfully. */static unsigned intget_data(unsigned char *orig_data,         unsigned char *params,         /* 6 bytes with the MSF start address                                           and number of sectors to read. */         unsigned int orig_data_size,         unsigned char *result_buffer,         unsigned int *result_size){   unsigned int cur_offset;   unsigned int retry_count;   int result_read;   int num_retries;   unsigned int num_sectors_read = 0;   unsigned char *data = orig_data;   unsigned int data_size = orig_data_size;   cli();   while (sony_inuse)   {      interruptible_sleep_on(&sony_wait);      if (current->signal & ~current->blocked)      {         result_buffer[0] = 0x20;         result_buffer[1] = SONY_SIGNAL_OP_ERR;         *result_size = 2;         return 0;      }   }   sony_inuse = 1;   has_cd_task = current;   sti();   num_retries = 0;retry_data_operation:   result_buffer[0] = 0;   result_buffer[1] = 0;   /*    * Clear any outstanding attentions and wait for the drive to    * complete any pending operations.    */   while (handle_sony_cd_attention())      ;   retry_count = jiffies + SONY_JIFFIES_TIMEOUT;   while ((retry_count > jiffies) && (is_busy()))   {      sony_sleep();            while (handle_sony_cd_attention())         ;   }   if (is_busy())   {      result_buffer[0] = 0x20;      result_buffer[1] = SONY_TIMEOUT_OP_ERR;      *result_size = 2;   }   else   {      /* Issue the command */      clear_result_ready();      clear_param_reg();      write_params(params, 6);      write_cmd(SONY_READ_CMD);      /*       * Read the data from the drive one 2048 byte sector at a time.  Handle       * any results received between sectors, if an error result is returned       * terminate the operation immediately.       */      cur_offset = 0;      result_read = 0;      while ((data_size > 0) && (result_buffer[0] == 0))      {         /* Wait for the drive to tell us we have something */         retry_count = jiffies + SONY_JIFFIES_TIMEOUT;         while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready())))         {            while (handle_sony_cd_attention())               ;            sony_sleep();         }         if (!(is_result_ready() || is_data_ready()))         {            result_buffer[0] = 0x20;            result_buffer[1] = SONY_TIMEOUT_OP_ERR;            *result_size = 2;         }               /* Handle results first */         else if (is_result_ready())         {            result_read = 1;            get_result(result_buffer, result_size);         }         else /* Handle data next */         {            /*             * The drive has to be polled for status on a byte-by-byte basis             * to know if the data is ready.  Yuck.  I really wish I could use DMA.             */            clear_data_ready();            read_data_block(data, result_buffer, result_size);            data += 2048;            data_size -= 2048;            cur_offset = cur_offset + 2048;            num_sectors_read++;         }      }      /* Make sure the result has been read */      if (!result_read)      {         get_result(result_buffer, result_size);      }   }   if (   ((result_buffer[0] & 0x20) == 0x20)       && (result_buffer[1] != SONY_NOT_SPIN_ERR) /* No retry when not spin */       && (num_retries < MAX_CDU31A_RETRIES))   {      /*       * If an error occurs, go back and only read one sector at the       * given location.  Hopefully the error occurred on an unused       * sector after the first one.  It is hard to say which sector       * the error occurred on because the drive returns status before       * the data transfer is finished and doesn't say which sector.       */      data_size = 2048;      data = orig_data;      num_sectors_read = 0;      size_to_buf(1, &params[3]);      num_retries++;      /* Issue a reset on an error (the second time), othersize just delay */      if (num_retries == 2)      {         restart_on_error();      }      else      {         current->state = TASK_INTERRUPTIBLE;         current->timeout = jiffies + 10;         schedule();      }      /* Restart the operation. */      goto retry_data_operation;   }   has_cd_task = NULL;   sony_inuse = 0;   wake_up_interruptible(&sony_wait);   return(num_sectors_read);}/* * Do a command that does not involve data transfer.  This routine must * be re-entrant from the same task to support being called from the * data operation code when an error occurs. */static voiddo_sony_cd_cmd(unsigned char cmd,               unsigned char *params,               unsigned int num_params,               unsigned char *result_buffer,               unsigned int *result_size){   unsigned int retry_count;   int num_retries;   int recursive_call;   cli();   if (current != has_cd_task) /* Allow recursive calls to this routine */   {      while (sony_inuse)      {         interruptible_sleep_on(&sony_wait);         if (current->signal & ~current->blocked)         {            result_buffer[0] = 0x20;            result_buffer[1] = SONY_SIGNAL_OP_ERR;            *result_size = 2;            return;         }      }      sony_inuse = 1;      has_cd_task = current;      recursive_call = 0;   }   else   {      recursive_call = 1;   }   sti();   num_retries = 0;retry_cd_operation:   while (handle_sony_cd_attention())      ;      retry_count = jiffies + SONY_JIFFIES_TIMEOUT;   while ((retry_count > jiffies) && (is_busy()))   {      sony_sleep();            while (handle_sony_cd_attention())         ;   }   if (is_busy())   {      result_buffer[0] = 0x20;      result_buffer[1] = SONY_TIMEOUT_OP_ERR;      *result_size = 2;   }   else   {      clear_result_ready();      clear_param_reg();      write_params(params, num_params);      write_cmd(cmd);      get_result(result_buffer, result_size);   }   if (   ((result_buffer[0] & 0x20) == 0x20)       && (num_retries < MAX_CDU31A_RETRIES))   {      num_retries++;      current->state = TASK_INTERRUPTIBLE;      current->timeout = jiffies + 10; /* Wait .1 seconds on retries */      schedule();      goto retry_cd_operation;   }   if (!recursive_call)   {      has_cd_task = NULL;      sony_inuse = 0;      wake_up_interruptible(&sony_wait);   }}/* * Handle an attention from the drive.  This will return 1 if it found one * or 0 if not (if one is found, the caller might want to call again). * * This routine counts the number of consecutive times it is called * (since this is always called from a while loop until it returns * a 0), and returns a 0 if it happens too many times.  This will help * prevent a lockup. */static inthandle_sony_cd_attention(void){   unsigned char atten_code;   static int num_consecutive_attentions = 0;   if (is_attention())   {      if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS)      {         printk("cdu31a: Too many consecutive attentions: %d\n",                num_consecutive_attentions);         num_consecutive_attentions = 0;         return(0);      }      clear_attention();      atten_code = read_result_register();      switch (atten_code)      {       /* Someone changed the CD.  Mark it as changed */      case SONY_MECH_LOADED_ATTN:         sony_disc_changed = 1;         sony_toc_read = 0;         sony_audio_status = CDROM_AUDIO_NO_STATUS;         sony_first_block = -1;         sony_last_block = -1;         break;      case SONY_AUDIO_PLAY_DONE_ATTN:         sony_audio_status = CDROM_AUDIO_COMPLETED;         read_subcode();         break;      case SONY_EJECT_PUSHED_ATTN:         sony_audio_status = CDROM_AUDIO_INVALID;         break;      case SONY_LEAD_IN_ERR_ATTN:      case SONY_LEAD_OUT_ERR_ATTN:      case SONY_DATA_TRACK_ERR_ATTN:      case SONY_AUDIO_PLAYBACK_ERR_ATTN:         sony_audio_status = CDROM_AUDIO_ERROR;         break;      }      num_consecutive_attentions++;      return(1);   }   num_consecutive_attentions = 0;   return(0);}/* Convert from an integer 0-99 to BCD */static inline unsigned intint_to_bcd(unsigned int val){   int retval;   retval = (val / 10) << 4;   retval = retval | val % 10;   return(retval);}/* Convert from BCD to an integer from 0-99 */static unsigned intbcd_to_int(unsigned int bcd){   return((((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f));}/* * Convert a logical sector value (like the OS would want to use for * a block device) to an MSF format. */static voidlog_to_msf(unsigned int log, unsigned char *msf)

⌨️ 快捷键说明

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