Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / AHI / Drivers / Alsa / alsa-main.c
blobef5e9c82107d59228162ff505d539183b9f0edd6
1 #include <aros/debug.h>
2 #include <config.h>
4 #include <devices/ahi.h>
5 #include <dos/dostags.h>
6 #include <exec/memory.h>
7 #include <libraries/ahi_sub.h>
8 #include <proto/ahi_sub.h>
9 #include <proto/exec.h>
10 #include <proto/dos.h>
11 #include <proto/utility.h>
13 #include <stddef.h>
15 #include "library.h"
16 #include "DriverData.h"
17 #include "alsa-bridge/alsa.h"
19 #define dd ((struct AlsaData*) AudioCtrl->ahiac_DriverData)
21 void
22 SlaveEntry( void );
24 PROCGW( static, void, slaveentry, SlaveEntry );
26 static const LONG frequencies[] =
28 8000, // ยต- and A-Law (telephone)
29 11025, // CD/4
30 22050, // CD/2
31 44100, // CD
32 48000 // DAT
35 #define FREQUENCIES (sizeof frequencies / sizeof frequencies[ 0 ])
37 static const ULONG table_5bit[] = {
38 0xb53c,
39 0x804e,
40 0x5ad5,
41 0x404e,
42 0x2d86,
43 0x203a,
44 0x16d1,
45 0x1027,
46 0x0b6f,
47 0x0818,
48 0x05bb,
49 0x040f,
50 0x02df,
51 0x0209,
52 0x0171,
53 0x0105,
54 0x00b9,
55 0x0083,
56 0x005d,
57 0x0042,
58 0x002e,
59 0x0021,
60 0x0017,
61 0x0010,
62 0x000c,
63 0x0008,
64 0x0006,
65 0x0004,
66 0x0003,
67 0x0002,
68 0x0001,
69 0x0000
72 static UWORD LinToLog(ULONG vol)
74 int i;
76 if (!vol) return 0x20;
78 for (i = 0; i < 32; i++)
80 if (vol > table_5bit[i])
82 return i;
85 return 0x1f;
88 static ULONG LogToLin(UWORD i)
90 if (i > 31) return 0x10000;
91 return table_5bit[i];
94 /******************************************************************************
95 ** AHIsub_AllocAudio **********************************************************
96 ******************************************************************************/
98 ULONG
99 _AHIsub_AllocAudio( struct TagItem* taglist,
100 struct AHIAudioCtrlDrv* AudioCtrl,
101 struct DriverBase* AHIsubBase )
103 struct AlsaBase* AlsaBase = (struct AlsaBase*) AHIsubBase;
104 ULONG freq = AudioCtrl->ahiac_MixFreq;
106 D(bug("[Alsa]: AllocAudio enter\n"));
108 AudioCtrl->ahiac_DriverData = AllocVec( sizeof( struct AlsaData ),
109 MEMF_CLEAR | MEMF_PUBLIC );
111 if( dd != NULL )
113 dd->slavesignal = -1;
114 dd->mastersignal = AllocSignal( -1 );
115 dd->mastertask = (struct Process*) FindTask( NULL );
116 dd->ahisubbase = AlsaBase;
118 else
120 return AHISF_ERROR;
123 if( dd->mastersignal == -1 )
125 return AHISF_ERROR;
128 dd->alsahandle = ALSA_Open();
130 if (dd->alsahandle == NULL)
132 bug("[Alsa]: Failed opening ALSA\n");
133 return AHISF_ERROR;
136 if (!ALSA_SetHWParams(dd->alsahandle, &freq))
138 bug("[Alsa]: Failed setting ALSA hardware parameters\n");
139 ALSA_DropAndClose(dd->alsahandle);
140 dd->alsahandle = NULL;
141 return AHISF_ERROR;
144 AudioCtrl->ahiac_MixFreq = freq;
146 D(bug("[Alsa]: AllocAudio completed\n"));
148 return ( AHISF_KNOWSTEREO | AHISF_MIXING | AHISF_TIMING );
152 /******************************************************************************
153 ** AHIsub_FreeAudio ***********************************************************
154 ******************************************************************************/
156 void
157 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv* AudioCtrl,
158 struct DriverBase* AHIsubBase )
160 if( AudioCtrl->ahiac_DriverData != NULL )
162 ALSA_DropAndClose(dd->alsahandle);
163 FreeSignal( dd->mastersignal );
164 FreeVec( AudioCtrl->ahiac_DriverData );
165 AudioCtrl->ahiac_DriverData = NULL;
170 /******************************************************************************
171 ** AHIsub_Disable *************************************************************
172 ******************************************************************************/
174 void
175 _AHIsub_Disable( struct AHIAudioCtrlDrv* AudioCtrl,
176 struct DriverBase* AHIsubBase )
178 // V6 drivers do not have to preserve all registers
180 Forbid();
184 /******************************************************************************
185 ** AHIsub_Enable **************************************************************
186 ******************************************************************************/
188 void
189 _AHIsub_Enable( struct AHIAudioCtrlDrv* AudioCtrl,
190 struct DriverBase* AHIsubBase )
192 // V6 drivers do not have to preserve all registers
194 Permit();
198 /******************************************************************************
199 ** AHIsub_Start ***************************************************************
200 ******************************************************************************/
202 ULONG
203 _AHIsub_Start( ULONG flags,
204 struct AHIAudioCtrlDrv* AudioCtrl,
205 struct DriverBase* AHIsubBase )
207 struct AlsaBase* AlsaBase = (struct AlsaBase*) AHIsubBase;
209 AHIsub_Stop( flags, AudioCtrl );
211 if(flags & AHISF_PLAY)
213 struct TagItem proctags[] =
215 { NP_Entry, (IPTR) &slaveentry },
216 { NP_Name, (IPTR) LibName },
217 { NP_Priority, 127 },
218 { TAG_DONE, 0 }
221 dd->mixbuffer = AllocVec( AudioCtrl->ahiac_BuffSize,
222 MEMF_ANY | MEMF_PUBLIC );
224 if( dd->mixbuffer == NULL ) return AHIE_NOMEM;
226 D(bug("[Alsa]: AHIsub_Start\n"));
228 Forbid();
230 dd->slavetask = CreateNewProc( proctags );
232 if( dd->slavetask != NULL )
234 dd->slavetask->pr_Task.tc_UserData = AudioCtrl;
237 Permit();
239 if( dd->slavetask != NULL )
241 Wait( 1L << dd->mastersignal ); // Wait for slave to come alive
243 if( dd->slavetask == NULL ) // Is slave alive or dead?
245 return AHIE_UNKNOWN;
248 else
250 return AHIE_NOMEM; // Well, out of memory or whatever...
254 if( flags & AHISF_RECORD )
256 return AHIE_UNKNOWN;
259 return AHIE_OK;
263 /******************************************************************************
264 ** AHIsub_Update **************************************************************
265 ******************************************************************************/
267 void
268 _AHIsub_Update( ULONG flags,
269 struct AHIAudioCtrlDrv* AudioCtrl,
270 struct DriverBase* AHIsubBase )
272 // Empty function
276 /******************************************************************************
277 ** AHIsub_Stop ****************************************************************
278 ******************************************************************************/
280 void
281 _AHIsub_Stop( ULONG flags,
282 struct AHIAudioCtrlDrv* AudioCtrl,
283 struct DriverBase* AHIsubBase )
285 if( flags & AHISF_PLAY )
287 if( dd->slavetask != NULL )
289 if( dd->slavesignal != -1 )
291 Signal( (struct Task*) dd->slavetask,
292 1L << dd->slavesignal ); // Kill him!
293 D(bug("[Alsa]: AHIsub_Stop\n"));
296 Wait( 1L << dd->mastersignal ); // Wait for slave to die
299 FreeVec( dd->mixbuffer );
300 dd->mixbuffer = NULL;
303 if(flags & AHISF_RECORD)
305 // Do nothing
310 /******************************************************************************
311 ** AHIsub_GetAttr *************************************************************
312 ******************************************************************************/
314 IPTR
315 _AHIsub_GetAttr( ULONG attribute,
316 LONG argument,
317 IPTR def,
318 struct TagItem* taglist,
319 struct AHIAudioCtrlDrv* AudioCtrl,
320 struct DriverBase* AHIsubBase )
322 struct AlsaBase* AlsaBase = (struct AlsaBase*) AHIsubBase;
323 size_t i;
325 switch( attribute )
327 case AHIDB_Bits:
328 return 32;
330 case AHIDB_Frequencies:
331 return FREQUENCIES;
333 case AHIDB_Frequency: // Index->Frequency
334 return (LONG) frequencies[ argument ];
336 case AHIDB_Index: // Frequency->Index
337 if( argument <= frequencies[ 0 ] )
339 return 0;
342 if( argument >= frequencies[ FREQUENCIES - 1 ] )
344 return FREQUENCIES - 1;
347 for( i = 1; i < FREQUENCIES; i++ )
349 if( frequencies[ i ] > argument )
351 if( ( argument - frequencies[ i - 1 ] ) <
352 ( frequencies[ i ] - argument ) )
354 return i-1;
356 else
358 return i;
363 return 0; // Will not happen
365 case AHIDB_Author:
366 return (IPTR) "Krzysztof Smiechowicz";
368 case AHIDB_Copyright:
369 return (IPTR) "APL";
371 case AHIDB_Version:
372 return (IPTR) LibIDString;
374 case AHIDB_Record:
375 return FALSE;
377 case AHIDB_Realtime:
378 return TRUE;
380 case AHIDB_Outputs:
381 return 1;
383 case AHIDB_Output:
384 return (IPTR) "Alsa"; // We have only one "output"!
386 case AHIDB_MinOutputVolume:
387 return 0x00000;
389 case AHIDB_MaxOutputVolume:
390 if (AlsaBase->al_MixerElem)
391 return 0x10000;
392 else
393 return 0x00000;
395 default:
396 return def;
401 /******************************************************************************
402 ** AHIsub_HardwareControl *****************************************************
403 ******************************************************************************/
405 ULONG
406 _AHIsub_HardwareControl( ULONG attribute,
407 LONG argument,
408 struct AHIAudioCtrlDrv* AudioCtrl,
409 struct DriverBase* AHIsubBase )
411 struct AlsaBase* AlsaBase = (struct AlsaBase*) AHIsubBase;
413 switch(attribute)
415 case AHIC_OutputVolume:
416 if (AlsaBase->al_MixerElem)
418 LONG val = (0x20 - LinToLog(argument)) * AlsaBase->al_MaxVolume / 0x20;
419 ALSA_MixerSetVolume(AlsaBase->al_MixerElem, (LONG)val);
422 return TRUE;
424 case AHIC_OutputVolume_Query:
425 if (AlsaBase->al_MixerElem)
427 LONG val = ALSA_MixerGetVolume(AlsaBase->al_MixerElem);
428 val = val * 0x20 / AlsaBase->al_MaxVolume;
429 return LogToLin(0x20 - val);
432 return 0;
435 return 0;