rem: AHIsub_Stop( AHISF_PLAY, AudioCtrl );
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;  AHIsub_Stop( flags, AudioCtrl );  if( flags & AHISF_PLAY )  {    ULONG dma_buffer_size;    ULONG dma_sample_frame_size;    /* Stop playback, free old buffers (if any) */    AHIsub_Stop( AHISF_PLAY, AudioCtrl );    /* 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.\n",	   AudioCtrl->ahiac_BuffSize );      return AHIE_NOMEM;    }    /* Allocate a voice buffer large enough for 16-bit double-buffered       playback (mono or stereo) */    if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )    {      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( emu10k1_voice_alloc_buffer( &dd->card,				    &dd->voice.mem,				    ( dma_buffer_size * 2 + PAGE_SIZE - 1 )				    / PAGE_SIZE ) < 0 )    {      Req( "Unable to allocate voice buffer.\n" );      return AHIE_NOMEM;    }    memset( dd->voice.mem.addr, 0, dma_buffer_size * 2 );    dd->voice_buffer_allocated = TRUE;    dd->voice.usage = VOICE_USAGE_PLAYBACK;    if( AudioCtrl->ahiac_Flags & AHIACF_STEREO )    {      dd->voice.flags = VOICE_FLAGS_STEREO | VOICE_FLAGS_16BIT;    }    else    {      dd->voice.flags = VOICE_FLAGS_16BIT;    }    if( emu10k1_voice_alloc( &dd->card, &dd->voice ) < 0 )    {      Req( "Unable to allocate voice.\n" );      return AHIE_UNKNOWN;    }    dd->voice_allocated = TRUE;    dd->voice.initial_pitch = (u16) ( srToPitch( AudioCtrl->ahiac_MixFreq ) >> 8 );    dd->voice.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->voice.start     = ( ( dd->voice.mem.emupageindex << 12 )			    / dma_sample_frame_size );    dd->voice.endloop   = dd->voice.start + AudioCtrl->ahiac_MaxBuffSamples * 2;    dd->voice.startloop = dd->voice.start;    /* Make interrupt routine start at the correct location */    dd->current_position = dd->current_length;    dd->current_buffer   = ( dd->voice.mem.addr +			     dd->current_position * dma_sample_frame_size );    if( dd->voice.flags & VOICE_FLAGS_STEREO )    {      dd->voice.params[0].send_a             = 0xff;      dd->voice.params[0].send_b             = 0x00;      dd->voice.params[0].send_c             = 0x00;      dd->voice.params[0].send_d             = 0x00;      dd->voice.params[0].send_routing       = 0x3210;      dd->voice.params[0].volume_target      = 0xffff;      dd->voice.params[0].initial_fc         = 0xff;      dd->voice.params[0].initial_attn       = 0x00;      dd->voice.params[0].byampl_env_sustain = 0x7f;      dd->voice.params[0].byampl_env_decay   = 0x7f;      dd->voice.params[1].send_a             = 0x00;      dd->voice.params[1].send_b             = 0xff;      dd->voice.params[1].send_c             = 0x00;      dd->voice.params[1].send_d             = 0x00;      dd->voice.params[1].send_routing       = 0x3210;      dd->voice.params[1].volume_target      = 0xffff;      dd->voice.params[1].initial_fc         = 0xff;      dd->voice.params[1].initial_attn       = 0x00;      dd->voice.params[1].byampl_env_sustain = 0x7f;      dd->voice.params[1].byampl_env_decay   = 0x7f;    }    else    {      dd->voice.params[0].send_a             = 0xff;      dd->voice.params[0].send_b             = 0xff;      dd->voice.params[0].send_c             = 0x00;      dd->voice.params[0].send_d             = 0x00;      dd->voice.params[0].send_routing       = 0x3210;      dd->voice.params[0].volume_target      = 0xffff;      dd->voice.params[0].initial_fc         = 0xff;      dd->voice.params[0].initial_attn       = 0x00;      dd->voice.params[0].byampl_env_sustain = 0x7f;      dd->voice.params[0].byampl_env_decay   = 0x7f;    }    DPD(2, "voice: startloop=%x, endloop=%x\n",	dd->voice.startloop, dd->voice.endloop);    emu10k1_voice_playback_setup( &dd->voice );    dd->playback_interrupt_enabled = TRUE;    /* Enable timer interrupts (TIMER_INTERRUPT_FREQUENCY Hz) */    emu10k1_writefn0( &dd->card, TIMER_RATE, 48000 / TIMER_INTERRUPT_FREQUENCY );    emu10k1_irq_enable( &dd->card, INTE_INTERVALTIMERENB );    emu10k1_voices_start( &dd->voice, 1, 0 );    dd->is_playing = TRUE;  }  if( flags & AHISF_RECORD )  {    int adcctl = 0;    /* Stop current recording, free old buffer (if any) */    AHIsub_Stop( AHISF_RECORD, AudioCtrl );    /* 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.\n",	   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;}