2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Paula audio.device
10 - Channel stealing not yet supported
11 - ADCMD_LOCK never returns
12 - DMA wait missing (CMD_STOP and immediate CMD_START may cause glitches)
16 - normally unused io->ioa_Request.io_Unit bits 4 to 7 are used to keep
17 track of pending SYNCCYCLE-style requests (all cleared = done)
22 #include <aros/debug.h>
24 #include <exec/resident.h>
25 #include <exec/errors.h>
26 #include <exec/memory.h>
27 #include <exec/lists.h>
28 #include <exec/alerts.h>
29 #include <exec/tasks.h>
30 #include <exec/interrupts.h>
31 #include <devices/audio.h>
32 #include <hardware/intbits.h>
33 #include <hardware/custom.h>
34 #include <clib/alib_protos.h>
35 #include <aros/symbolsets.h>
37 #include <proto/exec.h>
39 #include "audio_intern.h"
41 #include LC_LIBDEFS_FILE
43 static const UBYTE masktoch
[16] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
45 static BOOL
isplaying(struct AudioBase
*ab
, struct IOAudio
*io
, UBYTE ch
)
47 return (struct IOAudio
*)ab
->writelist
[ch
].mlh_Head
->mln_Succ
== io
&& !(ab
->stopmask
& (1 << ch
));
50 struct IOAudio
*getnextwrite(struct AudioBase
*ab
, UBYTE ch
, BOOL second
)
53 if (ab
->writelist
[ch
].mlh_Head
->mln_Succ
== NULL
)
55 io
= (struct IOAudio
*)ab
->writelist
[ch
].mlh_Head
;
58 if(ab
->writelist
[ch
].mlh_Head
->mln_Succ
->mln_Succ
== NULL
)
60 return (struct IOAudio
*)io
->ioa_Request
.io_Message
.mn_Node
.ln_Succ
;
64 UBYTE mask = (UBYTE)(ULONG)io->ioa_Request.io_Unit; \
65 WORD key = io->ioa_AllocKey; \
66 { io->ioa_Request.io_Unit = NULL; }
68 static void abort_io(struct AudioBase
*ab
, struct IOAudio
*io
)
70 UBYTE ch
= masktoch
[(UBYTE
)(ULONG
)io
->ioa_Request
.io_Unit
& CH_MASK
];
74 if (isplaying(ab
, io
, ch
)) {
75 D(bug("audio: ch %d aborted, io %p\n", ch
, io
));
76 audiohw_stop(ab
, 1 << ch
);
78 D(bug("abort_io(%p)\n", io
));
80 io
->ioa_Request
.io_Error
= IOERR_ABORTED
;
81 ReplyMsg(&io
->ioa_Request
.io_Message
);
84 static void abort_ch(struct AudioBase
*ab
, UBYTE ch
)
89 while ((io
= (struct IOAudio
*)GetHead(&ab
->writelist
[ch
])))
94 static void abort_waitcycles(struct AudioBase
*ab
, UBYTE mask
)
96 struct IOAudio
*io
, *next
;
98 ForeachNodeSafe(&ab
->misclist
, io
, next
) {
99 UWORD cmd
= io
->ioa_Request
.io_Command
;
100 UBYTE cmask
= (UBYTE
)(ULONG
)io
->ioa_Request
.io_Unit
;
101 if (cmd
!= ADCMD_FINISH
&& cmd
!= ADCMD_PERVOL
&& cmd
!= ADCMD_WAITCYCLE
)
110 static void allocchannels(struct AudioBase
*ab
, struct IOAudio
*io
, UBYTE mask
, BYTE pri
)
115 key
= io
->ioa_AllocKey
;
118 for (ch
= 0; ch
< NR_CH
; ch
++) {
119 if (mask
& (1 << ch
)) {
124 io
->ioa_AllocKey
= key
;
125 io
->ioa_Request
.io_Unit
= (struct Unit
*)(ULONG
)mask
;
126 audiohw_reset(ab
, mask
);
127 D(bug("audio: allocmask %02x, pri %d, %04x (%04x %04x %04x %04x)\n",
128 mask
, pri
, io
->ioa_AllocKey
, ab
->key
[0], ab
->key
[1], ab
->key
[2], ab
->key
[3]));
131 static BOOL
allocaudio(struct AudioBase
*ab
, struct IOAudio
*io
)
136 io
->ioa_Request
.io_Error
= 0;
138 for (ch
= 0; ch
< NR_CH
; ch
++) {
139 if (ab
->key
[ch
] == 0)
142 for (i
= 0; i
< io
->ioa_Length
&& i
< 16; i
++) {
143 UBYTE mask
= io
->ioa_Data
[i
];
144 D(bug("%d: allocation mask %02x & %02x\n", i
, mask
, freech
));
145 if (mask
== 0 || (mask
& freech
) == mask
) {
146 allocchannels(ab
, io
, mask
, io
->ioa_Request
.io_Message
.mn_Node
.ln_Pri
);
150 io
->ioa_Request
.io_Error
= ADIOERR_ALLOCFAILED
;
154 static void setunit(struct IOAudio
*io
, UBYTE num
)
156 ULONG unit
= (ULONG
)io
->ioa_Request
.io_Unit
;
158 io
->ioa_Request
.io_Unit
= (struct Unit
*)unit
;
161 static BOOL
ADCMD_ALLOCATE_f(struct AudioBase
*ab
, struct IOAudio
*io
)
164 D(bug("ADCMD_ALLOCATE %02x %04x\n", mask
, key
));
166 if (io
->ioa_Request
.io_Error
== 0)
168 if (io
->ioa_Request
.io_Flags
& ADIOF_NOWAIT
)
170 AddTail((struct List
*)&ab
->misclist
, &io
->ioa_Request
.io_Message
.mn_Node
);
174 static BOOL
ADCMD_FREE_f(struct AudioBase
*ab
, struct IOAudio
*io
)
178 struct IOAudio
*node
, *next
;
180 D(bug("ADCMD_FREE %02x %04x\n", mask
, key
));
181 for (ch
= 0; ch
< NR_CH
; ch
++) {
182 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
183 abort_waitcycles(ab
, 1 << ch
);
185 audiohw_reset(ab
, 1 << ch
);
189 if (!io
->ioa_Request
.io_Unit
) {
190 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
193 ForeachNodeSafe(&ab
->misclist
, node
, next
) {
194 if (node
->ioa_Request
.io_Command
== ADCMD_ALLOCATE
&& allocaudio(ab
, node
)) {
196 ReplyMsg(&io
->ioa_Request
.io_Message
);
202 static BOOL
ADCMD_LOCK_f(struct AudioBase
*ab
, struct IOAudio
*io
)
207 D(bug("ADCMD_LOCK %02x %04x\n", mask
, key
));
208 for (ch
= 0; ch
< NR_CH
; ch
++) {
209 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
])
212 if (!io
->ioa_Request
.io_Unit
) {
213 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
216 AddTail((struct List
*)&ab
->misclist
, &io
->ioa_Request
.io_Message
.mn_Node
);
220 static BOOL
ADCMD_SETPREC_f(struct AudioBase
*ab
, struct IOAudio
*io
)
225 D(bug("ADCMD_SETPREC %02x %04x\n", mask
, key
));
226 for (ch
= 0; ch
< NR_CH
; ch
++) {
227 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
228 ab
->pri
[ch
] = io
->ioa_Request
.io_Message
.mn_Node
.ln_Pri
;
232 if (!io
->ioa_Request
.io_Unit
)
233 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
237 static BOOL
ADCMD_NULL_f(struct AudioBase
*ab
, struct IOAudio
*io
)
242 for (ch
= 0; ch
< NR_CH
; ch
++) {
243 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
])
246 if (!io
->ioa_Request
.io_Unit
)
247 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
251 static BOOL
ADCMD_FLUSH_f(struct AudioBase
*ab
, struct IOAudio
*io
)
256 D(bug("ADCMD_FLUSH %02x %04x\n", mask
, key
));
257 for (ch
= 0; ch
< NR_CH
; ch
++) {
258 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
263 if (!io
->ioa_Request
.io_Unit
)
264 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
268 static BOOL
ADCMD_FINISH_f(struct AudioBase
*ab
, struct IOAudio
*io
)
274 D(bug("ADCMD_FINISH %02x %04x\n", mask
, key
));
278 for (ch
= 0; ch
< NR_CH
; ch
++) {
279 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
281 if (getnextwrite(ab
, ch
, FALSE
) && (io
->ioa_Request
.io_Flags
& ADIOF_SYNCCYCLE
)) {
283 AddTail((struct List
*)&ab
->misclist
, &io
->ioa_Request
.io_Message
.mn_Node
);
284 setunit(io
, ch
+ NR_CH
);
294 if (!io
->ioa_Request
.io_Unit
)
295 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
299 static BOOL
ADCMD_RESET_f(struct AudioBase
*ab
, struct IOAudio
*io
)
304 D(bug("ADCMD_RESET %02x %04x\n", mask
, key
));
305 for (ch
= 0; ch
< NR_CH
; ch
++) {
306 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
307 ADCMD_FLUSH_f(ab
, io
);
308 audiohw_reset(ab
, 1 << ch
);
310 ab
->stopmask
&= ~(1 << ch
);
313 if (!io
->ioa_Request
.io_Unit
)
314 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
318 static BOOL
ADCMD_START_f(struct AudioBase
*ab
, struct IOAudio
*io
)
324 D(bug("ADCMD_START %02x %04x\n", mask
, key
));
326 for (ch
= 0; ch
< NR_CH
; ch
++) {
327 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
] && (ab
->stopmask
& (1 << ch
))) {
328 ab
->stopmask
&= ~(1 << ch
);
333 if (!io
->ioa_Request
.io_Unit
)
334 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
336 audiohw_start(ab
, newmask
);
340 static BOOL
ADCMD_STOP_f(struct AudioBase
*ab
, struct IOAudio
*io
)
346 D(bug("ADCMD_STOP %02x %04x\n", mask
, key
));
348 for (ch
= 0; ch
< NR_CH
; ch
++) {
349 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
350 ab
->stopmask
|= 1 << ch
;
355 if (!io
->ioa_Request
.io_Unit
) {
356 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
358 audiohw_stop(ab
, newmask
);
359 abort_waitcycles(ab
, newmask
);
364 static BOOL
ADCMD_PERVOL_f(struct AudioBase
*ab
, struct IOAudio
*io
)
370 D(bug("ADCMD_PERVOL %02x %04x\n", mask
, key
));
374 for (ch
= 0; ch
< NR_CH
; ch
++) {
375 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
377 if (getnextwrite(ab
, ch
, FALSE
) && (io
->ioa_Request
.io_Flags
& ADIOF_SYNCCYCLE
)) {
379 AddTail((struct List
*)&ab
->misclist
, &io
->ioa_Request
.io_Message
.mn_Node
);
380 setunit(io
, ch
+ NR_CH
);
385 UBYTE flags
= io
->ioa_Request
.io_Flags
;
386 io
->ioa_Request
.io_Flags
|= ADIOF_PERVOL
;
387 audiohw_preparepervol(ab
, io
, ch
);
388 io
->ioa_Request
.io_Flags
= flags
;
393 if (!io
->ioa_Request
.io_Unit
)
394 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
398 static BOOL
ADCMD_WRITE_f(struct AudioBase
*ab
, struct IOAudio
*io
)
403 BOOL firstempty
, secondempty
;
406 D(bug("ADCMD_WRITE %02x %04x\n", mask
, key
));
409 firstempty
= secondempty
= FALSE
;
410 for (ch
= 0; ch
< NR_CH
; ch
++) {
411 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
413 firstempty
= getnextwrite(ab
, ch
, FALSE
) == NULL
;
414 secondempty
= getnextwrite(ab
, ch
, TRUE
) == NULL
;
415 AddTail((struct List
*)&ab
->writelist
[ch
], &io
->ioa_Request
.io_Message
.mn_Node
);
420 D(bug("unit=%08x 1=%d 2=%d newmask=%02x stopmask=%02x cycles=%d\n",
421 io
->ioa_Request
.io_Unit
, firstempty
, secondempty
, newmask
,
422 ab
->stopmask
, io
->ioa_Cycles
));
423 if (!io
->ioa_Request
.io_Unit
) {
424 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
426 if (!(ab
->stopmask
& newmask
)) {
428 audiohw_start(ab
, newmask
);
429 } else if (secondempty
) {
430 audiohw_prepareptlen(ab
, getnextwrite(ab
, ch
, TRUE
), ch
);
439 static BOOL
ADCMD_READ_f(struct AudioBase
*ab
, struct IOAudio
*io
)
444 D(bug("ADCMD_READ %02x %04x\n", mask
, key
));
445 for (ch
= 0; ch
< NR_CH
; ch
++) {
446 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
448 if (!(ab
->stopmask
& (1 << ch
)))
449 io
->ioa_Data
= (APTR
)getnextwrite(ab
, ch
, FALSE
);
453 if (!io
->ioa_Request
.io_Unit
)
454 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
458 static BOOL
ADCMD_WAITCYCLE_f(struct AudioBase
*ab
, struct IOAudio
*io
)
464 D(bug("ADCMD_WAITCYCLE %02x %04x\n", mask
, key
));
466 for (ch
= 0; ch
< NR_CH
; ch
++) {
467 if ((mask
& (1 << ch
)) && key
== ab
->key
[ch
]) {
469 if (!(ab
->stopmask
& (1 << ch
)) && getnextwrite(ab
, ch
, FALSE
)) {
470 AddTail((struct List
*)&ab
->misclist
, &io
->ioa_Request
.io_Message
.mn_Node
);
471 setunit(io
, ch
+ NR_CH
);
477 if (!io
->ioa_Request
.io_Unit
)
478 io
->ioa_Request
.io_Error
= ADIOERR_NOALLOCATION
;
482 static BOOL
processcommand(struct AudioBase
*ab
, struct IOAudio
*io
)
485 io
->ioa_Request
.io_Error
= 0;
486 switch(io
->ioa_Request
.io_Command
)
489 return ADCMD_NULL_f(ab
, io
);
491 return ADCMD_FLUSH_f(ab
, io
);
493 return ADCMD_RESET_f(ab
, io
);
495 return ADCMD_NULL_f(ab
, io
);
497 return ADCMD_START_f(ab
, io
);
499 return ADCMD_STOP_f(ab
, io
);
501 return ADCMD_READ_f(ab
, io
);
503 return ADCMD_WRITE_f(ab
, io
);
506 return ADCMD_ALLOCATE_f(ab
, io
);
508 return ADCMD_FREE_f(ab
, io
);
510 return ADCMD_LOCK_f(ab
, io
);
512 return ADCMD_SETPREC_f(ab
, io
);
513 case ADCMD_WAITCYCLE
:
514 return ADCMD_WAITCYCLE_f(ab
, io
);
516 return ADCMD_PERVOL_f(ab
, io
);
518 return ADCMD_FINISH_f(ab
, io
);
520 io
->ioa_Request
.io_Error
= IOERR_NOCMD
;
525 AROS_LH1(void, beginio
,
526 AROS_LHA(struct IOAudio
*, io
, A1
),
527 struct AudioBase
*, AudioBase
, 5, Audio
)
531 D(bug("audio beginio %p:%d\n", io
, io
->ioa_Request
.io_Command
));
533 io
->ioa_Request
.io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
534 if (processcommand(AudioBase
, io
)) {
535 /* TRUE = finished immediately */
536 if (!(io
->ioa_Request
.io_Flags
& IOF_QUICK
))
537 ReplyMsg(&io
->ioa_Request
.io_Message
);
540 io
->ioa_Request
.io_Flags
&= ~IOF_QUICK
;
546 AROS_LH1(LONG
, abortio
,
547 AROS_LHA(struct IOAudio
*, io
, A1
),
548 struct AudioBase
*, AudioBase
, 6, Audio
)
552 struct IOAudio
*node
;
555 D(bug("audio abortio %p\n", io
));
557 io
->ioa_Request
.io_Error
= 0;
560 for (ch
= 0; ch
< NR_CH
; ch
++) {
561 ForeachNode(&AudioBase
->writelist
[ch
], node
) {
563 abort_io(AudioBase
, io
);
568 ForeachNode(&AudioBase
->misclist
, node
) {
570 abort_io(AudioBase
, io
);
582 static int GM_UNIQUENAME(init
)(LIBBASETYPEPTR AudioBase
)
584 NEWLIST(&AudioBase
->writelist
[0]);
585 NEWLIST(&AudioBase
->writelist
[1]);
586 NEWLIST(&AudioBase
->writelist
[2]);
587 NEWLIST(&AudioBase
->writelist
[3]);
588 NEWLIST(&AudioBase
->misclist
);
589 AudioBase
->zerosample
= AllocMem(2, MEMF_CHIP
| MEMF_CLEAR
);
590 AudioBase
->keygen
= 0x5a00;
591 audiohw_init(AudioBase
);
595 static int GM_UNIQUENAME(open
)
597 LIBBASETYPEPTR AudioBase
,
603 D(bug("Audio open: pri=%d key=%04x data=%p len=%d\n",
604 io
->ioa_Request
.io_Message
.mn_Node
.ln_Pri
,
609 io
->ioa_Request
.io_Error
= 0;
610 io
->ioa_Request
.io_Unit
= (struct Unit
*) NULL
;
612 if (io
->ioa_Length
) {
613 allocaudio(AudioBase
, io
);
614 D(bug("new key = %04x\n", io
->ioa_AllocKey
));
615 io
->ioa_Request
.io_Device
= (struct Device
*)AudioBase
;
618 return io
->ioa_Request
.io_Error
== 0;
621 static int GM_UNIQUENAME(close
)
623 LIBBASETYPEPTR AudioBase
,
629 for (ch
= 0; ch
< NR_CH
; ch
++) {
630 if (io
->ioa_AllocKey
== AudioBase
->key
[ch
]) {
631 abort_ch(AudioBase
, ch
);
632 AudioBase
->key
[ch
] = 0;
633 audiohw_reset(AudioBase
, 1 << ch
);
636 io
->ioa_Request
.io_Unit
= NULL
;
637 io
->ioa_Request
.io_Device
= (struct Device
*)-1;
639 D(bug("Audio close: key = %04x\n", io
->ioa_AllocKey
));
644 ADD2INITLIB(GM_UNIQUENAME(init
), 0)
645 ADD2OPENDEV(GM_UNIQUENAME(open
), 0)
646 ADD2CLOSEDEV(GM_UNIQUENAME(close
), 0)