Added a test for MUIA_Listview_SelectChange.
[AROS.git] / arch / m68k-amiga / devs / audio / audio_hardware.c
blob00a811a7075203f5ba2d78a5d68e9040b3ac6bc6
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Paula audio.device
6 Lang: English
7 */
9 #define DEBUG 0
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;
31 if (!mask)
32 return;
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)
42 return;
43 if (io) {
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));
48 } else {
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);
70 UBYTE mask = 1 << ch;
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));
77 return;
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);
87 } else {
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) {
99 REMOVE(io);
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]) {
105 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)
116 continue;
117 if (!(cmask & mask))
118 continue;
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));
126 REMOVE(wio);
127 ReplyMsg(&wio->ioa_Request.io_Message);
134 AROS_INTH1(audio_int, struct AudioInterrupt *, ai)
136 AROS_INTFUNC_INIT
138 audioirq(ai->ab, ai->ch);
140 return 0;
142 AROS_INTFUNC_EXIT
145 void audiohw_reset(struct AudioBase *ab, UWORD mask)
147 volatile struct Custom *custom = (struct Custom*)0xdff000;
148 UBYTE ch;
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);
165 ab->cycles[ch] = 1;
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;
175 UWORD hwmask;
176 UBYTE ch;
178 if (!mask)
179 return;
180 hwmask = 0;
181 for (ch = 0; ch < NR_CH; ch++) {
182 if ((mask & (1 << ch)) && getnextwrite(ab, ch, FALSE)) {
183 hwmask |= 1 << ch;
184 preparech_initial(ab, ch);
187 D(bug("hw_start: %02x\n", hwmask));
188 if (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)
197 UBYTE ch;
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;
206 inter->ch = ch;
207 inter->ab = ab;
208 SetIntVector(INTB_AUD0 + ch, &inter->audint);