rem: KPrintF("Route for %ld: %08lx\n", i, routes[i]);
context: _AHIsub_Start( ULONG                   flags,	       struct AHIAudioCtrlDrv* AudioCtrl,	       struct DriverBase*      AHIsubBase ){  struct EMU10kxBase* EMU10kxBase = (struct EMU10kxBase*) AHIsubBase;  struct EMU10kxData* dd = (struct EMU10kxData*) AudioCtrl->ahiac_DriverData;  /* Stop playback/recording, free old buffers (if any) */  AHIsub_Stop( flags, AudioCtrl );  if( flags & AHISF_PLAY )  {    int num_voices;    int i;    ULONG dma_buffer_size;    ULONG dma_sample_frame_size;    /* Update cached/syncronized variables */    AHIsub_Update( AHISF_PLAY, AudioCtrl );    /* Allocate a new mixing buffer. Note: The buffer must be cleared, since       it might not be filled by the mixer software interrupt because of       pretimer/posttimer! */    dd->mix_buffer = AllocVec( AudioCtrl->ahiac_BuffSize,			       MEMF_ANY | MEMF_PUBLIC | MEMF_CLEAR );    if( dd->mix_buffer == NULL )    {      Req( "Unable to allocate %ld bytes for mixing buffer.",	   AudioCtrl->ahiac_BuffSize );      return AHIE_NOMEM;    }    /* Allocate 1 or 4 voice buffers large enough for 16-bit double-buffered       playback (mono, stereo or 8 channels) */    if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ||	AudioCtrl->ahiac_Flags & AHIACF_MULTICHANNEL)    {      dma_sample_frame_size = 4;      dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;    }    else    {      dma_sample_frame_size = 2;      dma_buffer_size = AudioCtrl->ahiac_MaxBuffSamples * dma_sample_frame_size;    }    if( AudioCtrl->ahiac_Flags & AHIACF_MULTICHANNEL )    {      num_voices = 4;    }    else    {      num_voices = 1;    }        for( i = 0; i < num_voices; ++i )    {      if( emu10k1_voice_alloc_buffer( &dd->card,				      &dd->voices[i].mem,				      ( dma_buffer_size * 2 + PAGE_SIZE - 1 )				      / PAGE_SIZE ) < 0 )      {	Req( "Unable to allocate voice buffer." );	return AHIE_NOMEM;      }      memset( dd->voices[i].mem.addr, 0, dma_buffer_size * 2 );      dd->voices[i].usage = VOICE_USAGE_PLAYBACK;      if( AudioCtrl->ahiac_Flags & AHIACF_STEREO ||	  AudioCtrl->ahiac_Flags & AHIACF_MULTICHANNEL )      {	dd->voices[i].flags = VOICE_FLAGS_STEREO | VOICE_FLAGS_16BIT;      }      else      {	dd->voices[i].flags = VOICE_FLAGS_16BIT;      }    }        dd->voice_buffers_allocated = num_voices;    for( i = 0; i < num_voices; ++i )    {      if( emu10k1_voice_alloc( &dd->card, &dd->voices[i] ) < 0 )      {	Req( "Unable to allocate voice." );	return AHIE_UNKNOWN;      }    }        dd->voices_allocated = num_voices;    for( i = 0; i < num_voices; ++i )    {      dd->voices[i].initial_pitch = (u16) ( srToPitch( AudioCtrl->ahiac_MixFreq ) >> 8 );      dd->voices[i].pitch_target  = SamplerateToLinearPitch( AudioCtrl->ahiac_MixFreq );      DPD(2, "Initial pitch --> %#x\n", dd->voice.initial_pitch);      /* start, startloop and endloop is unit sample frames, not bytes */      dd->voices[i].start     = ( ( dd->voices[i].mem.emupageindex << 12 )				  / dma_sample_frame_size );      dd->voices[i].endloop   = dd->voices[i].start + AudioCtrl->ahiac_MaxBuffSamples * 2;      dd->voices[i].startloop = dd->voices[i].start;      /* Make interrupt routine start at the correct location */      dd->current_position = dd->current_length;      dd->current_buffers[i] = ( dd->voices[i].mem.addr +				 dd->current_position * dma_sample_frame_size );      dd->voices[i].params[0].volume_target = 0xffff;      dd->voices[i].params[0].initial_fc = 0xff;      dd->voices[i].params[0].initial_attn = 0x00;      dd->voices[i].params[0].byampl_env_sustain = 0x7f;      dd->voices[i].params[0].byampl_env_decay = 0x7f;          if( dd->voices[i].flags & VOICE_FLAGS_STEREO )      {	if( dd->card.is_audigy )	{	  dd->voices[i].params[0].send_dcba = 0x00ff00ff;	  dd->voices[i].params[0].send_hgfe = 0x00007f7f;	  dd->voices[i].params[1].send_dcba = 0xff00ff00;	  dd->voices[i].params[1].send_hgfe = 0x00007f7f;	  dd->voices[i].params[0].send_routing  = dd->voices[i].params[1].send_routing  = 0x03020100;	  dd->voices[i].params[0].send_routing2 = dd->voices[i].params[1].send_routing2 = 0x07060504;	}	else	{	  static int routes[] = {	    0x3210, // Send FL/FR to ??/??, AHI_FRONT_L/MULTI_FRONT_R	    0x3254, // Send RL/RR to ??/??, AHI_REAR_L/AHI_REAR_R	    0x3276, // Send SL/SR to ??/??, AHI_SURROUND_L/AHI_SURROUND_R	    0x3298, // Send C/LFE to ??/??, AHI_CENTER,AHI_LFE	  };	    	  dd->voices[i].params[0].send_dcba = 0x000000ff;	  dd->voices[i].params[0].send_hgfe = 0;	  dd->voices[i].params[1].send_dcba = 0x0000ff00;	  dd->voices[i].params[1].send_hgfe = 0;	  KPrintF("Route for %ld: %08lx\n", i, routes[i]);	  dd->voices[i].params[0].send_routing  = dd->voices[i].params[1].send_routing  = routes[i];	  dd->voices[i].params[0].send_routing2 = dd->voices[i].params[1].send_routing2 = 0;	}	dd->voices[i].params[1].volume_target = 0xffff;	dd->voices[i].params[1].initial_fc = 0xff;	dd->voices[i].params[1].initial_attn = 0x00;	dd->voices[i].params[1].byampl_env_sustain = 0x7f;	dd->voices[i].params[1].byampl_env_decay = 0x7f;      }      else      {	if( dd->card.is_audigy )	{	  dd->voices[i].params[0].send_dcba = 0xffffffff;	  dd->voices[i].params[0].send_hgfe = 0x0000ffff; 	  dd->voices[i].params[0].send_routing  = 0x03020100;	  dd->voices[i].params[0].send_routing2 = 0x07060504;	}	else	{	  dd->voices[i].params[0].send_dcba = 0x000ffff;	  dd->voices[i].params[0].send_hgfe = 0;	  dd->voices[i].params[0].send_routing  = 0x3210;	  dd->voices[i].params[0].send_routing2 = 0;	}      }      DPD(2, "voice: startloop=%x, endloop=%x\n",	  dd->voice.startloop, dd->voice.endloop);      emu10k1_voice_playback_setup( &dd->voices[i] );    }        dd->playback_interrupt_enabled = TRUE;    /* Enable timer interrupts (TIMER_INTERRUPT_FREQUENCY Hz) */    emu10k1_timer_set( &dd->card, 48000 / TIMER_INTERRUPT_FREQUENCY );    emu10k1_irq_enable( &dd->card, INTE_INTERVALTIMERENB );    emu10k1_voices_start( dd->voices, num_voices, 0 );    dd->voices_started = num_voices;    dd->is_playing = TRUE;  }  if( flags & AHISF_RECORD )  {    int adcctl = 0;    /* Find out the recording frequency */    switch( AudioCtrl->ahiac_MixFreq )    {      case 48000:	adcctl = ADCCR_SAMPLERATE_48;	break;      case 44100:	adcctl = ADCCR_SAMPLERATE_44;	break;      case 32000:	adcctl = ADCCR_SAMPLERATE_32;	break;      case 24000:	adcctl = ADCCR_SAMPLERATE_24;	break;      case 22050:	adcctl = ADCCR_SAMPLERATE_22;	break;      case 16000:	adcctl = ADCCR_SAMPLERATE_16;	break;      case 11025:	adcctl = ADCCR_SAMPLERATE_11;	break;      case 8000:	adcctl = ADCCR_SAMPLERATE_8;	break;      default:	return AHIE_UNKNOWN;    }    adcctl |= ADCCR_LCHANENABLE | ADCCR_RCHANENABLE;    /* Allocate a new recording buffer (page aligned!) */    dd->record_buffer = pci_alloc_consistent( dd->card.pci_dev,					      RECORD_BUFFER_SAMPLES * 4,					      &dd->record_dma_handle );    if( dd->record_buffer == NULL )    {      Req( "Unable to allocate %ld bytes for the recording buffer.",	   RECORD_BUFFER_SAMPLES * 4 );      return AHIE_NOMEM;    }    SaveMixerState( dd );    UpdateMonitorMixer( dd );    sblive_writeptr( &dd->card, ADCBA, 0, dd->record_dma_handle );    sblive_writeptr( &dd->card, ADCBS, 0, RECORD_BUFFER_SIZE_VALUE );    sblive_writeptr( &dd->card, ADCCR, 0, adcctl );    dd->record_interrupt_enabled = TRUE;    /* Enable ADC interrupts  */    emu10k1_irq_enable( &dd->card, INTE_ADCBUFENABLE );    dd->is_recording = TRUE;  }  return AHIE_OK;}