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

📄 mcd.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* This file contains the driver for a Mitsumi cdrom controller.
 *
 * The file contains one entry point:
 *
 *   mcd_task:		main entry when system is brought up
 *
 *  Mar 30 1995			Author: Michel R. Prevenier 
 */


#include "kernel.h"
#include "driver.h"
#include "drvlib.h"
#include <minix/cdrom.h>
#include <sys/ioctl.h>

#if ENABLE_MITSUMI_CDROM

#define MCD_DEBUG		0	/* debug level */

/* Default IRQ. */
#define MCD_IRQ			10

/* Default I/O ports (offset from base address */
#define MCD_IO_BASE_ADDRESS	0x300	
#define MCD_DATA_PORT		(mcd_io_base+0)
#define MCD_FLAG_PORT		(mcd_io_base+1)
#define MCD_CONTROL_PORT	(mcd_io_base+2)


/* Miscellaneous constants. */
#define MCD_SKIP		150     /* Skip first 150 blocks on cdrom */
#define MCD_BLOCK_SIZE		2048    /* Block size in cooked mode */
#define MCD_BLOCK_SHIFT		11	/* for division */
#define MCD_BLOCK_MASK		2047	/* and remainder */
#define	BYTES_PER_SECTOR	2048	/* Nr. of bytes in a sector */
#define SECTORS_PER_SECOND	75	/* Nr. of sectors in a second */
#define SECONDS_PER_MINUTE	60      /* You never know, things change :-) */ 
#define MCD_RETRIES		2	/* Number of retries for a command */
#define REPLY_DELAY		5000	/* Count to wait for a reply */
#define MAX_TRACKS		104	/* Maximum nr. of tracks */
#define LEAD_OUT		0xAA	/* Lead out track is always 0xAA */
#define SUB_PER_DRIVE	(NR_PARTITIONS * NR_PARTITIONS)


/* Drive commands */
#define	MCD_GET_VOL_INFO	0x10	/* Read volume information */
#define MCD_GET_Q_CHANNEL	0x20	/* Read q-channel information */
#define MCD_GET_STATUS		0x40	/* Read status of drive	*/
#define MCD_SET_MODE		0x50	/* Set transmission mode */
#define MCD_RESET		0x60	/* Reset controller */
#define MCD_STOP_AUDIO		0x70	/* Stop audio playing */
#define MCD_SET_DRIVE_MODE	0xA0	/* Set drive mode */
#define MCD_READ_FROM_TO	0xC0	/* Read from .. to .. */
#define MCD_GET_VERSION		0xDC	/* Get version number */
#define MCD_STOP		0xF0	/* Stop everything */
#define MCD_EJECT		0xF6	/* Eject cd */
#define MCD_PICKLE		0x04	/* Needed for newer drive models */


/* Command bits for MCD_SET_MODE command */
#define MCD_MUTE_DATA		0x01	/* 1 = Don't play back data as audio */
#define MCD_GET_TOC		0x04	/* 0 = Get toc on next GET_Q_CHANNEL */
#define MCD_ECC_MODE		0x20	/* 0 = Use secondary ecc */
#define MCD_DATALENGTH		0x40	/* 0 = Read user data only */
#define MCD_COOKED		(MCD_MUTE_DATA)
#define MCD_TOC			(MCD_MUTE_DATA | MCD_GET_TOC)	


/* Status bits */
#define MCD_CMD_ERROR		0x01	/* Command error */
#define MCD_AUDIO_BUSY		0x02	/* Audio disk is playing */
#define MCD_READ_ERROR		0x04	/* Read error */
#define MCD_AUDIO_DISK		0x08	/* Audio disk is in */
#define MCD_SPINNING		0x10	/* Motor is spinning */
#define MCD_DISK_CHANGED	0x20	/* Disk has been removed or changed */
#define MCD_DISK_IN		0x40	/* Disk is in */
#define MCD_DOOR_OPEN		0x80	/* Door is open */

/* Flag bits */
#define MCD_DATA_AVAILABLE	0x02	/* Data available */
#define MCD_BUSY		0x04	/* Drive is busy */

/* Function prototypes */
FORWARD _PROTOTYPE ( int mcd_init, (void));
FORWARD _PROTOTYPE ( int c_handler, (int irq));
FORWARD _PROTOTYPE ( int mcd_play_mss, (struct cd_play_mss));
FORWARD _PROTOTYPE ( int mcd_play_tracks, (struct cd_play_track tracks));
FORWARD _PROTOTYPE ( int mcd_stop, (void));
FORWARD _PROTOTYPE ( int mcd_eject, (void));
FORWARD _PROTOTYPE ( int mcd_pause, (void));
FORWARD _PROTOTYPE ( int mcd_resume, (void));
FORWARD _PROTOTYPE ( u8_t bin2bcd, (u8_t b));
FORWARD _PROTOTYPE ( void bcd2bin, (u8_t *bcd));
FORWARD _PROTOTYPE ( long mss2block, (u8_t *mss));
FORWARD _PROTOTYPE ( void block2mss, (long block, u8_t *mss));
FORWARD _PROTOTYPE ( int mcd_get_reply, (u8_t *reply, int delay));
FORWARD _PROTOTYPE ( int mcd_get_status, (int f));
FORWARD _PROTOTYPE ( int mcd_ready, (int delay));
FORWARD _PROTOTYPE ( int mcd_data_ready, (int delay));
FORWARD _PROTOTYPE ( int mcd_set_mode, (int mode));
FORWARD _PROTOTYPE ( int mcd_send_command, (int command));
FORWARD _PROTOTYPE ( int mcd_get_disk_info, (void));
FORWARD _PROTOTYPE ( int mcd_read_q_channel, (struct cd_toc_entry *qc));
FORWARD _PROTOTYPE ( int mcd_read_toc, (void));
FORWARD _PROTOTYPE ( int ioctl_read_toc, (message *m_ptr));
FORWARD _PROTOTYPE ( int ioctl_disk_info, (message *m_ptr));
FORWARD _PROTOTYPE ( int ioctl_read_sub, (message *m_ptr));
FORWARD _PROTOTYPE ( int ioctl_disk_info, (message *m_ptr));
FORWARD _PROTOTYPE ( int ioctl_play_mss, (message *m_ptr));
FORWARD _PROTOTYPE ( int ioctl_play_ti, (message *m_ptr));
FORWARD _PROTOTYPE ( int mcd_open, (struct driver *dp, message *m_ptr));
FORWARD _PROTOTYPE ( int mcd_close, (struct driver *dp, message *m_ptr));
FORWARD _PROTOTYPE ( int mcd_ioctl, (struct driver *dp, message *m_ptr));
FORWARD _PROTOTYPE ( char *mcd_name, (void));
FORWARD _PROTOTYPE ( struct device *mcd_prepare, (int dev));
FORWARD _PROTOTYPE ( int mcd_schedule, (int proc_nr, struct iorequest_s *iop));
FORWARD _PROTOTYPE ( int mcd_finish, (void));
FORWARD _PROTOTYPE ( void mcd_geometry, (struct partition *entry));


/* Flags displaying current status of cdrom, used with the McdStatus variable */
#define TOC_UPTODATE   0x001     /* Table of contents is up to date */
#define INFO_UPTODATE  0x002     /* Disk info is up to date */
#define DISK_CHANGED   0x004     /* Disk has changed */
#define AUDIO_PLAYING  0x008     /* Cdrom is playing audio */
#define AUDIO_PAUSED   0x010     /* Cdrom is paused (only audio) */
#define AUDIO_DISK     0x020     /* Disk contains audio */
#define DISK_ERROR     0x040     /* An error occured */
#define NO_DISK        0x080     /* No disk in device */

/* Entry points to this driver. */
PRIVATE struct driver mcd_dtab = 
{
#if __minix_vmd
  NULL,		/* No private request buffer */
#endif
  mcd_name,	/* Current device's name */
  mcd_open,	/* Open request read table of contents */
  mcd_close,	/* Release device */
  mcd_ioctl,	/* Do cdrom ioctls */
  mcd_prepare,	/* Prepare for I/O */
  mcd_schedule,	/* Precompute blocks */
  mcd_finish,	/* Do the I/O */
  nop_cleanup,	/* No cleanup to do */
  mcd_geometry	/* Tell geometry */
};


PRIVATE struct trans 
{
  struct iorequest_s *tr_iop;	/* Belongs to this I/O request */
  unsigned long tr_pos;		/* Byte position to transfer from */
  int tr_count;			/* Byte count */
  phys_bytes tr_phys;		/* User physical address */
} mcd_trans[NR_IOREQS];


/* Globals */
#if __minix_vmd
PRIVATE int mcd_tasknr = ANY;
#endif
PRIVATE int mcd_avail;			/* Set if Mitsumi device exists */
PRIVATE int mcd_irq;			/* Interrupt request line */
PRIVATE int mcd_io_base;		/* I/O base register */
PRIVATE struct device *mcd_dv;		/* Active partition */
PRIVATE struct trans *mcd_tp;		/* Pointer to add transfer requests */
PRIVATE unsigned mcd_count;		/* Number of bytes to transfer */
PRIVATE unsigned long mcd_nextpos;	/* Next consecutive position on disk */
PRIVATE struct device mcd_part[DEV_PER_DRIVE];
					/* Primary partitions: cd[0-4] */
PRIVATE struct device mcd_subpart[SUB_PER_DRIVE];
					/* Subpartitions: cd[1-4][a-d] */
PRIVATE int mcd_open_ct;		/* in-use count */
PRIVATE int McdStatus = NO_DISK;        /* A new (or no) disk is inserted */ 
PRIVATE struct cd_play_mss PlayMss;     /* Keep track of where we are if we
                                           pause, used by resume */ 
PRIVATE struct cd_disk_info DiskInfo;   /* Contains toc header */  
PRIVATE struct cd_toc_entry Toc[MAX_TRACKS];  /* Buffer for toc */



/*=========================================================================*
 *				mcd_task				   *
 *=========================================================================*/
PUBLIC void mcd_task()
{
  long v;
  static char var[] = "MCD";
  static char fmt[] = "x:d";

#if __minix_vmd
  mcd_tasknr = proc_number(proc_ptr);
#endif

  /* Configure I/O base and IRQ. */
  v = MCD_IO_BASE_ADDRESS;
  (void) env_parse(var, fmt, 0, &v, 0x000L, 0x3FFL);
  mcd_io_base = v;

  v = MCD_IRQ;
  (void) env_parse(var, fmt, 0, &v, 0L, (long) NR_IRQ_VECTORS - 1);
  mcd_irq = v;

  driver_task(&mcd_dtab);       /* Start driver task for cdrom */
}


/*=========================================================================*
 *				mcd_open				   *	
 *=========================================================================*/
PRIVATE int mcd_open(dp, m_ptr)
struct driver *dp;	/* pointer to this drive */
message *m_ptr;		/* OPEN */
{
  int i, status;

  if (!mcd_avail && mcd_init() != OK) return EIO;

  if (mcd_prepare(m_ptr->DEVICE) == NIL_DEV) return ENXIO;

  /* A CD-ROM is read-only by definition. */
  if (m_ptr->COUNT & W_BIT) return EACCES;

  if (mcd_open_ct == 0)
  {
    i = 20;
    for (;;) {
      if (mcd_get_status(1) == -1) return EIO;   /* set McdStatus flags */
      if (!(McdStatus & NO_DISK)) break;
      if (--i == 0) return EIO;
      milli_delay(100);
    }

    /* Try to read the table of contents of the CD currently inserted */
    if ((status = mcd_read_toc()) != OK)  
      return status;

    mcd_open_ct++;

    /* fill in size of device (= nr. of bytes on the disk) */
    mcd_part[0].dv_base = 0;
    mcd_part[0].dv_size = 
     ((((unsigned long)DiskInfo.disk_length_mss[MINUTES] * SECONDS_PER_MINUTE
      + (unsigned long)DiskInfo.disk_length_mss[SECONDS]) * SECTORS_PER_SECOND)
      + (unsigned long)DiskInfo.disk_length_mss[SECTOR]) * BYTES_PER_SECTOR; 

#if MCD_DEBUG >= 1
    printf("cd size: %lu\n", mcd_part[0].dv_size);
#endif

    /* Partition the disk. */
    partition(&mcd_dtab, 0, P_PRIMARY);
  }
  return OK;
}


/*=========================================================================*
 *				mcd_close				   *	
 *=========================================================================*/
PRIVATE int mcd_close(dp, m_ptr)
struct driver *dp;	/* pointer to this drive */
message *m_ptr;		/* CLOSE */
{
  /* One less reference to the device */

  mcd_open_ct--;
  return OK;
}


/*=========================================================================*
 *				mcd_name				   *	
 *=========================================================================*/
PRIVATE char *mcd_name()
{
  /* Return a name for the device */

  return "cd0";
}


/*=========================================================================*
 *				mcd_ioctl				   *	
 *=========================================================================*/
PRIVATE int mcd_ioctl(dp, m_ptr)
struct driver *dp;	/* pointer to the drive */
message *m_ptr;		/* contains ioctl command */
{
  /* Perform the ioctl request */

  int status;

  if (mcd_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);

  mcd_get_status(1);	/* Update the status flags */
  if ((McdStatus & NO_DISK) && m_ptr->REQUEST != CDIOEJECT)
    return EIO;

  switch(m_ptr->REQUEST)
  {
    case CDIOPLAYMSS:     status = ioctl_play_mss(m_ptr);break;
    case CDIOPLAYTI:      status = ioctl_play_ti(m_ptr);break;
    case CDIOREADTOCHDR:  status = ioctl_disk_info(m_ptr);break;
    case CDIOREADTOC:     status = ioctl_read_toc(m_ptr);break;
    case CDIOREADSUBCH:   status = ioctl_read_sub(m_ptr);break;
    case CDIOSTOP:        status = mcd_stop();break;
    case CDIOPAUSE:       status = mcd_pause();break;
    case CDIORESUME:      status = mcd_resume();break;
    case CDIOEJECT:       status = mcd_eject();break;
    default:              status = do_diocntl(dp, m_ptr);
  }
  return status;
}


/*=========================================================================*
 *				mcd_get_reply				   *	
 *=========================================================================*/
PRIVATE int mcd_get_reply(reply, delay)
u8_t *reply;		/* variable to put reply in */
int delay;		/* count to wait for the reply */
{
  /* Get a reply from the drive */

  if (mcd_ready(delay) != OK) return EIO;           /* wait for drive to 
                                                       become available */
  *reply = in_byte(MCD_DATA_PORT);	/* get the reply */
  return OK;
}


/*=========================================================================*
 *				mcd_ready				   *	
 *=========================================================================*/
PRIVATE int mcd_ready(delay)
int delay;   /* count to wait for drive to become available again */
{
  /* Wait for drive to become available */

  struct milli_state ms;

  milli_start(&ms);
  do
  {
    if (!(in_byte(MCD_FLAG_PORT) & MCD_BUSY)) return OK; /* OK, drive ready */
  } while(milli_elapsed(&ms) < delay);

  return EIO; /* Timeout */
}


/*=========================================================================*
 *				mcd_data_ready				   *	
 *=========================================================================*/
PRIVATE int mcd_data_ready(delay)
int delay;    	/* count to wait for the data */
{
  /* Wait for the drive to get the data */

  struct milli_state ms;

  milli_start(&ms);
  do
  {
    if (!(in_byte(MCD_FLAG_PORT) & 2)) return OK; /* OK, data is there */
  } while(milli_elapsed(&ms) < delay);

  return EIO;  /* Timeout */
}


/*=========================================================================*
 *				mcd_get_status				   *	
 *=========================================================================*/
PRIVATE int mcd_get_status(f)
int f; 		/* flag */
{
  /* Return status info from the drive and update the global McdStatus */

  u8_t status;

  /* If f = 1, we first send a get_status command, otherwise we just get
     the status info from the drive */ 

  if (f) out_byte(MCD_DATA_PORT, MCD_GET_STATUS);        /* Try to get status */
  if (mcd_get_reply(&status,REPLY_DELAY) != OK) return -1; 

  McdStatus &= ~(NO_DISK | DISK_CHANGED | DISK_ERROR);

  /* Fill in the McdStatus variable */
  if (status & MCD_DOOR_OPEN ||
     !(status & MCD_DISK_IN))         McdStatus = NO_DISK;  
  else if (status & MCD_DISK_CHANGED) McdStatus = DISK_CHANGED; 
  else if (status & MCD_READ_ERROR ||
           status & MCD_CMD_ERROR)    McdStatus = DISK_ERROR; 
  else 
  {
    if (status & MCD_AUDIO_DISK) 
    {
      McdStatus |= AUDIO_DISK;
      if (!(status & MCD_AUDIO_BUSY)) McdStatus &= ~(AUDIO_PLAYING); 
      else McdStatus |= AUDIO_PLAYING;
    }
  }
#if MCD_DEBUG >= 3
  printf("mcd_get_status(%d) = %02x, McdStatus = %02x\n",
	f, status, McdStatus);
#endif
  return status;	/* Return status */
}


/*=========================================================================*
 *				mcd_set_mode				   *	
 *=========================================================================*/
PRIVATE int mcd_set_mode(mode)
int mode; /* new drive mode */
{
  /* Set drive mode */

  int i;

  for (i = 0; i < MCD_RETRIES; i++)
  {
    out_byte(MCD_DATA_PORT, MCD_SET_MODE); /* Send set mode command */
    out_byte(MCD_DATA_PORT, mode);         /* Send which mode */

⌨️ 快捷键说明

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