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

📄 gus_wave.c

📁 内核是系统的心脏
💻 C
📖 第 1 页 / 共 5 页
字号:
	    return RET_ERROR (ENOSPC);

	  free_mem_ptr = tmp_mem;	/* 
					 * This leaves unusable memory 
					 */
	}
    }

  if ((free_mem_ptr + patch.len) > gus_mem_size)
    return RET_ERROR (ENOSPC);

  sample_ptrs[free_sample] = free_mem_ptr;

  /* 
   * Tremolo is not possible with envelopes 
   */

  if (patch.mode & WAVE_ENVELOPES)
    patch.mode &= ~WAVE_TREMOLO;

  memcpy ((char *) &samples[free_sample], &patch, sizeof_patch);

  /* 
   * Link this_one sample to the list of samples for patch 'instr'.
   */

  samples[free_sample].key = patch_table[instr];
  patch_table[instr] = free_sample;

  /* 
   * Use DMA to transfer the wave data to the DRAM
   */

  left = patch.len;
  src_offs = 0;
  target = free_mem_ptr;

  while (left)			/* 
				 * Not all moved 
				 */
    {
      blk_size = sound_buffsizes[gus_devnum];
      if (blk_size > left)
	blk_size = left;

      /* 
       * DMA cannot cross 256k bank boundaries. Check for that.
       */
      blk_end = target + blk_size;

      if ((target >> 18) != (blk_end >> 18))
	{			/* 
				 * Have to split the block 
				 */

	  blk_end &= ~(256 * 1024 - 1);
	  blk_size = blk_end - target;
	}

#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
      /* 
       * For some reason the DMA is not possible. We have to use PIO.
       */
      {
	long            i;
	unsigned char   data;

	for (i = 0; i < blk_size; i++)
	  {
	    GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
	    if (patch.mode & WAVE_UNSIGNED)

	      if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
		data ^= 0x80;	/* 
				 * Convert to signed 
				 */
	    gus_poke (target + i, data);
	  }
      }
#else /* 
       * * * GUS_NO_DMA   */
      {
	unsigned long   address, hold_address;
	unsigned char   dma_command;
	unsigned long   flags;

	/* 
	 * OK, move now. First in and then out.
	 */

	COPY_FROM_USER (snd_raw_buf[gus_devnum][0],
			addr, sizeof_patch + src_offs,
			blk_size);

	DISABLE_INTR (flags);	/******** INTERRUPTS DISABLED NOW ********/
	gus_write8 (0x41, 0);	/* 
				 * Disable GF1 DMA 
				 */
	DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0],
			  blk_size, DMA_MODE_WRITE);

	/* 
	 * Set the DRAM address for the wave data
	 */

	address = target;

	if (sound_dsp_dmachan[gus_devnum] > 3)
	  {
	    hold_address = address;
	    address = address >> 1;
	    address &= 0x0001ffffL;
	    address |= (hold_address & 0x000c0000L);
	  }

	gus_write16 (0x42, (address >> 4) & 0xffff);	/* 
							 * DRAM DMA address 
							 */

	/* 
	 * Start the DMA transfer
	 */

	dma_command = 0x21;	/* 
				 * IRQ enable, DMA start 
				 */
	if (patch.mode & WAVE_UNSIGNED)
	  dma_command |= 0x80;	/* 
				 * Invert MSB 
				 */
	if (patch.mode & WAVE_16_BITS)
	  dma_command |= 0x40;	/* 
				 * 16 bit _DATA_ 
				 */
	if (sound_dsp_dmachan[gus_devnum] > 3)
	  dma_command |= 0x04;	/* 
				 * 16 bit DMA channel 
				 */

	gus_write8 (0x41, dma_command);		/* 
						 * Let's go luteet (=bugs) 
						 */

	/* 
	 * Sleep here until the DRAM DMA done interrupt is served
	 */
	active_device = GUS_DEV_WAVE;

	DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
	if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
	  printk ("GUS: DMA Transfer timed out\n");
	RESTORE_INTR (flags);
      }
#endif /* 
        * * * GUS_NO_DMA   */

      /* 
       * Now the next part
       */

      left -= blk_size;
      src_offs += blk_size;
      target += blk_size;

      gus_write8 (0x41, 0);	/* 
				 * Stop DMA 
				 */
    }

  free_mem_ptr += patch.len;

  if (!pmgr_flag)
    pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0);
  free_sample++;
  return 0;
}

static void
guswave_hw_control (int dev, unsigned char *event)
{
  int             voice, cmd;
  unsigned short  p1, p2;
  unsigned long   plong, flags;

  cmd = event[2];
  voice = event[3];
  p1 = *(unsigned short *) &event[4];
  p2 = *(unsigned short *) &event[6];
  plong = *(unsigned long *) &event[4];

  if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
      (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
    do_volume_irq (voice);

  switch (cmd)
    {

    case _GUS_NUMVOICES:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_select_max_voices (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICESAMPLE:
      guswave_set_instr (dev, voice, p1);
      break;

    case _GUS_VOICEON:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      p1 &= ~0x20;		/* 
				 * Disable intr 
				 */
      gus_voice_on (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEOFF:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_voice_off ();
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEFADE:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_voice_fade (voice);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEMODE:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      p1 &= ~0x20;		/* 
				 * Disable intr 
				 */
      gus_voice_mode (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEBALA:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_voice_balance (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEFREQ:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_voice_freq (plong);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEVOL:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_voice_volume (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_VOICEVOL2:	/* 
				 * Just update the voice value 
				 */
      voices[voice].initial_volume =
	voices[voice].current_volume = p1;
      break;

    case _GUS_RAMPRANGE:
      if (voices[voice].mode & WAVE_ENVELOPES)
	break;			/* 
				 * NO-NO 
				 */
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_ramp_range (p1, p2);
      RESTORE_INTR (flags);
      break;

    case _GUS_RAMPRATE:
      if (voices[voice].mode & WAVE_ENVELOPES)
	break;			/* 
				 * NO-NO 
				 */
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_ramp_rate (p1, p2);
      RESTORE_INTR (flags);
      break;

    case _GUS_RAMPMODE:
      if (voices[voice].mode & WAVE_ENVELOPES)
	break;			/* 
				 * NO-NO 
				 */
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      p1 &= ~0x20;		/* 
				 * Disable intr 
				 */
      gus_ramp_mode (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_RAMPON:
      if (voices[voice].mode & WAVE_ENVELOPES)
	break;			/* 
				 * NO-NO 
				 */
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      p1 &= ~0x20;		/* 
				 * Disable intr 
				 */
      gus_rampon (p1);
      RESTORE_INTR (flags);
      break;

    case _GUS_RAMPOFF:
      if (voices[voice].mode & WAVE_ENVELOPES)
	break;			/* 
				 * NO-NO 
				 */
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_rampoff ();
      RESTORE_INTR (flags);
      break;

    case _GUS_VOLUME_SCALE:
      volume_base = p1;
      volume_scale = p2;
      break;

    case _GUS_VOICE_POS:
      DISABLE_INTR (flags);
      gus_select_voice (voice);
      gus_set_voice_pos (voice, plong);
      RESTORE_INTR (flags);
      break;

    default:;
    }
}

static int
gus_sampling_set_speed (int speed)
{
  if (speed <= 0)
    return gus_sampling_speed;

  if (speed > 44100)
    speed = 44100;

  gus_sampling_speed = speed;
  return speed;
}

static int
gus_sampling_set_channels (int channels)
{
  if (!channels)
    return gus_sampling_channels;
  if (channels > 2)
    channels = 2;
  if (channels < 1)
    channels = 1;
  gus_sampling_channels = channels;
  return channels;
}

static int
gus_sampling_set_bits (int bits)
{
  if (!bits)
    return gus_sampling_bits;

  if (bits != 8 && bits != 16)
    bits = 8;

  gus_sampling_bits = bits;
  return bits;
}

static int
gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
{
  switch (cmd)
    {
    case SOUND_PCM_WRITE_RATE:
      if (local)
	return gus_sampling_set_speed (arg);
      return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg)));
      break;

    case SOUND_PCM_READ_RATE:
      if (local)
	return gus_sampling_speed;
      return IOCTL_OUT (arg, gus_sampling_speed);
      break;

    case SNDCTL_DSP_STEREO:
      if (local)
	return gus_sampling_set_channels (arg + 1) - 1;
      return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1);
      break;

    case SOUND_PCM_WRITE_CHANNELS:
      if (local)
	return gus_sampling_set_channels (arg);
      return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg)));
      break;

    case SOUND_PCM_READ_CHANNELS:
      if (local)
	return gus_sampling_channels;
      return IOCTL_OUT (arg, gus_sampling_channels);
      break;

    case SNDCTL_DSP_SAMPLESIZE:
      if (local)
	return gus_sampling_set_bits (arg);
      return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg)));
      break;

    case SOUND_PCM_READ_BITS:
      if (local)
	return gus_sampling_bits;
      return IOCTL_OUT (arg, gus_sampling_bits);

    case SOUND_PCM_WRITE_FILTER:	/* 
					 * NOT YET IMPLEMENTED 
					 */
      return IOCTL_OUT (arg, RET_ERROR (EINVAL));
      break;

    case SOUND_PCM_READ_FILTER:
      return IOCTL_OUT (arg, RET_ERROR (EINVAL));
      break;

    default:
      return RET_ERROR (EINVAL);
    }
  return RET_ERROR (EINVAL);
}

static void
gus_sampling_reset (int dev)
{
}

static int
gus_sampling_open (int dev, int mode)
{
#ifdef GUS_NO_DMA
  printk ("GUS: DMA mode not enabled. Device not supported\n");
  return RET_ERROR (ENXIO);
#endif

  if (gus_busy)
    return RET_ERROR (EBUSY);

  gus_initialize ();

  gus_busy = 1;
  active_device = 0;

  gus_reset ();
  reset_sample_memory ();
  gus_select_max_voices (14);

  pcm_active = 0;
  pcm_opened = 1;
  if (mode & OPEN_READ) 
  {
     recording_active = 1;
     set_input_volumes();
  }

  return 0;
}

static void
gus_sampling_close (int dev)
{
  gus_reset ();
  gus_busy = 0;
  pcm_opened = 0;
  active_device = 0;

  if (recording_active)
     set_input_volumes();

  recording_active = 0;
}

static void
gus_sampling_update_volume (void)
{
  unsigned long   flags;
  int             voice;

  DISABLE_INTR (flags);
  if (pcm_active && pcm_opened)
    for (voice = 0; voice < gus_sampling_channels; voice++)
      {
	gus_select_voice (voice);
	gus_rampoff ();
	gus_voice_volume (1530 + (25 * gus_pcm_volume));
	gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
      }
  RESTORE_INTR (flags);
}

static void
play_next_pcm_block (void)
{
  unsigned long   flags;
  int             speed = gus_sampling_speed;
  int             this_one, is16bits, chn;
  unsigned long   dram_loc;
  unsigned char   mode[2], ramp_mode[2];

  if (!pcm_qlen)
    return;

  this_one = pcm_head;

  for (chn = 0; chn < gus_sampling_channels; chn++)
    {
      mode[chn] = 0x00;
      ramp_mode[chn] = 0x03;	/* 
				 * Ramping and rollover off 
				 */

      if (chn == 0)
	{
	  mode[chn] |= 0x20;	/* 
				 * Loop irq 
				 */
	  voices[chn].loop_irq_mode = LMODE_PCM;
	}

      if (gus_sampling_bits != 8)
	{
	  is16bits = 1;
	  mode[chn] |= 0x04;	/* 
				 * 16 bit data 
				 */
	}
      else
	is16bits = 0;

      dram_loc = this_one * pcm_bsize;
      dram_loc += chn * pcm_banksize;

      if (this_one == (pcm_nblk - 1))	/* 
					 * Last of the DRAM buffers 
					 */
	{
	  mode[chn] |= 0x08;	/* 
				 * Enable loop 
				 */
	  ramp_mode[chn] = 0x03;	/* 
					 * Disable rollover 
					 */
	}
      else
	{
	  if (chn == 0)
	    ramp_mode[chn] = 0x04;	/* 
					 * Enable rollover bit 
					 */
	}

      DISABLE_INTR (flags);
      gus_select_voice (chn);
      gus_voice_freq (speed);

      if (gus_sampling_channels == 1)
	gus_voice_balance (7);	/* 
				 * mono 
				 */
      else if (chn == 0)
	gus_voice_balance (0);	/* 
				 * left 
				 */
      else
	gus_voice_balance (15);	/* 
				 * right 
				 */

⌨️ 快捷键说明

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