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

📄 gus_wave.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 5 页
字号:
   * right data to the area pointed by gus_page_size.   */  int             this_one, count;  unsigned long   flags;  unsigned char   dma_command;  unsigned long   address, hold_address;  DISABLE_INTR (flags);  count = total_count / gus_sampling_channels;  if (chn == 0)    {      if (pcm_qlen >= pcm_nblk)	printk ("GUS Warning: PCM buffers out of sync\n");      this_one = pcm_current_block = pcm_tail;      pcm_qlen++;      pcm_tail = (pcm_tail + 1) % pcm_nblk;      pcm_datasize[this_one] = count;    }  else    this_one = pcm_current_block;  gus_write8 (0x41, 0);		/* 				 * Disable GF1 DMA 				 */  DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE);  address = this_one * pcm_bsize;  address += chn * pcm_banksize;  if (sound_dsp_dmachan[dev] > 3)    {      hold_address = address;      address = address >> 1;      address &= 0x0001ffffL;      address |= (hold_address & 0x000c0000L);    }  gus_write16 (0x42, (address >> 4) & 0xffff);	/* 						 * DRAM DMA address 						 */  dma_command = 0x21;		/* 				 * IRQ enable, DMA start 				 */  if (gus_sampling_bits != 8)    dma_command |= 0x40;	/* 				 * 16 bit _DATA_ 				 */  else    dma_command |= 0x80;	/* 				 * Invert MSB 				 */  if (sound_dsp_dmachan[dev] > 3)    dma_command |= 0x04;	/* 				 * 16 bit DMA channel 				 */  gus_write8 (0x41, dma_command);	/* 					 * Kick on 					 */  if (chn == (gus_sampling_channels - 1))	/* 						 * Last channel 						 */    {      /*        * Last (right or mono) channel data        */      active_device = GUS_DEV_PCM_DONE;      if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize))	{	  play_next_pcm_block ();	}    }  else				/* 				 * * * Left channel data. The right channel				 * is * * * transferred after DMA interrupt   */    active_device = GUS_DEV_PCM_CONTINUE;  RESTORE_INTR (flags);}static voidgus_sampling_output_block (int dev, unsigned long buf, int total_count,			   int intrflag, int restart_dma){  pcm_current_buf = buf;  pcm_current_count = total_count;  pcm_current_intrflag = intrflag;  pcm_current_dev = dev;  gus_transfer_output_block (dev, buf, total_count, intrflag, 0);}static voidgus_sampling_start_input (int dev, unsigned long buf, int count,			  int intrflag, int restart_dma){  unsigned long   flags;  unsigned char   mode;  DISABLE_INTR (flags);  DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);  mode = 0xa0;			/* 				 * DMA IRQ enable, invert MSB 				 */  if (sound_dsp_dmachan[dev] > 3)    mode |= 0x04;		/* 				 * 16 bit DMA channel 				 */  if (gus_sampling_channels > 1)    mode |= 0x02;		/* 				 * Stereo 				 */  mode |= 0x01;			/* 				 * DMA enable 				 */  gus_write8 (0x49, mode);  RESTORE_INTR (flags);}static intgus_sampling_prepare_for_input (int dev, int bsize, int bcount){  unsigned int    rate;  rate = (9878400 / (gus_sampling_speed + 2)) / 16;  gus_write8 (0x48, rate & 0xff);	/* 					 * Set sampling frequency 					 */  if (gus_sampling_bits != 8)    {      printk ("GUS Error: 16 bit recording not supported\n");      return RET_ERROR (EINVAL);    }  return 0;}static intgus_sampling_prepare_for_output (int dev, int bsize, int bcount){  int             i;  long            mem_ptr, mem_size;  mem_ptr = 0;  mem_size = gus_mem_size / gus_sampling_channels;  if (mem_size > (256 * 1024))    mem_size = 256 * 1024;  pcm_bsize = bsize / gus_sampling_channels;  pcm_head = pcm_tail = pcm_qlen = 0;  pcm_nblk = MAX_PCM_BUFFERS;  if ((pcm_bsize * pcm_nblk) > mem_size)    pcm_nblk = mem_size / pcm_bsize;  for (i = 0; i < pcm_nblk; i++)    pcm_datasize[i] = 0;  pcm_banksize = pcm_nblk * pcm_bsize;  if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024))    pcm_nblk--;  return 0;}static intgus_has_output_drained (int dev){  return !pcm_qlen;}static voidgus_copy_from_user (int dev, char *localbuf, int localoffs,		    snd_rw_buf * userbuf, int useroffs, int len){  if (gus_sampling_channels == 1)    {      COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len);    }  else if (gus_sampling_bits == 8)    {      int             in_left = useroffs;      int             in_right = useroffs + 1;      char           *out_left, *out_right;      int             i;      len /= 2;      localoffs /= 2;      out_left = &localbuf[localoffs];      out_right = out_left + pcm_bsize;      for (i = 0; i < len; i++)	{	  GET_BYTE_FROM_USER (*out_left++, userbuf, in_left);	  in_left += 2;	  GET_BYTE_FROM_USER (*out_right++, userbuf, in_right);	  in_right += 2;	}    }  else    {      int             in_left = useroffs;      int             in_right = useroffs + 1;      short          *out_left, *out_right;      int             i;      len /= 4;      localoffs /= 4;      out_left = (short *) &localbuf[localoffs];      out_right = out_left + (pcm_bsize / 2);      for (i = 0; i < len; i++)	{	  GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left);	  in_left += 2;	  GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right);	  in_right += 2;	}    }}static struct audio_operations gus_sampling_operations ={  "Gravis UltraSound",  gus_sampling_open,  gus_sampling_close,  gus_sampling_output_block,  gus_sampling_start_input,  gus_sampling_ioctl,  gus_sampling_prepare_for_input,  gus_sampling_prepare_for_output,  gus_sampling_reset,  gus_sampling_reset,  gus_has_output_drained,  gus_copy_from_user};#ifdef FUTURE_VERSIONstatic voidguswave_bender (int dev, int voice, int value){  int             freq;  unsigned long   flags;  voices[voice].bender = value - 8192;  freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range);  voices[voice].current_freq = freq;  DISABLE_INTR (flags);  gus_select_voice (voice);  gus_voice_freq (freq);  RESTORE_INTR (flags);}#endifstatic intguswave_patchmgr (int dev, struct patmgr_info *rec){  int             i, n;  switch (rec->command)    {    case PM_GET_DEVTYPE:      rec->parm1 = PMTYPE_WAVE;      return 0;      break;    case PM_GET_NRPGM:      rec->parm1 = MAX_PATCH;      return 0;      break;    case PM_GET_PGMMAP:      rec->parm1 = MAX_PATCH;      for (i = 0; i < MAX_PATCH; i++)	{	  int             ptr = patch_table[i];	  rec->data.data8[i] = 0;	  while (ptr >= 0 && ptr < free_sample)	    {	      rec->data.data8[i]++;	      ptr = samples[ptr].key;	/* 					 * Follow link 					 */	    }	}      return 0;      break;    case PM_GET_PGM_PATCHES:      {	int             ptr = patch_table[rec->parm1];	n = 0;	while (ptr >= 0 && ptr < free_sample)	  {	    rec->data.data32[n++] = ptr;	    ptr = samples[ptr].key;	/* 					 * Follow link 					 */	  }      }      rec->parm1 = n;      return 0;      break;    case PM_GET_PATCH:      {	int             ptr = rec->parm1;	struct patch_info *pat;	if (ptr < 0 || ptr >= free_sample)	  return RET_ERROR (EINVAL);	memcpy (rec->data.data8, (char *) &samples[ptr],		sizeof (struct patch_info));	pat = (struct patch_info *) rec->data.data8;	pat->key = GUS_PATCH;	/* 				 * Restore patch type 				 */	rec->parm1 = sample_ptrs[ptr];	/* 					 * DRAM address 					 */	rec->parm2 = sizeof (struct patch_info);      }      return 0;      break;    case PM_SET_PATCH:      {	int             ptr = rec->parm1;	struct patch_info *pat;	if (ptr < 0 || ptr >= free_sample)	  return RET_ERROR (EINVAL);	pat = (struct patch_info *) rec->data.data8;	if (pat->len > samples[ptr].len)	/* 						 * Cannot expand sample 						 */	  return RET_ERROR (EINVAL);	pat->key = samples[ptr].key;	/* 					 * Ensure the link is correct 					 */	memcpy ((char *) &samples[ptr], rec->data.data8,		sizeof (struct patch_info));	pat->key = GUS_PATCH;      }      return 0;      break;    case PM_READ_PATCH:	/* 				 * Returns a block of wave data from the DRAM 				 */      {	int             sample = rec->parm1;	int             n;	long            offs = rec->parm2;	int             l = rec->parm3;	if (sample < 0 || sample >= free_sample)	  return RET_ERROR (EINVAL);	if (offs < 0 || offs >= samples[sample].len)	  return RET_ERROR (EINVAL);	/* 					 * Invalid offset 					 */	n = samples[sample].len - offs;		/* 						 * Nr of bytes left 						 */	if (l > n)	  l = n;	if (l > sizeof (rec->data.data8))	  l = sizeof (rec->data.data8);	if (l <= 0)	  return RET_ERROR (EINVAL);	/* 					 * Was there a bug? 					 */	offs += sample_ptrs[sample];	/* 					 * Begin offsess + offset to DRAM 					 */	for (n = 0; n < l; n++)	  rec->data.data8[n] = gus_peek (offs++);	rec->parm1 = n;		/* 				 * Nr of bytes copied 				 */      }      return 0;      break;    case PM_WRITE_PATCH:	/* 				 * Writes a block of wave data to the DRAM 				 */      {	int             sample = rec->parm1;	int             n;	long            offs = rec->parm2;	int             l = rec->parm3;	if (sample < 0 || sample >= free_sample)	  return RET_ERROR (EINVAL);	if (offs < 0 || offs >= samples[sample].len)	  return RET_ERROR (EINVAL);	/* 					 * Invalid offset 					 */	n = samples[sample].len - offs;		/* 						 * Nr of bytes left 						 */	if (l > n)	  l = n;	if (l > sizeof (rec->data.data8))	  l = sizeof (rec->data.data8);	if (l <= 0)	  return RET_ERROR (EINVAL);	/* 					 * Was there a bug? 					 */	offs += sample_ptrs[sample];	/* 					 * Begin offsess + offset to DRAM 					 */	for (n = 0; n < l; n++)	  gus_poke (offs++, rec->data.data8[n]);	rec->parm1 = n;		/* 				 * Nr of bytes copied 				 */      }      return 0;      break;    default:      return RET_ERROR (EINVAL);    }}static struct synth_operations guswave_operations ={  &gus_info,#ifdef FUTURE_VERSION  0,#endif  SYNTH_TYPE_SAMPLE,  SAMPLE_TYPE_GUS,  guswave_open,  guswave_close,  guswave_ioctl,  guswave_kill_note,  guswave_start_note,  guswave_set_instr,  guswave_reset,  guswave_hw_control,  guswave_load_patch,  guswave_aftertouch,  guswave_controller,  guswave_panning,  guswave_patchmgr,#ifdef FUTURE_VERSION  guswave_bender#endif};static voidset_input_volumes(void){	unsigned long flags;	unsigned char mask = 0xff & ~0x06;	/* Just line out enabled */	DISABLE_INTR(flags);/* *	Enable channels having vol > 10% *	Note! bit 0x01 means line in DISABLED while 0x04 means *	      mic in ENABLED. */ 	if (gus_line_vol > 10) mask &= ~0x01; 	if (gus_mic_vol > 10) mask |= 0x04;	if (recording_active)	  {/* *	Disable channel, if not selected for recording */	  	if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01;	  	if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04;	  }	mix_image &= ~0x07;	mix_image |= mask & 0x07;  	OUTB (mix_image, u_Mixer);	RESTORE_INTR(flags);}static intgus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg){#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)  if (((cmd >> 8) & 0xff) == 'M')    {      if (cmd & IOC_IN)	switch (cmd & 0xff)	  {	  case SOUND_MIXER_RECSRC:	    gus_recmask = IOCTL_IN(arg) & MIX_DEVS;	    if (!(gus_recmask & (SOUND_MASK_MIC|SOUND_MASK_LINE)))	       gus_recmask = SOUND_MASK_MIC;	    /* Note! Input volumes are updated during next open for recording */	    return IOCTL_OUT (arg, gus_recmask);	    break;	  case SOUND_MIXER_MIC:	    {	      int             vol = IOCTL_IN (arg) & 0xff;	      if (vol < 0) vol = 0;	      if (vol > 100) vol = 100;	      gus_mic_vol = vol;	      set_input_volumes();	      return IOCTL_OUT (arg, vol | (vol << 8));	    }	    break;	  case SOUND_MIXER_LINE:	    {	      int             vol = IOCTL_IN (arg) & 0xff;	      if (vol < 0) vol = 0;	      if (vol > 100) vol = 100;	      gus_line_vol = vol;	      set_input_volumes();	      return IOCTL_OUT (arg, vol | (vol << 8));	    }	    break;	  case SOUND_MIXER_PCM:	      gus_pcm_volume = IOCTL_IN (arg) & 0xff;	      if (gus_pcm_volume < 0)		gus_pcm_volume = 0;	      if (gus_pcm_volume > 100)		gus_pcm_volume = 100;	      gus_sampling_update_volume ();	      return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8));	    break;	  case SOUND_MIXER_SYNTH:	    {	      int             voice; 	      gus_wave_volume = IOCTL_IN (arg) & 0xff;	      if (gus_wave_volume < 0)		gus_wave_volume = 0;	      if (gus_wave_volume > 100)		gus_wave_volume = 100;	      if (active_device == GUS_DEV_WAVE)		for (voice = 0; voice < nr_voices; voice++)		  dynamic_volume_change (voice);	/* 							 * Apply the new							 * volume 							 */	      return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8));	    }	    break;	  default:	    return RET_ERROR (EINVAL);	  }      else	switch (cmd & 0xff)	/* 				 * Return parameters 				 */	  {	  case SOUND_MIXER_RECSRC:	    return IOCTL_OUT (arg, gus_recmask);	    break;	  case SOUND_MIXER_DEV

⌨️ 快捷键说明

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