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

📄 sb16_dsp.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* This file contains the driver for a DSP (Digital Sound Processor) on
 * a SoundBlaster 16 (ASP) soundcard.
 *
 * The driver supports the following operations (using message format m2):
 *
 *    m_type      DEVICE    PROC_NR     COUNT    POSITION  ADRRESS
 * ----------------------------------------------------------------
 * |  DEV_OPEN  | device  | proc nr |         |         |         |
 * |------------+---------+---------+---------+---------+---------|
 * |  DEV_CLOSE | device  | proc nr |         |         |         |
 * |------------+---------+---------+---------+---------+---------|
 * |  DEV_READ  | device  | proc nr |  bytes  |         | buf ptr |
 * |------------+---------+---------+---------+---------+---------|
 * |  DEV_WRITE | device  | proc nr |  bytes  |         | buf ptr |
 * |------------+---------+---------+---------+---------+---------|
 * |  DEV_IOCTL | device  | proc nr |func code|         | buf ptr |
 * ----------------------------------------------------------------
 *
 * The file contains one entry point:
 *
 *   dsp_task:	main entry when system is brought up
 *
 *  May 20 1995			Author: Michel R. Prevenier 
 */


#include "kernel.h"
#include <minix/com.h> 
#include <minix/callnr.h> 
#include <sys/ioctl.h>
#if __minix_vmd
#include "proc.h"
#include "config.h"
#endif
#include "sb16.h"

#if ENABLE_SB_AUDIO

/* prototypes */
FORWARD _PROTOTYPE( void init_buffer, (void));
FORWARD _PROTOTYPE( int dsp_init, (void)); 
FORWARD _PROTOTYPE( int dsp_handler, (int irq));
FORWARD _PROTOTYPE( int dsp_open, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_close, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_ioctl, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_write, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_read, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_reset, (void)); 
FORWARD _PROTOTYPE( int dsp_command, (int value));
FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed));
FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size));
FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo));
FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits));
FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign));
FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count));
FORWARD _PROTOTYPE( void dsp_setup, (void));

/* globals */
#if __minix_vmd
PRIVATE int DspTasknr = ANY;
#endif
PRIVATE int DspVersion[2]; 
PRIVATE unsigned int DspStereo = DEFAULT_STEREO;
PRIVATE unsigned int DspSpeed = DEFAULT_SPEED; 
PRIVATE unsigned int DspBits = DEFAULT_BITS;
PRIVATE unsigned int DspSign = DEFAULT_SIGN;
PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE;
PRIVATE int DspAvail = 0;
PRIVATE int DspBusy = 0;
PRIVATE int DmaBusy = 0;
PRIVATE int DmaDone = 1;
PRIVATE int DmaMode = 0;

PRIVATE char DmaBuffer[(long)2 * DMA_SIZE];
PRIVATE char *DmaPtr;
PRIVATE phys_bytes DmaPhys;


/*=========================================================================*
 *				dsp_task				   *
 *=========================================================================*/
PUBLIC void dsp_task()
{
  message mess;
  int err, caller, proc_nr;

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

  /* initialize the DMA buffer */
  init_buffer();

  /* Here is the main loop of the sound task. It waits for a message, carries
   * it out, and sends a reply.
   */
  while (TRUE) 
  {
	receive(ANY, &mess);

	caller = mess.m_source;
	proc_nr = mess.PROC_NR;

	switch (caller) 
        {
   	  case HARDWARE:
		/* Leftover interrupt. */
		continue;
	  case FS_PROC_NR:
		/* The only legitimate caller. */
		break;
	  default:
		printf("sb16: got message from %d\n", caller);
		continue;
	}

	/* Now carry out the work. */
	switch(mess.m_type) 
        {
	    case DEV_OPEN:      err = dsp_open(&mess);break;	
	    case DEV_CLOSE:     err = dsp_close(&mess);break; 
	    case DEV_IOCTL:     err = dsp_ioctl(&mess);break;
	    case DEV_READ:      err = dsp_read(&mess);break;  
	    case DEV_WRITE:     err = dsp_write(&mess);break;
	    default:		err = EINVAL;break;
	}

	/* Finally, prepare and send the reply message. */
	mess.m_type = TASK_REPLY;
	mess.REP_PROC_NR = proc_nr;

	mess.REP_STATUS = err;	/* #bytes transfered or error code */
	send(caller, &mess);	/* send reply to caller */
  }
}


/*===========================================================================*
 *				init_buffer				     *
 *===========================================================================*/
PRIVATE void init_buffer()
{
/* Select a buffer that can safely be used for dma transfers.  
 * Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
 */

  DmaPtr = DmaBuffer;
  DmaPhys = vir2phys(DmaBuffer);

  if (dma_bytes_left(DmaPhys) < DMA_SIZE) {
	/* First half of buffer crosses a 64K boundary, can't DMA into that */
	DmaPtr += DMA_SIZE;
	DmaPhys += DMA_SIZE;
  }
}


/*=========================================================================*
 *				dsp_open				   *	
 *=========================================================================*/
PRIVATE int dsp_open(m_ptr)
message *m_ptr;
{

#if SB_DEBUG
  printf("sb16_open\n");
#endif

  /* try to detect SoundBlaster card */
  if (!DspAvail && dsp_init() != OK) return EIO;

  /* Only one open at a time with soundcards */
  if (DspBusy) return EBUSY;
 
  /* Start with a clean DSP */
  if (dsp_reset() != OK) return EIO;

  /* Setup default values */
  DspStereo = DEFAULT_STEREO;
  DspSpeed = DEFAULT_SPEED;
  DspBits = DEFAULT_BITS;
  DspSign = DEFAULT_SIGN;
  DspFragmentSize = DMA_SIZE;
  
  DspBusy = 1;
  DmaBusy = 0;

  return OK;
}


/*=========================================================================*
 *				dsp_close				   *	
 *=========================================================================*/
PRIVATE int dsp_close(m_ptr)
message *m_ptr;
{

#if SB_DEBUG
  printf("dsp_close\n");
#endif

  DspBusy = 0;                  /* soundcard available again */
  DmaBusy = 0;

  return OK;
}


/*=========================================================================*
 *				dsp_ioctl				   *	
 *=========================================================================*/
PRIVATE int dsp_ioctl(m_ptr)
message *m_ptr;
{
  int status;
  phys_bytes user_phys;
  unsigned int val;

  /* Cannot change parameters during play or recording */
  if (DmaBusy) return EBUSY;

  /* Get user data */
  if (m_ptr->REQUEST != DSPIORESET)
  {
    user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, 
                                                   sizeof(unsigned int));
    if (user_phys == 0) return(EFAULT);
    phys_copy(user_phys, vir2phys(&val), (phys_bytes) sizeof(val));
  }

#if SB_DEBUG
  printf("dsp_ioctl: got ioctl %d, argument: %d\n", m_ptr->REQUEST, val);
#endif

  switch(m_ptr->REQUEST)
  {
    case DSPIORATE:	status = dsp_set_speed(val);break;
    case DSPIOSTEREO:	status = dsp_set_stereo(val);break;
    case DSPIOBITS:	status = dsp_set_bits(val);break;
    case DSPIOSIZE:	status = dsp_set_size(val);break;
    case DSPIOSIGN:	status = dsp_set_sign(val);break;
    case DSPIOMAX:	{ 
                           val = DMA_SIZE;
                           phys_copy(vir2phys(&val), user_phys, 
                                           (phys_bytes) sizeof(val));
                           status = OK;
                        };break;
    case DSPIORESET:    status = dsp_reset();break;
    default:            status = ENOTTY;break;
  }

  return status;
}


/*=========================================================================*
 *				dsp_init				   *
 *=========================================================================*/
PRIVATE int dsp_init()
{
  int i;

  if (dsp_reset () != OK) 
  { 
    printf("sb16: No SoundBlaster card detected\n");
    return -1;
  }

  DspVersion[0] = DspVersion[1] = 0;
  dsp_command(DSP_GET_VERSION);	/* Get DSP version bytes */

  for (i = 1000; i; i--)
  {
    if (in_byte (DSP_DATA_AVL) & 0x80)
    {		
      if (DspVersion[0] == 0)
        DspVersion[0] = in_byte (DSP_READ);
      else
      {
        DspVersion[1] = in_byte (DSP_READ);
        break;
      }
    }
  }

  if (DspVersion[0] < 4)
  {
    printf("sb16: No SoundBlaster 16 compatible card detected\n");
    return -1;
  }
  else
    printf ("sb16: SoundBlaster DSP version %d.%d detected\n", 
          DspVersion[0], DspVersion[1]);

  /* set IRQ and DMA channels */
  mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
  mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16)); 

  /* register interrupt vector and enable irq */
  put_irq_handler(SB_IRQ, dsp_handler);
  enable_irq(SB_IRQ);

  DspAvail = 1;
  return OK;
}


/*=========================================================================*
 *				dsp_handler				   *
 *=========================================================================*/
PRIVATE int dsp_handler(irq)
int irq;
{

#if SB_DEBUG2
  printf("SoundBlaster interrupt %d\n", irq);
#endif 

  if (DmaDone)     /* Dma transfer is done */
  {
    /* Send DSP command to stop dma */
    dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));

    DmaBusy = 0;  /* Dma available again */
  }

  /* Send interrupt to audio task and enable again */
#if __minix_vmd
  interrupt(DspTasknr);
#else
  interrupt(AUDIO);
#endif

  /* Acknowledge the interrupt on the DSP */
  (void) in_byte((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));

  return 1;
}


/*=========================================================================*
 *				dsp_command				   *
 *=========================================================================*/
PRIVATE int dsp_command(value)
int value;
{

⌨️ 快捷键说明

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