2 emu10kx.audio - AHI driver for SoundBlaster Live! series
3 Copyright (C) 2002-2005 Martin Blom <martin@blom.org>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <libraries/ahi_sub.h>
23 #include <exec/execbase.h>
24 #include <clib/alib_protos.h>
25 #include <proto/exec.h>
29 #include "pci_wrapper.h"
31 #define min(a,b) ((a)<(b)?(a):(b))
34 # define CallHookA CallHookPkt
39 copy_mono( WORD
* src
, WORD
* dst
, int count
, int stride
, BOOL src32
, BOOL flush_caches
);
42 copy_stereo( WORD
* lsrc
, WORD
* rsrc
, WORD
* dst
, int count
, int stride
, BOOL src32
, BOOL flush_caches
);
45 /******************************************************************************
46 ** Hardware interrupt handler *************************************************
47 ******************************************************************************/
51 EMU10kxInterrupt( struct ExceptionContext
*pContext
, struct ExecBase
*SysBase
, struct EMU10kxData
* dd
)
54 EMU10kxInterrupt( struct EMU10kxData
* dd
)
57 struct AHIAudioCtrlDrv
* AudioCtrl
= dd
->audioctrl
;
58 struct DriverBase
* AHIsubBase
= (struct DriverBase
*) dd
->ahisubbase
;
59 struct EMU10kxBase
* EMU10kxBase
= (struct EMU10kxBase
*) AHIsubBase
;
64 while( ( intreq
= ahi_pci_inl( dd
->card
.iobase
+ IPR
, dd
->card
.pci_dev
) ) != 0 )
66 // KPrintF("IRQ: %08lx\n", intreq );
67 if( intreq
& IPR_INTERVALTIMER
&&
70 int hw
= sblive_readptr( &dd
->card
, CCCA_CURRADDR
, dd
->voices
[0].num
);
71 int diff
= dd
->current_position
- ( hw
- dd
->voices
[0].start
);
75 diff
+= AudioCtrl
->ahiac_MaxBuffSamples
* 2;
78 // KPrintF( ">>> hw_pos = %08lx; current_pos = %08lx; diff=%ld <<<\n",
79 // hw, dd->current_position, diff );
81 if( (ULONG
) diff
< dd
->current_length
)
83 if( dd
->playback_interrupt_enabled
)
85 /* Invoke softint to fetch new sample data */
87 dd
->playback_interrupt_enabled
= FALSE
;
88 Cause( &dd
->playback_interrupt
);
89 /* KPrintF("hw[0]=%08lx, hw[1]=%08lx, hw[2]=%08lx, hw[3]=%08lx\n", */
90 /* sblive_readptr( &dd->card, CCCA_CURRADDR, dd->voices[0].num ), */
91 /* sblive_readptr( &dd->card, CCCA_CURRADDR, dd->voices[1].num ), */
92 /* sblive_readptr( &dd->card, CCCA_CURRADDR, dd->voices[2].num ), */
93 /* sblive_readptr( &dd->card, CCCA_CURRADDR, dd->voices[3].num ) ); */
98 if( intreq
& ( IPR_ADCBUFHALFFULL
| IPR_ADCBUFFULL
) )
100 if( intreq
& IPR_ADCBUFHALFFULL
)
102 dd
->current_record_buffer
= dd
->record_buffer
;
106 dd
->current_record_buffer
= ( dd
->record_buffer
+
107 RECORD_BUFFER_SAMPLES
* 4 / 2 );
110 if( dd
->record_interrupt_enabled
)
112 /* Invoke softint to convert and feed AHI with the new sample data */
114 dd
->record_interrupt_enabled
= FALSE
;
115 Cause( &dd
->record_interrupt
);
119 if( intreq
& IPR_MIDIRECVBUFEMPTY
)
123 while( emu10k1_mpu_read_data( &dd
->card
, &b
) >= 0 )
125 struct ReceiveMessage msg
= { b
};
127 if( dd
->camd_receivefunc
== NULL
)
129 KPrintF( "emu10kx.audio got unexpected IPR_MIDIRECVBUFEMPTY\n" );
132 // KPrintF( "\t%lx\n", (int) b );
133 CallHookA( dd
->camd_receivefunc
, (Object
*) EMU10kxBase
, &msg
);
137 if( intreq
& IPR_MIDITRANSBUFEMPTY
)
141 if( dd
->camd_transmitfunc
== NULL
)
143 KPrintF( "emu10kx.audio got unexpected IPR_MIDITRANSBUFEMPTY\n" );
146 b
= CallHookA( dd
->camd_transmitfunc
, (Object
*) EMU10kxBase
, NULL
);
148 // KPrintF( "%08lx\n", b );
150 // Check if d0.w is negative (as the V37 did once?) or if bit 8
151 // is set (as the V40 example does)
153 if( ( b
& 0x00008100 ) == 0x0000 )
155 emu10k1_mpu_write_data( &dd
->card
, b
);
158 if( ( !dd
->camd_v40
&& ( b
& 0x00ff0000 ) != 0 ) ||
159 ( b
& 0x00008100 ) != 0 )
161 // KPrintF( "Disabling interrupts\n" );
162 emu10k1_irq_disable( &dd
->card
, INTE_MIDITXENABLE
);
166 /* Clear interrupt pending bit(s) */
167 ahi_pci_outl( intreq
, dd
->card
.iobase
+ IPR
, dd
->card
.pci_dev
);
176 /******************************************************************************
177 ** Playback interrupt handler *************************************************
178 ******************************************************************************/
182 PlaybackInterrupt( struct ExceptionContext
*pContext
, struct ExecBase
*SysBase
, struct EMU10kxData
* dd
)
185 PlaybackInterrupt( struct EMU10kxData
* dd
)
188 struct AHIAudioCtrlDrv
* AudioCtrl
= dd
->audioctrl
;
189 struct DriverBase
* AHIsubBase
= (struct DriverBase
*) dd
->ahisubbase
;
190 struct EMU10kxBase
* EMU10kxBase
= (struct EMU10kxBase
*) AHIsubBase
;
192 if( dd
->mix_buffer
!= NULL
&& dd
->current_buffers
[0] != NULL
)
200 skip_mix
= CallHookA( AudioCtrl
->ahiac_PreTimerFunc
, (Object
*) AudioCtrl
, 0 );
202 CallHookA( AudioCtrl
->ahiac_PlayerFunc
, (Object
*) AudioCtrl
, NULL
);
206 CallHookA( AudioCtrl
->ahiac_MixerFunc
, (Object
*) AudioCtrl
, dd
->mix_buffer
);
209 /* Now translate and transfer to the DMA buffer */
210 samples
= dd
->current_length
;
213 AudioCtrl
->ahiac_MaxBuffSamples
* 2 - dd
->current_position
);
215 src
= dd
->mix_buffer
;
217 switch( AudioCtrl
->ahiac_BuffType
)
220 dd
->current_buffers
[0] = copy_mono( src
, dd
->current_buffers
[0],
222 EMU10kxBase
->flush_caches
);
227 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 1, dd
->current_buffers
[0],
229 EMU10kxBase
->flush_caches
);
234 dd
->current_buffers
[0] = copy_mono( src
, dd
->current_buffers
[0],
236 EMU10kxBase
->flush_caches
);
241 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 2, dd
->current_buffers
[0],
243 EMU10kxBase
->flush_caches
);
248 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 2, dd
->current_buffers
[0],
250 EMU10kxBase
->flush_caches
);
251 dd
->current_buffers
[1] = copy_stereo( src
+ 4, src
+ 6, dd
->current_buffers
[1],
253 EMU10kxBase
->flush_caches
);
254 dd
->current_buffers
[2] = copy_stereo( src
+ 8, src
+ 10, dd
->current_buffers
[2],
256 EMU10kxBase
->flush_caches
);
257 dd
->current_buffers
[3] = copy_stereo( src
+ 12, src
+ 14, dd
->current_buffers
[3],
259 EMU10kxBase
->flush_caches
);
264 dd
->current_position
+= s
;
267 if( dd
->current_position
== AudioCtrl
->ahiac_MaxBuffSamples
* 2 )
269 dd
->current_buffers
[0] = dd
->voices
[0].mem
.addr
;
270 dd
->current_buffers
[1] = dd
->voices
[1].mem
.addr
;
271 dd
->current_buffers
[2] = dd
->voices
[2].mem
.addr
;
272 dd
->current_buffers
[3] = dd
->voices
[3].mem
.addr
;
273 dd
->current_position
= 0;
280 switch( AudioCtrl
->ahiac_BuffType
)
283 dd
->current_buffers
[0] = copy_mono( src
, dd
->current_buffers
[0],
285 EMU10kxBase
->flush_caches
);
289 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 1, dd
->current_buffers
[0],
291 EMU10kxBase
->flush_caches
);
295 dd
->current_buffers
[0] = copy_mono( src
, dd
->current_buffers
[0],
297 EMU10kxBase
->flush_caches
);
301 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 2, dd
->current_buffers
[0],
303 EMU10kxBase
->flush_caches
);
307 dd
->current_buffers
[0] = copy_stereo( src
, src
+ 2, dd
->current_buffers
[0],
309 EMU10kxBase
->flush_caches
);
310 dd
->current_buffers
[1] = copy_stereo( src
+ 4, src
+ 6, dd
->current_buffers
[1],
312 EMU10kxBase
->flush_caches
);
313 dd
->current_buffers
[2] = copy_stereo( src
+ 8, src
+ 10, dd
->current_buffers
[2],
315 EMU10kxBase
->flush_caches
);
316 dd
->current_buffers
[3] = copy_stereo( src
+ 12, src
+ 14, dd
->current_buffers
[3],
318 EMU10kxBase
->flush_caches
);
322 dd
->current_position
+= s
;
325 CallHookA( AudioCtrl
->ahiac_PostTimerFunc
, (Object
*) AudioCtrl
, 0 );
328 dd
->playback_interrupt_enabled
= TRUE
;
333 copy_mono( WORD
* src
, WORD
* dst
, int count
, int stride
, BOOL src32
, BOOL flush_caches
)
336 WORD
* last
= dst
+ count
;
339 #ifndef WORDS_BIGENDIAN
342 // Move to high 16 bits
347 for( x
= 0, y
= 0; y
< count
; x
+= stride
, ++y
)
349 #ifndef WORDS_BIGENDIAN
352 dst
[y
] = ( ( src
[x
] & 0xff ) << 8 ) | ( ( src
[x
] & 0xff00 ) >> 8 );
358 CacheClearE( first
, (ULONG
) last
- (ULONG
) first
, CACRF_ClearD
);
366 copy_stereo( WORD
* lsrc
, WORD
* rsrc
, WORD
* dst
, int count
, int stride
, BOOL src32
, BOOL flush_caches
)
369 WORD
* last
= dst
+ count
* 2;
372 #ifndef WORDS_BIGENDIAN
375 // Move to high 16 bits
381 for( x
= 0, y
= 0; y
< count
* 2; x
+= stride
, y
+= 2 )
383 #ifndef WORDS_BIGENDIAN
387 dst
[y
+0] = ( ( lsrc
[x
] & 0xff ) << 8 ) | ( ( lsrc
[x
] & 0xff00 ) >> 8 );
388 dst
[y
+1] = ( ( rsrc
[x
] & 0xff ) << 8 ) | ( ( rsrc
[x
] & 0xff00 ) >> 8 );
394 CacheClearE( first
, (ULONG
) last
- (ULONG
) first
, CACRF_ClearD
);
401 /******************************************************************************
402 ** Record interrupt handler ***************************************************
403 ******************************************************************************/
407 RecordInterrupt( struct ExceptionContext
*pContext
, struct ExecBase
*SysBase
, struct EMU10kxData
* dd
)
410 RecordInterrupt( struct EMU10kxData
* dd
)
413 struct AHIAudioCtrlDrv
* AudioCtrl
= dd
->audioctrl
;
414 struct DriverBase
* AHIsubBase
= (struct DriverBase
*) dd
->ahisubbase
;
415 struct EMU10kxBase
* EMU10kxBase
= (struct EMU10kxBase
*) AHIsubBase
;
417 ULONG CacheCommand
= CACRF_InvalidateD
;
419 ULONG CacheCommand
= CACRF_ClearD
;
423 struct AHIRecordMessage rm
=
426 dd
->current_record_buffer
,
427 RECORD_BUFFER_SAMPLES
/ 2
430 #ifdef WORDS_BIGENDIAN
432 WORD
* ptr
= dd
->current_record_buffer
;
436 // As OS4 can do invalidate only, we don't need to do flushing here.
437 // Between the invalidate at the end, DMA and entering this interrupt code,
438 // nobody should have touched this half of the record buffer.
440 if( EMU10kxBase
->flush_caches
)
442 // This is used to invalidate the cache
444 CacheClearE( dd
->current_record_buffer
,
445 RECORD_BUFFER_SAMPLES
/ 2 * 4,
450 #ifdef WORDS_BIGENDIAN
451 while( i
< RECORD_BUFFER_SAMPLES
/ 2 * 2 )
453 *ptr
= ( ( *ptr
& 0xff ) << 8 ) | ( ( *ptr
& 0xff00 ) >> 8 );
460 CallHookA( AudioCtrl
->ahiac_SamplerFunc
, (Object
*) AudioCtrl
, &rm
);
462 if( EMU10kxBase
->flush_caches
)
464 // This is used to make sure the call above doesn't push dirty data
465 // the next time it's called. God help us if dd->current_record_buffer
466 // is not a the beginning of a cache line and there are dirty data
467 // in the DMA buffer before or after the current buffer.
469 CacheClearE( dd
->current_record_buffer
,
470 RECORD_BUFFER_SAMPLES
/ 2 * 4,
474 dd
->record_interrupt_enabled
= TRUE
;