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

📄 cdu31a.c

📁 还有没有人研究过cdrom 的驱动源码啊
💻 C
📖 第 1 页 / 共 5 页
字号:
/** Sony CDU-31A CDROM interface device driver.** Corey Minyard (minyard@wf-rch.cirr.com)** Colossians 3:17**  See Documentation/cdrom/cdu31a for additional details about this driver.* * 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.** WARNING - 	All autoprobes have been removed from the driver.*		You MUST configure the CDU31A via a LILO config*		at boot time or in lilo.conf.  I have the*		following in my lilo.conf:**                append="cdu31a=0x1f88,0,PAS"**		The first number is the I/O base address of the*		card.  The second is the interrupt (0 means none). *		The third should be "PAS" if on a Pro-Audio *		spectrum, or nothing if on something else. * * This interface is (unfortunately) 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 (time_before(jiffies, retry_count) && (! <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 * asynchronous events from the drive informing the driver that a disk * has been inserted, removed, etc. * * NEWS FLASH - The driver now supports interrupts but they are * turned off by default.  Use of interrupts is highly encouraged, it * cuts CPU usage down to a reasonable level.  I had DMA in for a while * but PC DMA is just too slow.  Better to just insb() it. * * 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. * * DRIVER SPECIAL FEATURES * ----------------------- * * This section describes features beyond the normal audio and CD-ROM * functions of the drive. * * 2048 byte buffer mode * * If a disk is mounted with -o block=2048, data is copied straight * from the drive data port to the buffer.  Otherwise, the readahead * buffer must be involved to hold the other 1K of data when a 1K * block operation is done.  Note that with 2048 byte blocks you * cannot execute files from the CD. * * XA compatibility * * The driver should support XA disks for both the CDU31A and CDU33A. * It does this transparently, the using program doesn't need to set it. * * Multi-Session * * A multi-session disk looks just like a normal disk to the user. * Just mount one normally, and all the data should be there. * A special thanks to Koen for help with this! *  * Raw sector I/O * * Using the CDROMREADAUDIO it is possible to read raw audio and data * tracks.  Both operations return 2352 bytes per sector.  On the data * tracks, the first 12 bytes is not returned by the drive and the value * of that data is indeterminate. * * *  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. * * TODO:  *       CDs with form1 and form2 sectors cause problems *       with current read-ahead strategy. * * Credits: *    Heiko Eissfeldt <heiko@colossus.escape.de> *         For finding abug in the return of the track numbers. *         TOC processing redone for proper multisession support. * * *  It probably a little late to be adding a history, but I guess I *  will start. * *  10/24/95 - Added support for disabling the eject button when the *             drive is open.  Note that there is a small problem *             still here, if the eject button is pushed while the *             drive light is flashing, the drive will return a bad *             status and be reset.  It recovers, though. * *  03/07/97 - Fixed a problem with timers. * * *  18 Spetember 1997 -- Ported to Uniform CD-ROM driver by  *                 Heiko Eissfeldt <heiko@colossus.escape.de> with additional *                 changes by Erik Andersen <andersee@debian.org> * *  24 January 1998 -- Removed the scd_disc_status() function, which was now *                     just dead code left over from the port. *                          Erik Andersen <andersee@debian.org> * *  16 July 1998 -- Drive donated to Erik Andersen by John Kodis *                   <kodis@jagunet.com>.  Work begun on fixing driver to *                   work under 2.1.X.  Added temporary extra printks *                   which seem to slow it down enough to work. * *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x  *	               Removed init_module & cleanup_module in favor of  *		       module_init & module_exit. *		       Torben Mathiasen <tmm@image.dk>*/#include <linux/major.h>#include <linux/module.h>#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 <linux/devfs_fs_kernel.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/system.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/dma.h>#include <linux/cdrom.h>#include "cdu31a.h"#define MAJOR_NR CDU31A_CDROM_MAJOR#include <linux/blk.h>#define CDU31A_READAHEAD 4	/* 128 sector, 64kB, 32 reads read-ahead */#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10#define DEBUG 0/* Define the following if you have data corruption problems. */#undef SONY_POLL_EACH_BYTE/*** Edit the following data to change interrupts, DMA channels, etc.** Default is polled and no DMA.  DMA is not recommended for double-speed** drives.*/static struct {	unsigned short base;	/* I/O Base Address */	short int_num;		/* Interrupt Number (-1 means scan for it,				   0 means don't use) */} cdu31a_addresses[] __initdata = {	{0}};static int handle_sony_cd_attention(void);static int read_subcode(void);static void sony_get_toc(void);static int scd_spinup(void);/*static int scd_open(struct inode *inode, struct file *filp);*/static int scd_open(struct cdrom_device_info *, int);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);/* Parameters for the read-ahead. */static unsigned int sony_next_block;	/* Next 512 byte block offset */static unsigned int sony_blocks_left = 0;	/* Number of 512 byte blocks left						   in the current read command. *//* 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 int cdu31a_port = 0;MODULE_PARM(cdu31a_port, "i");/* * 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_spun_up = 0;	/* Has the drive been spun up? */static int sony_speed = 0;	/* Last wanted speed */static int sony_xa_mode = 0;	/* Is an XA disk in the drive				   and the drive a CDU31A? */static int sony_raw_data_mode = 1;	/* 1 if data tracks, 0 if audio.					   For raw data reads. */static unsigned int sony_usage = 0;	/* How many processes have the					   drive open. */static int sony_pas_init = 0;	/* Initialize the Pro-Audio				   Spectrum card? */static struct s_sony_session_toc single_toc;	/* Holds the						   table of						   contents. */static struct s_all_sessions_toc sony_toc;	/* entries gathered from all						   sessions */static int sony_toc_read = 0;	/* Has the TOC been read for				   the drive? */static struct s_sony_subcode last_sony_subcode;	/* Points to the last						   subcode address read */static volatile int sony_inuse = 0;	/* Is the drive in use?  Only one operation					   at a time allowed */static DECLARE_WAIT_QUEUE_HEAD(sony_wait);	/* Things waiting for the drive */static struct task_struct *has_cd_task = NULL;	/* The task that is currently						   using the CDROM drive, or						   NULL if none. */static int is_double_speed = 0;	/* does the drive support double speed ? */static int is_a_cdu31a = 1;	/* Is the drive a CDU31A? */static int is_auto_eject = 1;	/* Door has been locked? 1=No/0=Yes *//* * 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. */static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 };static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 };/* What IRQ is the drive using?  0 if none. */static int cdu31a_irq = 0;MODULE_PARM(cdu31a_irq, "i");/* The interrupt handler will wake this queue up when it gets an   interrupts. */DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait);static int curr_control_reg = 0;	/* Current value of the control register *//* A disk changed variable.  When a disk change is detected, it will   all be set to TRUE.  As the upper layers ask for disk_changed status   it will be cleared. */static char disk_changed;/* Variable for using the readahead buffer.  The readahead buffer   is used for raw sector reads and for blocksizes that are smaller   than 2048 bytes. */static char readahead_buffer[CD_FRAMESIZE_RAW];static int readahead_dataleft = 0;static int readahead_bad = 0;/* Used to time a short period to abort an operation after the   drive has been idle for a while.  This keeps the light on   the drive from flashing for very long. */static struct timer_list cdu31a_abort_timer;/* Marks if the timeout has started an abort read.  This is used   on entry to the drive to tell the code to read out the status   from the abort read. */static int abort_read_started = 0;/* * This routine returns 1 if the disk has been changed since the last * check or 0 if it hasn't. */static int scd_disk_change(kdev_t full_dev){	int retval;	retval = disk_changed;	disk_changed = 0;	return retval;}/* * Uniform cdrom interface function * report back, if disc has changed from time of last request. */static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr){	return scd_disk_change(cdi->dev);}/* * Uniform cdrom interface function * report back, if drive is ready */static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr){	if (CDSL_CURRENT != slot_nr) {		/* we have no changer support */		return -EINVAL;	}	if (scd_spinup() == 0) {		sony_spun_up = 1;	}	return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY;}static inline void enable_interrupts(void){	curr_control_reg |= (SONY_ATTN_INT_EN_BIT			     | SONY_RES_RDY_INT_EN_BIT			     | SONY_DATA_RDY_INT_EN_BIT);	outb(curr_control_reg, sony_cd_control_reg);}static inline void disable_interrupts(void){	curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT			      | SONY_RES_RDY_INT_EN_BIT			      | SONY_DATA_RDY_INT_EN_BIT);	outb(curr_control_reg, sony_cd_control_reg);}/* * 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 void sony_sleep(void){	unsigned long flags;	if (cdu31a_irq <= 0) {		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(0);	} else {		/* Interrupt driven */		save_flags(flags);		cli();		enable_interrupts();		interruptible_sleep_on(&cdu31a_irq_wait);		restore_flags(flags);	}}/* * The following are convenience routine to read various status and set * various conditions in the drive. */static inline int is_attention(void){	return ((inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0);}static inline int is_busy(void){	return ((inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0);}static inline int is_data_ready(void){	return ((inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0);}static inline int is_data_requested(void){	return ((inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0);}static inline int is_result_ready(void){	return ((inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0);}static inline int is_param_write_rdy(void){	return ((inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0);}static inline int is_result_reg_not_empty(void){	return ((inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0);}static inline void reset_drive(void){	curr_control_reg = 0;	readahead_dataleft = 0;	sony_toc_read = 0;	outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg);}/* * Uniform cdrom interface function * reset drive and return when it is ready */static int scd_reset(struct cdrom_device_info *cdi){	int retry_count;	reset_drive();	retry_count = jiffies + SONY_RESET_TIMEOUT;	while (time_before(jiffies, retry_count) && (!is_attention())) {		sony_sleep();	}	return 0;}static inline void clear_attention(void){	outb(curr_control_reg | SONY_ATTN_CLR_BIT, sony_cd_control_reg);}static inline void clear_result_ready(void){	outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg);}static inline void clear_data_ready(void){	outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT,	     sony_cd_control_reg);}static inline void clear_param_reg(void){	outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg);}static inline unsigned char read_status_register(void){

⌨️ 快捷键说明

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