3 #include <aros/debug.h>
5 #include <devices/ahi.h>
6 #include <dos/dostags.h>
7 #include <exec/memory.h>
8 #include <libraries/ahi_sub.h>
9 #include <utility/tagitem.h>
11 #include <proto/ahi_sub.h>
12 #include <proto/exec.h>
13 #include <proto/dos.h>
14 #include <proto/utility.h>
20 #include "DriverData.h"
25 PROCGW( static, void, slaveentry
, SlaveEntry
);
28 /* There is probably no reason to support all these frequencies. If,
29 * for example, your hardware is locked at 48 kHz, it's ok to only
30 * present one single mixing/recording frequency to the user. If your
31 * hardware has internal resamples and accepts any frequency, select a
35 static const LONG frequencies
[] =
40 #define FREQUENCIES (sizeof frequencies / sizeof frequencies[ 0 ])
42 static const ULONG table_5bit
[] = {
77 static UWORD
LinToLog(ULONG vol
)
81 if (!vol
) return 0x20;
83 for (i
=0; i
< 32; i
++)
85 if (vol
> table_5bit
[i
])
93 static AROS_INTP(play_int
);
96 /******************************************************************************
97 ** AHIsub_AllocAudio **********************************************************
98 ******************************************************************************/
101 _AHIsub_AllocAudio( struct TagItem
* taglist
,
102 struct AHIAudioCtrlDrv
* AudioCtrl
,
103 struct DriverBase
* AHIsubBase
)
105 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
107 AudioCtrl
->ahiac_DriverData
= AllocVec( sizeof( struct AC97Data
),
108 MEMF_CLEAR
| MEMF_PUBLIC
);
110 #define dd ((struct AC97Data *) AudioCtrl->ahiac_DriverData)
112 D(bug("AHI: AllocAudio: dd=%08x\n", dd
));
116 dd
->slavesignal
= -1;
117 dd
->mastersignal
= AllocSignal( -1 );
118 dd
->mastertask
= (struct Process
*) FindTask( NULL
);
119 dd
->ahisubbase
= ac97Base
;
120 dd
->out_volume
= 0x10000;
128 dd
->irq
.is_Node
.ln_Type
= NT_INTERRUPT
;
129 dd
->irq
.is_Node
.ln_Pri
= 0;
130 dd
->irq
.is_Node
.ln_Name
= "AHI Int";
131 dd
->irq
.is_Code
= (APTR
)play_int
;
132 dd
->irq
.is_Data
= AudioCtrl
;
134 AddIntServer(INTB_KERNEL
+ ac97Base
->irq_num
, &dd
->irq
);
137 D(bug("AHI: AllocAudio: Everything OK\n"));
139 if( dd
->mastersignal
== -1 )
144 /* Setting the only working frequency for AC97 */
145 AudioCtrl
->ahiac_MixFreq
= 48000;
147 return ( AHISF_KNOWSTEREO
|
153 /******************************************************************************
154 ** AHIsub_FreeAudio ***********************************************************
155 ******************************************************************************/
158 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv
* AudioCtrl
,
159 struct DriverBase
* AHIsubBase
)
161 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
163 D(bug("AHI: FreeAudio\n"));
165 RemIntServer(INTB_KERNEL
+ ac97Base
->irq_num
, &dd
->irq
);
167 D(bug("AHI: FreeAudio: IRQ removed\n"));
169 if( AudioCtrl
->ahiac_DriverData
!= NULL
)
171 FreeSignal( dd
->mastersignal
);
173 D(bug("AHI: FreeAudio: Signal freed\n"));
175 FreeVec( AudioCtrl
->ahiac_DriverData
);
177 D(bug("AHI: FreeAudio: DriverData freed\n"));
179 AudioCtrl
->ahiac_DriverData
= NULL
;
184 /******************************************************************************
185 ** AHIsub_Disable *************************************************************
186 ******************************************************************************/
189 _AHIsub_Disable( struct AHIAudioCtrlDrv
* AudioCtrl
,
190 struct DriverBase
* AHIsubBase
)
192 // V6 drivers do not have to preserve all registers
198 /******************************************************************************
199 ** AHIsub_Enable **************************************************************
200 ******************************************************************************/
203 _AHIsub_Enable( struct AHIAudioCtrlDrv
* AudioCtrl
,
204 struct DriverBase
* AHIsubBase
)
206 // V6 drivers do not have to preserve all registers
212 /******************************************************************************
213 ** AHIsub_Start ***************************************************************
214 ******************************************************************************/
217 _AHIsub_Start( ULONG flags
,
218 struct AHIAudioCtrlDrv
* AudioCtrl
,
219 struct DriverBase
* AHIsubBase
)
221 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
223 D(bug("AHI: Start\n"));
225 AHIsub_Stop( flags
, AudioCtrl
);
227 D(bug("AHI: Start: Stop called\n"));
229 if(flags
& AHISF_PLAY
)
231 struct TagItem proctags
[] =
233 { NP_Entry
, (IPTR
) &slaveentry
},
234 { NP_Name
, (IPTR
) LibName
},
239 dd
->mixbuffer
= AllocVec( AudioCtrl
->ahiac_BuffSize
,
240 MEMF_ANY
| MEMF_PUBLIC
);
242 D(bug("AHI: Start: Mixing buffer = %08x\n",dd
->mixbuffer
));
244 if( dd
->mixbuffer
== NULL
) return AHIE_NOMEM
;
248 dd
->slavetask
= CreateNewProc( proctags
);
250 D(bug("AHI: Start: Slave task = %08x\n",dd
->slavetask
));
252 if( dd
->slavetask
!= NULL
)
254 dd
->slavetask
->pr_Task
.tc_UserData
= AudioCtrl
;
257 D(bug("AHI: Start: Slave task UserData set\n"));
261 if( dd
->slavetask
!= NULL
)
263 Wait( 1L << dd
->mastersignal
); // Wait for slave to come alive
265 D(bug("AHI: Start: Slave task UP and running\n"));
267 if( dd
->slavetask
== NULL
) // Is slave alive or dead?
274 return AHIE_NOMEM
; // Well, out of memory or whatever...
278 if( flags
& AHISF_RECORD
)
283 D(bug("AHI: Start: Everything OK\n"));
289 /******************************************************************************
290 ** AHIsub_Update **************************************************************
291 ******************************************************************************/
294 _AHIsub_Update( ULONG flags
,
295 struct AHIAudioCtrlDrv
* AudioCtrl
,
296 struct DriverBase
* AHIsubBase
)
302 /******************************************************************************
303 ** AHIsub_Stop ****************************************************************
304 ******************************************************************************/
307 _AHIsub_Stop( ULONG flags
,
308 struct AHIAudioCtrlDrv
* AudioCtrl
,
309 struct DriverBase
* AHIsubBase
)
311 if( flags
& AHISF_PLAY
)
313 if( dd
->slavetask
!= NULL
)
315 if( dd
->slavesignal
!= -1 )
317 Signal( (struct Task
*) dd
->slavetask
,
318 1L << dd
->slavesignal
); // Kill him!
321 Wait( 1L << dd
->mastersignal
); // Wait for slave to die
324 FreeVec( dd
->mixbuffer
);
325 dd
->mixbuffer
= NULL
;
328 if(flags
& AHISF_RECORD
)
335 /******************************************************************************
336 ** AHIsub_GetAttr *************************************************************
337 ******************************************************************************/
340 _AHIsub_GetAttr( ULONG attribute
,
343 struct TagItem
* taglist
,
344 struct AHIAudioCtrlDrv
* AudioCtrl
,
345 struct DriverBase
* AHIsubBase
)
354 case AHIDB_Frequencies
:
357 case AHIDB_Frequency
: // Index->Frequency
358 return (LONG
) frequencies
[ argument
];
360 case AHIDB_Index
: // Frequency->Index
361 if( argument
<= frequencies
[ 0 ] )
366 if( argument
>= frequencies
[ FREQUENCIES
- 1 ] )
368 return FREQUENCIES
- 1;
371 for( i
= 1; i
< FREQUENCIES
; i
++ )
373 if( frequencies
[ i
] > argument
)
375 if( ( argument
- frequencies
[ i
- 1 ] ) <
376 ( frequencies
[ i
] - argument
) )
387 return 0; // Will not happen
390 return (IPTR
) "Michal Schulz";
392 case AHIDB_Copyright
:
396 return (IPTR
) LibIDString
;
408 case AHIDB_MinMonitorVolume:
411 case AHIDB_MaxMonitorVolume:
414 case AHIDB_MinOutputVolume
:
417 case AHIDB_MaxOutputVolume
:
421 return (IPTR
) "Default"; // We have only one "output"!
429 /******************************************************************************
430 ** AHIsub_HardwareControl *****************************************************
431 ******************************************************************************/
434 _AHIsub_HardwareControl( ULONG attribute
,
436 struct AHIAudioCtrlDrv
* AudioCtrl
,
437 struct DriverBase
* AHIsubBase
)
439 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
444 case AHIC_OutputVolume
:
445 vol
= LinToLog(argument
);
447 if (vol
== 0x20) vol
= 0x8000;
448 else vol
= vol
| vol
<< 8;
450 D(bug("SetVol %05x translated to %04x\n", argument
, vol
));
451 dd
->out_volume
= argument
;
452 if (ac97Base
->mixer_set_reg
)
453 ac97Base
->mixer_set_reg(ac97Base
, AC97_PCM_VOL
, vol
);
456 case AHIC_OutputVolume_Query
:
457 return dd
->out_volume
;
465 static AROS_INTH1(play_int
, struct AHIAudioCtrlDrv
*, AudioCtrl
)
469 struct DriverBase
* AHIsubBase
;
470 struct ac97Base
* ac97Base
;
472 AHIsubBase
= (struct DriverBase
*) dd
->ahisubbase
;
473 ac97Base
= (struct ac97Base
*) AHIsubBase
;
475 dd
->old_SR
= inw(ac97Base
->dmabase
+ ac97Base
->off_po_sr
);
476 outw(dd
->old_SR
& 0x1c, ac97Base
->dmabase
+ ac97Base
->off_po_sr
);
478 if ((dd
->old_SR
& 0x1c) && dd
->slavetask
)
480 /* Signaling the slave task */
481 Signal((struct Task
*)dd
->slavetask
, SIGBREAKF_CTRL_E
);