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

📄 sbpcd.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 *  sbpcd.c   CD-ROM device driver for the whole family of IDE-style
 *            Kotobuki/Matsushita/Panasonic CR-5xx drives for
 *            SoundBlaster ("Pro" or "16 ASP" or compatible) cards
 *            and for "no-sound" interfaces like Lasermate and the
 *            Panasonic CI-101P.
 *
 *  NOTE:     This is release 1.3.
 *            It works with my SbPro & drive CR-521 V2.11 from 2/92
 *            and with the new CR-562-B V0.75 on a "naked" Panasonic
 *            CI-101P interface. And vice versa. 
 *  
 *
 *  VERSION HISTORY
 *
 *  0.1  initial release, April/May 93, after mcd.c (Martin Harriss)
 *
 *  0.2  the "repeat:"-loop in do_sbpcd_request did not check for
 *       end-of-request_queue (resulting in kernel panic).
 *       Flow control seems stable, but throughput is not better.  
 *
 *  0.3  interrupt locking totally eliminated (maybe "inb" and "outb"
 *       are still locking) - 0.2 made keyboard-type-ahead losses.
 *       check_sbpcd_media_change added (to use by isofs/inode.c)
 *       - but it detects almost nothing.
 *
 *  0.4  use MAJOR 25 definitely.
 *       Almost total re-design to support double-speed drives and
 *       "naked" (no sound) interface cards.
 *       Flow control should be exact now (tell me if not).
 *       Don't occupy the SbPro IRQ line (not needed either); will
 *       live together with Hannu Savolainen's sndkit now.
 *	 Speeded up data transfer to 150 kB/sec, with help from Kai
 *       Makisara, the "provider" of the "mt" tape utility.
 *       Give "SpinUp" command if necessary.
 *       First steps to support up to 4 drives (but currently only one).
 *       Implemented audio capabilities - workman should work, xcdplayer
 *       gives some problems.
 *       This version is still consuming too much CPU time, and
 *       sleeping still has to be worked on.
 *       During "long" implied seeks, it seems possible that a 
 *       ReadStatus command gets ignored. That gives the message
 *       "ResponseStatus timed out" (happens about 6 times here during
 *       a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is
 *       handled without data error, but it should get done better.
 *
 *  0.5  Free CPU during waits (again with help from Kai Makisara).
 *       Made it work together with the LILO/kernel setup standard.
 *       Included auto-probing code, as suggested by YGGDRASIL.
 *       Formal redesign to add DDI debugging.
 *       There are still flaws in IOCTL (workman with double speed drive).
 *
 *  1.0  Added support for all drive ids (0...3, no longer only 0)
 *       and up to 4 drives on one controller.
 *       Added "#define MANY_SESSION" for "old" multi session CDs.
 *
 *  1.1  Do SpinUp for new drives, too.
 *       Revised for clean compile under "old" kernels (pl9).
 *
 *  1.2  Found the "workman with double-speed drive" bug: use the driver's
 *       audio_state, not what the drive is reporting with ReadSubQ.
 *
 *  1.3  Minor cleanups.
 *       Refinements regarding Workman.
 *
 *     special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
 *     elaborated speed-up experiments (and the fabulous results!), for
 *     the "push" towards load-free wait loops, and for the extensive mail
 *     thread which brought additional hints and bug fixes.
 * 
 *
 *   Copyright (C) 1993, 1994  Eberhard Moenkeberg <emoenke@gwdg.de>
 *                         or <eberhard_moenkeberg@rollo.central.de>
 *
 *                  The FTP-home of this driver is 
 *                  ftp.gwdg.de:/pub/linux/cdrom/drivers/sbpcd/.
 *
 *                  If you change this software, you should mail a .diff
 *                  file with some description lines to emoenke@gwdg.de.
 *                  I want to know about it.
 *
 *                  If you are the editor of a Linux CD, you should
 *                  enable sbpcd.c within your boot floppy kernel and
 *                  send me one of your CDs for free.
 *
 *   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, or (at your option)
 *   any later version.
 *
 *   You should have received a copy of the GNU General Public License
 *   (for example /usr/src/linux/COPYING); if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <linux/config.h>
#include <linux/errno.h>

#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
#include <linux/sbpcd.h>

#if SBPCD_USE_IRQ
#include <linux/signal.h>
#endif SBPCD_USE_IRQ

#include <linux/ddi.h>
#include <linux/major.h> 

#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <stdarg.h>

#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
#include "blk.h"

#define VERSION "1.3 Eberhard Moenkeberg <emoenke@gwdg.de>"

#define SBPCD_DEBUG

#ifndef CONFIG_ISO9660_FS
#error "SBPCD: \"make config\" again. File system iso9660 is necessary."
#endif

/*
 * still testing around...
 */
#define MANY_SESSION 0
#define CDMKE
#undef  FUTURE
#define WORKMAN 1 /* some testing stuff to make it better */

/*==========================================================================*/
/*==========================================================================*/
/*
 * auto-probing address list
 * inspired by Adam J. Richter from Yggdrasil
 *
 * still not good enough - can cause a hang.
 *   example: a NE 2000 ethernet card at 300 will cause a hang probing 310.
 * if that happens, reboot and use the LILO (kernel) command line.
 * The possibly conflicting ethernet card addresses get NOT probed 
 * by default - to minimize the hang possibilities. 
 *
 * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error,
 * the 0x2xx-addresses must get checked before 0x6xx.
 *
 * send mail to emoenke@gwdg.de if your interface card is not FULLY
 * represented here.
 */
static int autoprobe[] = 
{
  CDROM_PORT, SBPRO, /* probe with user's setup first */
  0x230, 1, /* Soundblaster Pro and 16 (default) */
  0x300, 0, /* CI-101P (default), Galaxy (default), Reveal (one default) */
  0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */
  0x260, 1, /* OmniCD */
  0x320, 0, /* Lasermate, CI-101P, Galaxy, Reveal (other default) */
  0x340, 0, /* Lasermate, CI-101P */
  0x360, 0, /* Lasermate, CI-101P */
  0x270, 1, /* Soundblaster 16 */
  0x630, 0, /* "sound card #9" (default) */
  0x650, 0, /* "sound card #9" */
  0x670, 0, /* "sound card #9" */
  0x690, 0, /* "sound card #9" */
#if 0
/* some "hazardous" locations (ethernet cards) */
  0x330, 0, /* Lasermate, CI-101P */
  0x350, 0, /* Lasermate, CI-101P */
  0x370, 0, /* Lasermate, CI-101P */
  0x290, 1, /* Soundblaster 16 */
  0x310, 0, /* Lasermate, CI-101P */
#endif
};

#define NUM_AUTOPROBE  (sizeof(autoprobe) / sizeof(int))


/*==========================================================================*/
/*
 * the forward references:
 */
static void sbp_read_cmd(void);
static int  sbp_data(void);

/*==========================================================================*/

/*
 * pattern for printk selection:
 *
 * (1<<DBG_INF)  necessary information
 * (1<<DBG_IRQ)  interrupt trace
 * (1<<DBG_REA)  "read" status trace
 * (1<<DBG_CHK)  "media check" trace
 * (1<<DBG_TIM)  datarate timer test
 * (1<<DBG_INI)  initialization trace
 * (1<<DBG_TOC)  tell TocEntry values
 * (1<<DBG_IOC)  ioctl trace
 * (1<<DBG_STA)  "ResponseStatus" trace
 * (1<<DBG_ERR)  "xx_ReadError" trace
 * (1<<DBG_CMD)  "cmd_out" trace
 * (1<<DBG_WRN)  give explanation before auto-probing
 * (1<<DBG_MUL)  multi session code test
 * (1<<DBG_ID)   "drive_id != 0" test code
 * (1<<DBG_IOX)  some special information
 * (1<<DBG_DID)  drive ID test
 * (1<<DBG_RES)  drive reset info
 * (1<<DBG_SPI)  SpinUp test info
 * (1<<DBG_IOS)  ioctl trace: "subchannel"
 * (1<<DBG_IO2)  ioctl trace: general
 * (1<<DBG_000)  unnecessary information
 */
#if 1
static int sbpcd_debug =  (1<<DBG_INF) | (1<<DBG_WRN);
#else
static int sbpcd_debug =  (1<<DBG_INF) |
                          (1<<DBG_TOC) |
                          (1<<DBG_IOC) |
                          (1<<DBG_IOX);
#endif
static int sbpcd_ioaddr = CDROM_PORT;	/* default I/O base address */
static int sbpro_type = SBPRO;
static int CDo_command, CDo_reset;
static int CDo_sel_d_i, CDo_enable;
static int CDi_info, CDi_status, CDi_data;
static int MIXER_addr, MIXER_data;
static struct cdrom_msf msf;
static struct cdrom_ti ti;
static struct cdrom_tochdr tochdr;
static struct cdrom_tocentry tocentry;
static struct cdrom_subchnl SC;
static struct cdrom_volctrl volctrl;
char *str_sb = "SoundBlaster";
char *str_lm = "LaserMate";
char *type;

/*==========================================================================*/

#if FUTURE
static struct wait_queue *sbp_waitq = NULL;
#endif FUTURE

/*==========================================================================*/

#define SBP_BUFFER_FRAMES 4 /* driver's own read_ahead */

/*==========================================================================*/

static u_char drive_family[]="CR-5";
static u_char drive_vendor[]="MATSHITA";

static u_int response_count=0;
static u_int flags_cmd_out;
static u_char cmd_type=0;
static u_char drvcmd[7];
static u_char infobuf[20];

static u_char timed_out=0;
static u_int datarate= 1000000;
static u_int maxtim16=16000000;
static u_int maxtim04= 4000000;
static u_int maxtim02= 2000000;
static u_int maxtim_8=   30000;
#if MANY_SESSION
static u_int maxtim_data= 9000;
#else
static u_int maxtim_data= 3000;
#endif MANY_SESSION

/*==========================================================================*/

static int ndrives=0;
static u_char drv_pattern[4]={ 0x80, 0x80, 0x80, 0x80 }; /* auto speed */
/*  /X:... drv_pattern[0] |= (sax_n1|sax_n2);         */
/*  /A:... for (i=0;i<4;i++) drv_pattern[i] |= sax_a; */
/*  /N:... ndrives=i-'0';                             */

/*==========================================================================*/
/*
 * drive space begins here (needed separate for each unit) 
 */
static int d=0; /* DS index: drive number */

static struct {
  char drv_minor; /* minor number or -1 */

  char drive_model[4];
  char firmware_version[4];
  u_char *sbp_buf; /* Pointer to internal data buffer,
                           space allocated during sbpcd_init() */
  int sbp_first_frame;  /* First frame in buffer */
  int sbp_last_frame;   /* Last frame in buffer  */
  int sbp_read_frames;   /* Number of frames being read to buffer */
  int sbp_current;       /* Frame being currently read */

  u_char drv_type;
  u_char drv_options;
  u_char status_byte;
  u_char diskstate_flags;
  u_char sense_byte;
  
  u_char CD_changed;
  
  u_char error_byte;
  
  u_char f_multisession;
  u_int lba_multi;
  
  u_char audio_state;
  u_int pos_audio_start;
  u_int pos_audio_end;
  char vol_chan0;
  u_char vol_ctrl0;
  char vol_chan1;
  u_char vol_ctrl1;
#if 000
  char vol_chan2;
  u_char vol_ctrl2;
  char vol_chan3;
  u_char vol_ctrl3;
#endif 000
  
  u_char SubQ_audio;
  u_char SubQ_ctl_adr;
  u_char SubQ_trk;
  u_char SubQ_pnt_idx;
  u_int SubQ_run_tot;
  u_int SubQ_run_trk;
  u_char SubQ_whatisthis;
  
  u_char UPC_ctl_adr;
  u_char UPC_buf[7];
  
  int CDsize_blk;
  int frame_size;
  int CDsize_frm;
  
  u_char xa_byte; /* 0x20: XA capabilities */
  u_char n_first_track; /* binary */
  u_char n_last_track; /* binary (not bcd), 0x01...0x63 */
  u_int size_msf; /* time of whole CD, position of LeadOut track */
  u_int size_blk;
  
  u_char TocEnt_nixbyte; /* em */
  u_char TocEnt_ctl_adr;
  u_char TocEnt_number;
  u_char TocEnt_format; /* em */
  u_int TocEnt_address;
  u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */
  
  struct {
    u_char nixbyte; /* em */
    u_char ctl_adr; /* 0x4x: data, 0x0x: audio */
    u_char number;
    u_char format; /* em */ /* 0x00: lba, 0x01: msf */
    u_int address;
  } TocBuffer[MAX_TRACKS+1]; /* last entry faked */ 
  
  int in_SpinUp;
  
} DS[4];

/*
 * drive space ends here (needed separate for each unit)
 */

/*==========================================================================*/
/*==========================================================================*/
/*
 * DDI interface definitions
 */
#ifdef SBPCD_DEBUG
# define DPRINTF(x)	sbpcd_dprintf x

void sbpcd_dprintf(int level, char *fmt, ...)
{
  char buff[256];
  va_list args;
  extern int vsprintf(char *buf, const char *fmt, va_list args);

  if (! (sbpcd_debug & (1 << level))) return;

  va_start(args, fmt);
  vsprintf(buff, fmt, args);
  va_end(args);
  printk(buff);
}

#else
# define DPRINTF(x)	/* nothing */

#endif SBPCD_DEBUG

/*
 * maintain trace bit pattern
 */
static int sbpcd_dbg_ioctl(unsigned long arg, int level)
{
  int val;

  val = get_fs_long((int *) arg);
  switch(val)
    {
    case 0:	/* OFF */
      sbpcd_debug = 0;
      break;

    default:
      if (val >= 128) sbpcd_debug &= ~(1 << (val - 128));
      else sbpcd_debug |= (1 << val);
    }
  return(0);
}


/*==========================================================================*/
/*==========================================================================*/
/*
 * 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 sbp_sleep(u_int jifs)
{
   current->state = TASK_INTERRUPTIBLE;
   current->timeout = jiffies + jifs;
   schedule();
}

/*==========================================================================*/
/*==========================================================================*/
/*
 *  convert logical_block_address to m-s-f_number (3 bytes only)
 */
static void lba2msf(int lba, u_char *msf)
{
  lba += CD_BLOCK_OFFSET;
  msf[0] = lba / (CD_SECS*CD_FRAMES);
  lba %= CD_SECS*CD_FRAMES;
  msf[1] = lba / CD_FRAMES;
  msf[2] = lba % CD_FRAMES;
}
/*==========================================================================*/
/*==========================================================================*/
/*
 *  convert msf-bin to msf-bcd
 */
static void bin2bcdx(u_char *p)  /* must work only up to 75 or 99 */
{
  *p=((*p/10)<<4)|(*p%10);
}
/*==========================================================================*/
static u_int blk2msf(u_int blk)
{
  MSF msf;
  u_int mm;

⌨️ 快捷键说明

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