2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Paula audio.device
10 #include <aros/debug.h>
12 #include <exec/resident.h>
13 #include <exec/errors.h>
14 #include <exec/memory.h>
15 #include <exec/lists.h>
16 #include <exec/alerts.h>
17 #include <exec/tasks.h>
18 #include <exec/interrupts.h>
19 #include <devices/audio.h>
20 #include <hardware/intbits.h>
21 #include <hardware/custom.h>
23 #include <proto/exec.h>
25 #include "audio_intern.h"
27 void audiohw_stop(struct AudioBase
*ab
, UWORD mask
)
29 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
33 custom
->dmacon
= mask
;
34 custom
->intena
= mask
<< INTB_AUD0
;
37 void audiohw_prepareptlen(struct AudioBase
*ab
, struct IOAudio
*io
, UBYTE ch
)
39 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
41 if (ab
->cycles
[ch
] != 1)
44 custom
->aud
[ch
].ac_ptr
= (UWORD
*)io
->ioa_Data
;
45 custom
->aud
[ch
].ac_len
= io
->ioa_Length
/ 2;
46 ab
->cycles
[ch
] = io
->ioa_Cycles
;
47 D(bug("ch%d: pt=%08x len=%d cyc=%d\n", ch
, io
->ioa_Data
, io
->ioa_Length
/ 2, io
->ioa_Cycles
));
49 custom
->aud
[ch
].ac_ptr
= ab
->zerosample
;
50 custom
->aud
[ch
].ac_len
= 1;
51 D(bug("ch%d: null\n", ch
));
53 ab
->initialcyclemask
&= ~(1 << ch
);
56 void audiohw_preparepervol(struct AudioBase
*ab
, struct IOAudio
*io
, UBYTE ch
)
58 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
60 if (io
&& (io
->ioa_Request
.io_Flags
& ADIOF_PERVOL
)) {
61 custom
->aud
[ch
].ac_per
= io
->ioa_Period
;
62 custom
->aud
[ch
].ac_vol
= io
->ioa_Volume
;
63 D(bug("ch%d: per=%d vol=%d\n", ch
, io
->ioa_Period
, io
->ioa_Volume
));
67 static void audioirq(struct AudioBase
*ab
, UBYTE ch
)
69 struct IOAudio
*io
= getnextwrite(ab
, ch
, FALSE
);
72 D(bug("audio: ch %d interrupt, io %p %04x %04x %04x %d\n", ch
, io
, ab
->initialcyclemask
, ab
->initialdmamask
, ab
->stopmask
, ab
->cycles
[ch
]));
74 if (!io
|| (ab
->stopmask
& mask
)) {
75 audiohw_stop(ab
, mask
);
76 D(bug("ch%d: finished\n", ch
));
80 if (!(ab
->initialdmamask
& mask
)) {
81 D(bug("audio: ch%d startup interrupt\n", ch
));
82 ab
->initialdmamask
|= mask
;
83 if (io
->ioa_Request
.io_Flags
& ADIOF_WRITEMESSAGE
)
84 ReplyMsg(&io
->ioa_WriteMsg
);
85 io
= getnextwrite(ab
, ch
, TRUE
);
86 audiohw_prepareptlen(ab
, io
, ch
);
88 struct IOAudio
*wio
, *next
;
89 struct IOAudio
*io2
= getnextwrite(ab
, ch
, TRUE
);
91 if (!(ab
->initialcyclemask
& mask
)) {
92 ab
->initialcyclemask
|= mask
;
93 audiohw_preparepervol(ab
, io2
, ch
);
94 if (io2
&& (io2
->ioa_Request
.io_Flags
& ADIOF_WRITEMESSAGE
))
95 ReplyMsg(&io2
->ioa_WriteMsg
);
98 if (ab
->cycles
[ch
] == 1) {
100 ReplyMsg(&io
->ioa_Request
.io_Message
);
101 io
= getnextwrite(ab
, ch
, TRUE
);
102 D(bug("audio: ch%d next io %p\n", ch
, io
));
103 audiohw_prepareptlen(ab
, io
, ch
);
104 } else if (ab
->cycles
[ch
]) {
108 /* Does ADIOF_SYNCCYCLE mean end of any cycle or only when cycle count == 1?
109 * Documentation isn't clear about this ("end of current cycle")
110 * This assumes "end of any cycle"
112 ForeachNodeSafe(&ab
->misclist
, wio
, next
) {
113 UWORD cmd
= wio
->ioa_Request
.io_Command
;
114 UBYTE cmask
= (UBYTE
)(ULONG
)wio
->ioa_Request
.io_Unit
;
115 if (cmd
!= ADCMD_PERVOL
&& cmd
!= ADCMD_FINISH
&& cmd
!= ADCMD_WAITCYCLE
)
119 if (cmask
& (mask
<< NR_CH
)) {
120 if (cmd
== ADCMD_PERVOL
)
121 audiohw_preparepervol(ab
, wio
, ch
);
123 cmask
&= ~(mask
<< NR_CH
);
124 if ((cmask
>> NR_CH
) == 0) {
125 D(bug("audio: ch %d SYNCCYCLE woken up, io %p\n", ch
, wio
));
127 ReplyMsg(&wio
->ioa_Request
.io_Message
);
134 AROS_INTH1(audio_int
, struct AudioInterrupt
*, ai
)
138 audioirq(ai
->ab
, ai
->ch
);
145 void audiohw_reset(struct AudioBase
*ab
, UWORD mask
)
147 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
150 custom
->adkcon
= mask
| (mask
<< 4);
151 custom
->dmacon
= mask
;
152 custom
->intena
= mask
<< INTB_AUD0
;
153 custom
->intreq
= mask
<< INTB_AUD0
;
154 for (ch
= 0; ch
< 4; ch
++) {
155 if ((1 << ch
) & mask
) {
156 custom
->aud
[ch
].ac_vol
= 0;
157 custom
->aud
[ch
].ac_per
= 100;
162 static void preparech_initial(struct AudioBase
*ab
, UBYTE ch
)
164 struct IOAudio
*io
= getnextwrite(ab
, ch
, FALSE
);
166 audiohw_prepareptlen(ab
, io
, ch
);
167 audiohw_preparepervol(ab
, io
, ch
);
168 ab
->initialdmamask
&= ~(1 << ch
);
169 ab
->initialcyclemask
|= 1 << ch
;
172 void audiohw_start(struct AudioBase
*ab
, UWORD mask
)
174 volatile struct Custom
*custom
= (struct Custom
*)0xdff000;
181 for (ch
= 0; ch
< NR_CH
; ch
++) {
182 if ((mask
& (1 << ch
)) && getnextwrite(ab
, ch
, FALSE
)) {
184 preparech_initial(ab
, ch
);
187 D(bug("hw_start: %02x\n", hwmask
));
189 custom
->intreq
= hwmask
<< INTB_AUD0
;
190 custom
->intena
= INTF_SETCLR
| (hwmask
<< INTB_AUD0
);
191 custom
->dmacon
= 0x8000 | hwmask
;
195 void audiohw_init(struct AudioBase
*ab
)
199 audiohw_reset(ab
, CH_MASK
);
200 for (ch
= 0; ch
< NR_CH
; ch
++) {
201 struct AudioInterrupt
*inter
= &ab
->audint
[ch
];
202 inter
->audint
.is_Code
= (APTR
)audio_int
;
203 inter
->audint
.is_Data
= inter
;
204 inter
->audint
.is_Node
.ln_Name
= "audio";
205 inter
->audint
.is_Node
.ln_Type
= NT_INTERRUPT
;
208 SetIntVector(INTB_AUD0
+ ch
, &inter
->audint
);