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

📄 cdu31a.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Sony CDU-31A CDROM interface device driver. * * Corey Minyard (minyard@wf-rch.cirr.com) * * Colossians 3:17 * * The Sony interface device driver handles Sony interface CDROM * drives and provides a complete block-level interface as well as an * ioctl() interface compatible with the Sun (as specified in * include/linux/cdrom.h).  With this interface, CDROMs can be * accessed and standard audio CDs can be played back normally. * * This interface is (unfortunatly) a polled interface.  This is * because most Sony interfaces are set up with DMA and interrupts * disables.  Some (like mine) do not even have the capability to * handle interrupts or DMA.  For this reason you will see a lot of * the following: * *   retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; *   while ((retry_count > jiffies) && (! <some condition to wait for)) *   { *      while (handle_sony_cd_attention()) *         ; * *      sony_sleep(); *   } *   if (the condition not met) *   { *      return an error; *   } * * This ugly hack waits for something to happen, sleeping a little * between every try.  it also handles attentions, which are * asyncronous events from the drive informing the driver that a disk * has been inserted, removed, etc. * * One thing about these drives: They talk in MSF (Minute Second Frame) format. * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a * disk.  The funny thing is that these are sent to the drive in BCD, but the * interface wants to see them in decimal.  A lot of conversion goes on. * *  Copyright (C) 1993  Corey Minyard * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/errno.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/hdreg.h>#include <linux/genhd.h>#include <linux/ioport.h>#include <asm/system.h>#include <asm/io.h>#include <asm/segment.h>#include <linux/cdrom.h>#include <linux/cdu31a.h>#define MAJOR_NR CDU31A_CDROM_MAJOR#include "blk.h"#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10static unsigned short cdu31a_addresses[] ={   0x340,	/* Standard configuration Sony Interface */   0x1f88,	/* Fusion CD-16 */   0x230,	/* SoundBlaster 16 card */   0x360,	/* Secondary standard Sony Interface */   0x320,	/* Secondary standard Sony Interface */   0x330,	/* Secondary standard Sony Interface */   0};static int handle_sony_cd_attention(void);static int read_subcode(void);static void sony_get_toc(void);static int scd_open(struct inode *inode, struct file *filp);static void do_sony_cd_cmd(unsigned char cmd,                           unsigned char *params,                           unsigned int num_params,                           unsigned char *result_buffer,                           unsigned int *result_size);static void size_to_buf(unsigned int size,                        unsigned char *buf);/* The base I/O address of the Sony Interface.  This is a variable (not a   #define) so it can be easily changed via some future ioctl() */static unsigned short sony_cd_base_io = 0;/* * The following are I/O addresses of the various registers for the drive.  The * comment for the base address also applies here. */static volatile unsigned short sony_cd_cmd_reg;static volatile unsigned short sony_cd_param_reg;static volatile unsigned short sony_cd_write_reg;static volatile unsigned short sony_cd_control_reg;static volatile unsigned short sony_cd_status_reg;static volatile unsigned short sony_cd_result_reg;static volatile unsigned short sony_cd_read_reg;static volatile unsigned short sony_cd_fifost_reg;static int sony_disc_changed = 1;          /* Has the disk been changed                                              since the last check? */static int sony_toc_read = 0;              /* Has the table of contents been                                              read? */static int sony_spun_up = 0;               /* Has the drive been spun up? */static unsigned int sony_buffer_size;      /* Size in bytes of the read-ahead                                              buffer. */static unsigned int sony_buffer_sectors;   /* Size (in 2048 byte records) of                                              the read-ahead buffer. */static unsigned int sony_usage = 0;        /* How many processes have the                                              drive open. */static volatile int sony_first_block = -1; /* First OS block (512 byte) in                                              the read-ahead buffer */static volatile int sony_last_block = -1;  /* Last OS block (512 byte) in                                              the read-ahead buffer */static struct s_sony_toc *sony_toc;              /* Points to the table of                                                    contents. */static struct s_sony_subcode * volatile last_sony_subcode; /* Points to the last                                                    subcode address read */static unsigned char * volatile sony_buffer;     /* Points to the read-ahead                                                    buffer */static volatile int sony_inuse = 0;  /* Is the drive in use?  Only one operation at a time                                        allowed */static struct wait_queue * sony_wait = NULL;static struct task_struct *has_cd_task = NULL;  /* The task that is currently using the                                                   CDROM drive, or NULL if none. *//* * The audio status uses the values from read subchannel data as specified * in include/linux/cdrom.h. */static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS;/* * The following are a hack for pausing and resuming audio play.  The drive * does not work as I would expect it, if you stop it then start it again, * the drive seeks back to the beginning and starts over.  This holds the * position during a pause so a resume can restart it.  It uses the * audio status variable above to tell if it is paused. */unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 };unsigned volatile char final_pos_msf[3] = { 0, 0, 0 };/* * This routine returns 1 if the disk has been changed since the last * check or 0 if it hasn't.  Setting flag to 0 resets the changed flag. */intcheck_cdu31a_media_change(int full_dev, int flag){   int retval, target;   target = MINOR(full_dev);   if (target > 0) {      printk("Sony CD-ROM request error: invalid device.\n");      return 0;   }   retval = sony_disc_changed;   if (!flag)   {      sony_disc_changed = 0;   }   return retval;}/* * Wait a little while (used for polling the drive).  If in initialization, * setting a timeout doesn't work, so just loop for a while. */static inline voidsony_sleep(void){   current->state = TASK_INTERRUPTIBLE;   current->timeout = jiffies;   schedule();}/* * The following are convenience routine to read various status and set * various conditions in the drive. */static inline intis_attention(void){   return((inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0);}static inline intis_busy(void){   return((inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0);}static inline intis_data_ready(void){   return((inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0);}static inline intis_data_requested(void){   return((inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0);}static inline intis_result_ready(void){   return((inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0);}static inline intis_param_write_rdy(void){   return((inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0);}static inline voidreset_drive(void){   outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg);}static inline voidclear_attention(void){   outb(SONY_ATTN_CLR_BIT, sony_cd_control_reg);}static inline voidclear_result_ready(void){   outb(SONY_RES_RDY_CLR_BIT, sony_cd_control_reg);}static inline voidclear_data_ready(void){   outb(SONY_DATA_RDY_CLR_BIT, sony_cd_control_reg);}static inline voidclear_param_reg(void){   outb(SONY_PARAM_CLR_BIT, sony_cd_control_reg);}static inline unsigned charread_status_register(void){   return(inb(sony_cd_status_reg));}static inline unsigned charread_result_register(void){   return(inb(sony_cd_result_reg));}static inline unsigned charread_data_register(void){   return(inb(sony_cd_read_reg));}static inline voidwrite_param(unsigned char param){   outb(param, sony_cd_param_reg);}static inline voidwrite_cmd(unsigned char cmd){   outb(cmd, sony_cd_cmd_reg);   outb(SONY_RES_RDY_INT_EN_BIT, sony_cd_control_reg);}/* * Set the drive parameters so the drive will auto-spin-up when a * disk is inserted. */static voidset_drive_params(void){   unsigned char res_reg[2];   unsigned int res_size;   unsigned char params[3];   params[0] = SONY_SD_MECH_CONTROL;   params[1] = 0x03;   do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,                  params,                  2,                  res_reg,                  &res_size);   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))   {      printk("  Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]);   }}/* * This code will reset the drive and attempt to restore sane parameters. */static voidrestart_on_error(void){   unsigned char res_reg[2];   unsigned int res_size;   unsigned int retry_count;   printk("cdu31a: Resetting drive on error\n");   reset_drive();   retry_count = jiffies + SONY_RESET_TIMEOUT;   while ((retry_count > jiffies) && (!is_attention()))   {      sony_sleep();   }   set_drive_params();   do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))   {      printk("cdu31a: Unable to spin up drive: 0x%2.2x\n", res_reg[1]);   }   current->state = TASK_INTERRUPTIBLE;   current->timeout = jiffies + 200;   schedule();   do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size);   if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20))   {      printk("cdu31a: Unable to read TOC: 0x%2.2x\n", res_reg[1]);   }   sony_get_toc();   if (!sony_toc_read)   {      printk("cdu31a: Unable to get TOC data\n");   }}/* * This routine writes data to the parameter register.  Since this should * happen fairly fast, it is polled with no OS waits between. */static intwrite_params(unsigned char *params,             int num_params){   unsigned int retry_count;   retry_count = SONY_READY_RETRIES;   while ((retry_count > 0) && (!is_param_write_rdy()))   {      retry_count--;   }   if (!is_param_write_rdy())   {      return -EIO;   }   while (num_params > 0)   {      write_param(*params);      params++;      num_params--;   }   return 0;}/* * The following reads data from the command result register.  It is a * fairly complex routine, all status info flows back through this * interface.  The algorithm is stolen directly from the flowcharts in * the drive manual. */static voidget_result(unsigned char *result_buffer,           unsigned int *result_size){   unsigned char a, b;   int i;   unsigned int retry_count;   while (handle_sony_cd_attention())      ;   /* Wait for the result data to be ready */   retry_count = jiffies + SONY_JIFFIES_TIMEOUT;   while ((retry_count > jiffies) && (is_busy() || (!(is_result_ready()))))   {      sony_sleep();      while (handle_sony_cd_attention())         ;   }   if (is_busy() || (!(is_result_ready())))   {      result_buffer[0] = 0x20;      result_buffer[1] = SONY_TIMEOUT_OP_ERR;      *result_size = 2;      return;   }   /*    * Get the first two bytes.  This determines what else needs    * to be done.    */   clear_result_ready();   a = read_result_register();   *result_buffer = a;   result_buffer++;   b = read_result_register();   *result_buffer = b;   result_buffer++;   *result_size = 2;   /*    * 0x20 means an error occured.  Byte 2 will have the error code.    * Otherwise, the command succeded, byte 2 will have the count of

⌨️ 快捷键说明

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