3 #include <aros/debug.h>
7 #include <devices/ahi.h>
8 #include <dos/dostags.h>
9 #include <exec/memory.h>
10 #include <libraries/ahi_sub.h>
11 #include <utility/tagitem.h>
13 #include <proto/ahi_sub.h>
14 #include <proto/exec.h>
15 #include <proto/dos.h>
16 #include <proto/utility.h>
23 #include "DriverData.h"
28 PROCGW( static, void, slaveentry
, SlaveEntry
);
31 /* There is probably no reason to support all these frequencies. If,
32 * for example, your hardware is locked at 48 kHz, it's ok to only
33 * present one single mixing/recording frequency to the user. If your
34 * hardware has internal resamples and accepts any frequency, select a
38 static const LONG frequencies
[] =
43 #define FREQUENCIES (sizeof frequencies / sizeof frequencies[ 0 ])
45 static const ULONG table_5bit
[] = {
80 static UWORD
LinToLog(ULONG vol
)
84 if (!vol
) return 0x20;
86 for (i
=0; i
< 32; i
++)
88 if (vol
> table_5bit
[i
])
96 static void play_int(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
);
99 /******************************************************************************
100 ** AHIsub_AllocAudio **********************************************************
101 ******************************************************************************/
104 _AHIsub_AllocAudio( struct TagItem
* taglist
,
105 struct AHIAudioCtrlDrv
* AudioCtrl
,
106 struct DriverBase
* AHIsubBase
)
108 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
109 OOP_Object
*irq
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
112 AudioCtrl
->ahiac_DriverData
= AllocVec( sizeof( struct AC97Data
),
113 MEMF_CLEAR
| MEMF_PUBLIC
);
115 #define dd ((struct AC97Data *) AudioCtrl->ahiac_DriverData)
117 D(bug("AHI: AllocAudio: dd=%08x\n", dd
));
121 dd
->slavesignal
= -1;
122 dd
->mastersignal
= AllocSignal( -1 );
123 dd
->mastertask
= (struct Process
*) FindTask( NULL
);
124 dd
->ahisubbase
= ac97Base
;
125 dd
->out_volume
= 0x10000;
132 dd
->irq
= AllocVec(sizeof (HIDDT_IRQ_Handler
), MEMF_CLEAR
| MEMF_PUBLIC
);
136 struct pHidd_IRQ_AddHandler __msg__
= {
137 mID
: OOP_GetMethodID(CLID_Hidd_IRQ
, moHidd_IRQ_AddHandler
),
138 handlerinfo
: dd
->irq
,
139 id
: ac97Base
->irq_num
,
142 dd
->irq
->h_Node
.ln_Pri
= 0;
143 dd
->irq
->h_Node
.ln_Name
= "AHI Int";
144 dd
->irq
->h_Code
= play_int
;
145 dd
->irq
->h_Data
= AudioCtrl
;
147 OOP_DoMethod(irq
, (OOP_Msg
)msg
);
149 OOP_DisposeObject(irq
);
152 D(bug("AHI: AllocAudio: Everything OK\n"));
154 if( dd
->mastersignal
== -1 )
159 /* Setting the only working frequency for AC97 */
160 AudioCtrl
->ahiac_MixFreq
= 48000;
162 return ( AHISF_KNOWSTEREO
|
168 /******************************************************************************
169 ** AHIsub_FreeAudio ***********************************************************
170 ******************************************************************************/
173 _AHIsub_FreeAudio( struct AHIAudioCtrlDrv
* AudioCtrl
,
174 struct DriverBase
* AHIsubBase
)
176 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
177 OOP_Object
*irq
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
);
179 D(bug("AHI: FreeAudio\n"));
183 struct pHidd_IRQ_RemHandler __msg__
= {
184 mID
: OOP_GetMethodID(CLID_Hidd_IRQ
, moHidd_IRQ_RemHandler
),
185 handlerinfo
: dd
->irq
,
187 OOP_DoMethod(irq
, (OOP_Msg
)msg
);
191 D(bug("AHI: FreeAudio: IRQ removed\n"));
193 if( AudioCtrl
->ahiac_DriverData
!= NULL
)
195 FreeSignal( dd
->mastersignal
);
197 D(bug("AHI: FreeAudio: Signal freed\n"));
199 FreeVec( AudioCtrl
->ahiac_DriverData
);
201 D(bug("AHI: FreeAudio: DriverData freed\n"));
203 AudioCtrl
->ahiac_DriverData
= NULL
;
206 OOP_DisposeObject(irq
);
208 D(bug("AHI: FreeAudio: IRQ object freed\n"));
213 /******************************************************************************
214 ** AHIsub_Disable *************************************************************
215 ******************************************************************************/
218 _AHIsub_Disable( struct AHIAudioCtrlDrv
* AudioCtrl
,
219 struct DriverBase
* AHIsubBase
)
221 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
223 // V6 drivers do not have to preserve all registers
229 /******************************************************************************
230 ** AHIsub_Enable **************************************************************
231 ******************************************************************************/
234 _AHIsub_Enable( struct AHIAudioCtrlDrv
* AudioCtrl
,
235 struct DriverBase
* AHIsubBase
)
237 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
239 // V6 drivers do not have to preserve all registers
245 /******************************************************************************
246 ** AHIsub_Start ***************************************************************
247 ******************************************************************************/
250 _AHIsub_Start( ULONG flags
,
251 struct AHIAudioCtrlDrv
* AudioCtrl
,
252 struct DriverBase
* AHIsubBase
)
254 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
256 D(bug("AHI: Start\n"));
258 AHIsub_Stop( flags
, AudioCtrl
);
260 D(bug("AHI: Start: Stop called\n"));
262 if(flags
& AHISF_PLAY
)
264 struct TagItem proctags
[] =
266 { NP_Entry
, (IPTR
) &slaveentry
},
267 { NP_Name
, (IPTR
) LibName
},
272 dd
->mixbuffer
= AllocVec( AudioCtrl
->ahiac_BuffSize
,
273 MEMF_ANY
| MEMF_PUBLIC
);
275 D(bug("AHI: Start: Mixing buffer = %08x\n",dd
->mixbuffer
));
277 if( dd
->mixbuffer
== NULL
) return AHIE_NOMEM
;
281 dd
->slavetask
= CreateNewProc( proctags
);
283 D(bug("AHI: Start: Slave task = %08x\n",dd
->slavetask
));
285 if( dd
->slavetask
!= NULL
)
287 dd
->slavetask
->pr_Task
.tc_UserData
= AudioCtrl
;
290 D(bug("AHI: Start: Slave task UserData set\n"));
294 if( dd
->slavetask
!= NULL
)
296 Wait( 1L << dd
->mastersignal
); // Wait for slave to come alive
298 D(bug("AHI: Start: Slave task UP and running\n"));
300 if( dd
->slavetask
== NULL
) // Is slave alive or dead?
307 return AHIE_NOMEM
; // Well, out of memory or whatever...
311 if( flags
& AHISF_RECORD
)
316 D(bug("AHI: Start: Everything OK\n"));
322 /******************************************************************************
323 ** AHIsub_Update **************************************************************
324 ******************************************************************************/
327 _AHIsub_Update( ULONG flags
,
328 struct AHIAudioCtrlDrv
* AudioCtrl
,
329 struct DriverBase
* AHIsubBase
)
331 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
337 /******************************************************************************
338 ** AHIsub_Stop ****************************************************************
339 ******************************************************************************/
342 _AHIsub_Stop( ULONG flags
,
343 struct AHIAudioCtrlDrv
* AudioCtrl
,
344 struct DriverBase
* AHIsubBase
)
346 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
348 if( flags
& AHISF_PLAY
)
350 if( dd
->slavetask
!= NULL
)
352 if( dd
->slavesignal
!= -1 )
354 Signal( (struct Task
*) dd
->slavetask
,
355 1L << dd
->slavesignal
); // Kill him!
358 Wait( 1L << dd
->mastersignal
); // Wait for slave to die
361 FreeVec( dd
->mixbuffer
);
362 dd
->mixbuffer
= NULL
;
365 if(flags
& AHISF_RECORD
)
372 /******************************************************************************
373 ** AHIsub_GetAttr *************************************************************
374 ******************************************************************************/
377 _AHIsub_GetAttr( ULONG attribute
,
380 struct TagItem
* taglist
,
381 struct AHIAudioCtrlDrv
* AudioCtrl
,
382 struct DriverBase
* AHIsubBase
)
384 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
392 case AHIDB_Frequencies
:
395 case AHIDB_Frequency
: // Index->Frequency
396 return (LONG
) frequencies
[ argument
];
398 case AHIDB_Index
: // Frequency->Index
399 if( argument
<= frequencies
[ 0 ] )
404 if( argument
>= frequencies
[ FREQUENCIES
- 1 ] )
406 return FREQUENCIES
- 1;
409 for( i
= 1; i
< FREQUENCIES
; i
++ )
411 if( frequencies
[ i
] > argument
)
413 if( ( argument
- frequencies
[ i
- 1 ] ) <
414 ( frequencies
[ i
] - argument
) )
425 return 0; // Will not happen
428 return (IPTR
) "Michal Schulz";
430 case AHIDB_Copyright
:
434 return (IPTR
) LibIDString
;
446 case AHIDB_MinMonitorVolume:
449 case AHIDB_MaxMonitorVolume:
452 case AHIDB_MinOutputVolume
:
455 case AHIDB_MaxOutputVolume
:
459 return (IPTR
) "Default"; // We have only one "output"!
467 /******************************************************************************
468 ** AHIsub_HardwareControl *****************************************************
469 ******************************************************************************/
472 _AHIsub_HardwareControl( ULONG attribute
,
474 struct AHIAudioCtrlDrv
* AudioCtrl
,
475 struct DriverBase
* AHIsubBase
)
477 struct ac97Base
* ac97Base
= (struct ac97Base
*) AHIsubBase
;
482 case AHIC_OutputVolume
:
483 vol
= LinToLog(argument
);
485 if (vol
== 0x20) vol
= 0x8000;
486 else vol
= vol
| vol
<< 8;
488 D(bug("SetVol %05x translated to %04x\n", argument
, vol
));
489 dd
->out_volume
= argument
;
490 if (ac97Base
->mixer_set_reg
)
491 ac97Base
->mixer_set_reg(ac97Base
, AC97_PCM_VOL
, vol
);
494 case AHIC_OutputVolume_Query
:
495 return dd
->out_volume
;
502 static void play_int(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
504 struct AHIAudioCtrlDrv
* AudioCtrl
;
505 struct DriverBase
* AHIsubBase
;
506 struct ac97Base
* ac97Base
;
507 struct ExecBase
*SysBase
;
509 AudioCtrl
= (struct AHIAudioCtrlDrv
*) irq
->h_Data
;
510 AHIsubBase
= (struct DriverBase
*) dd
->ahisubbase
;
511 ac97Base
= (struct ac97Base
*) AHIsubBase
;
512 SysBase
= (struct SysBase
*) ac97Base
->sysbase
;
514 dd
->old_SR
= inw(ac97Base
->dmabase
+ ac97Base
->off_po_sr
);
515 outw(dd
->old_SR
& 0x1c, ac97Base
->dmabase
+ ac97Base
->off_po_sr
);
517 if ((dd
->old_SR
& 0x1c) && dd
->slavetask
)
519 /* Signaling the slave task */
520 Signal((struct Task
*)dd
->slavetask
, SIGBREAKF_CTRL_E
);