2 AHI-Handler - The AUDIO: DOS device for AHI
3 Copyright (C) 1997-2005 Martin Blom <martin@blom.org>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * This code is written using DICE, and is based on the DosHan example
22 * source code that came with the compiler. Not all comments are mine,
29 #include <exec/types.h>
30 #include <exec/nodes.h>
31 #include <exec/ports.h>
32 #include <exec/memory.h>
34 #include <dos/dosextens.h>
35 #include <dos/filehandler.h>
36 #include <dos/rdargs.h>
38 #include <devices/ahi.h>
39 #include <proto/ahi.h>
41 #include <proto/exec.h>
42 #include <proto/dos.h>
43 #include <proto/utility.h>
44 #include <clib/alib_protos.h>
59 LONG
PlayAndSwap(struct HandlerData
*, LONG
);
60 long extended2long(extended
*);
61 void ulong2extended (ULONG
, extended
*);
62 void FillAIFFheader(struct HandlerData
*);
63 void FillAIFCheader(struct HandlerData
*);
64 LONG
ReadCOMMchunk(struct HandlerData
*, UBYTE
*, LONG
);
67 long ParseArgs(struct HandlerData
*, char *);
68 long InitHData(struct HandlerData
*);
69 void FreeHData(struct HandlerData
*);
70 void returnpacket (struct DosPacket
*);
71 void Initialize (void);
72 void UnInitialize (void);
79 #define min(a,b) ((a)<=(b)?(a):(b))
82 #define BTOC(bptr) ((void *)((long)(bptr) << 2))
83 #define CTOB(cptr) ((BPTR)(((long)cptr) >> 2))
92 #define HIT(x) {char *a=NULL; *a=x;}
94 static const UWORD rawputchar_m68k
[] =
96 0x2C4B, // MOVEA.L A3,A6
97 0x4EAE, 0xFDFC, // JSR -$0204(A6)
102 KPrintFArgs( UBYTE
* fmt
,
105 RawDoFmt( fmt
, args
, (void(*)(void)) rawputchar_m68k
, SysBase
);
108 #define kprintf( fmt, ... ) \
110 ULONG _args[] = { __VA_ARGS__ }; \
111 KPrintFArgs( (fmt), _args ); \
121 static const char ID
[] = "$VER: AHI-Handler " VERS
"\r\n";
123 struct MsgPort
*PktPort
;
124 struct DeviceNode
*DevNode
;
127 struct MsgPort
*AHImp
= NULL
;
128 struct AHIRequest
*AHIio
= NULL
;
130 struct Library
*AHIBase
;
132 struct AIFCHeader AIFCHeader
= {
134 ID_FVER
, sizeof(FormatVersionHeader
), {
137 ID_COMM
, sizeof(ExtCommonChunk
), {
143 {sizeof("not compressed")-1,
144 'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'}
149 struct AIFFHeader AIFFHeader
= {
151 ID_COMM
, sizeof(CommonChunk
),{
161 /******************************************************************************
162 **** Entry ********************************************************************
163 ******************************************************************************/
165 // Disable command line processing
166 const long __nocommandline
=1;
168 // We (mis)use this one directly instead
169 extern struct Message
*_WBenchMsg
;
173 struct DosPacket
*packet
;
174 struct Process
*proc
;
179 kprintf("The very first call...\n");
182 proc
= (struct Process
*) FindTask (NULL
);
184 PktPort
= &proc
->pr_MsgPort
;
201 while ((msg
= GetMsg (PktPort
)) == NULL
)
202 Wait (1 << PktPort
->mp_SigBit
);
203 packet
= (struct DosPacket
*) msg
->mn_Node
.ln_Name
;
206 kprintf ("Got packet: %ld\n", packet
->dp_Type
);
209 * default return value
212 packet
->dp_Res1
= DOS_TRUE
;
219 switch (packet
->dp_Type
) {
221 case ACTION_DIE
: /* ??? */
226 /***********************************************************************/
228 case ACTION_FINDUPDATE
: /* FileHandle,Lock,Name Bool */
229 case ACTION_FINDINPUT
: /* FileHandle,Lock,Name Bool */
230 case ACTION_FINDOUTPUT
: /* FileHandle,Lock,Name Bool */
232 struct FileHandle
*fh
= BTOC (packet
->dp_Arg1
);
233 unsigned char *base
= BTOC (packet
->dp_Arg3
);
234 unsigned int len
= *base
;
236 struct HandlerData
*data
;
237 int unit
= AHI_DEFAULT_UNIT
;
239 // Skip volume name and ':'
241 while(*++base
!= ':')
246 // Convert /'s to blanks
255 if (len
>= sizeof (buf
))
256 len
= sizeof (buf
) - 1;
258 strncpy (buf
, base
, len
- 1);
263 kprintf("ACTION_FIND#?: %s\n", (char *) buf
);
266 data
= AllocVec(sizeof(struct HandlerData
), MEMF_PUBLIC
| MEMF_CLEAR
);
268 packet
->dp_Res1
= DOS_FALSE
;
269 packet
->dp_Res2
= ERROR_NO_FREE_STORE
;
273 if( (packet
->dp_Res2
= ParseArgs(data
, (char *) buf
)) ) {
275 packet
->dp_Res1
= DOS_FALSE
;
279 if(data
->args
.unit
) {
280 unit
= *data
->args
.unit
;
283 if( (packet
->dp_Res2
= AllocAudio(unit
)) ) {
286 packet
->dp_Res1
= DOS_FALSE
;
291 fh
->fh_Arg1
= (ULONG
) data
;
292 fh
->fh_Port
= DOS_TRUE
;
296 /***********************************************************************/
298 case ACTION_READ
: /* FHArg1,CPTRBuffer,Length ActLength */
302 * Reading is straightforward except for handling EOF... We
303 * must guarentee a return value of 0 (no bytes left) before
304 * beginning to return EOFs (-1's). If we return a negative
305 * number right off programs like COPY will assume a failure
306 * (if AUDIO: is the source) and delete the destination file.
308 * The basic idea is to feed the packets from one buffer while
309 * recording asyncroniously to the other. When we have read
310 * the buffer, we wait until the other is filled, and switch
314 struct HandlerData
*data
= (struct HandlerData
*) packet
->dp_Arg1
;
315 UBYTE
*dest
= (void *) packet
->dp_Arg2
;
319 kprintf("ACTION_READ: 0x%08lx, %ld\n", packet
->dp_Arg2
, packet
->dp_Arg3
);
322 if(! data
->initialized
) {
323 packet
->dp_Res2
= InitHData(data
);
324 if(packet
->dp_Res2
) {
325 packet
->dp_Res1
= -1;
330 length
= filled
= min(data
->totallength
, packet
->dp_Arg3
);
333 packet
->dp_Res1
= length
;
334 data
->totallength
= -1;
338 if(data
->buffer1
== NULL
) {
340 data
->buffer1
= AllocVec(data
->buffersize
, MEMF_PUBLIC
);
341 data
->buffer2
= AllocVec(data
->buffersize
, MEMF_PUBLIC
);
342 data
->readreq
= AllocVec(sizeof (struct AHIRequest
), MEMF_PUBLIC
);
344 if((data
->buffer1
== NULL
)
345 || (data
->buffer2
== NULL
)
346 || (data
->readreq
== NULL
)) {
347 packet
->dp_Res1
= -1;
348 packet
->dp_Res2
= ERROR_NO_FREE_STORE
;
352 CopyMem(AHIio
, data
->readreq
, sizeof (struct AHIRequest
));
355 // Note that io_Offset is always 0 the first time
357 data
->readreq
->ahir_Std
.io_Command
= CMD_READ
;
358 data
->readreq
->ahir_Std
.io_Data
= data
->buffer2
;
359 data
->readreq
->ahir_Std
.io_Length
= data
->buffersize
;
360 data
->readreq
->ahir_Std
.io_Offset
= 0;
361 data
->readreq
->ahir_Type
= data
->type
;
362 data
->readreq
->ahir_Frequency
= data
->freq
;
363 data
->readreq
->ahir_Volume
= data
->vol
;
364 data
->readreq
->ahir_Position
= data
->pos
;
365 SendIO((struct IORequest
*) data
->readreq
);
367 // Force buffer switch filling of the other buffer
369 data
->length
= data
->offset
= 0;
371 // Check if we should write a header first
373 if(data
->format
== AIFF
) {
374 if(length
< (LONG
) sizeof(struct AIFFHeader
)) {
375 packet
->dp_Res1
= -1;
376 packet
->dp_Res2
= ERROR_BAD_NUMBER
;
380 FillAIFFheader(data
);
382 CopyMem(&AIFFHeader
, dest
, sizeof(struct AIFFHeader
));
383 dest
+= sizeof(struct AIFFHeader
);
384 length
-= sizeof(struct AIFFHeader
);
387 else if(data
->format
== AIFC
) {
388 if(length
< (LONG
) sizeof(struct AIFCHeader
)) {
389 packet
->dp_Res1
= -1;
390 packet
->dp_Res2
= ERROR_BAD_NUMBER
;
394 FillAIFCheader(data
);
396 CopyMem(&AIFCHeader
, dest
, sizeof(struct AIFCHeader
));
397 dest
+= sizeof(struct AIFCHeader
);
398 length
-= sizeof(struct AIFCHeader
);
406 if(data
->offset
>= data
->length
) {
409 temp
= data
->buffer1
;
410 data
->buffer1
= data
->buffer2
;
411 data
->buffer2
= temp
;
413 if(WaitIO((struct IORequest
*) data
->readreq
)) {
414 packet
->dp_Res1
= -1;
415 if(data
->readreq
->ahir_Std
.io_Error
== AHIE_HALFDUPLEX
) {
416 packet
->dp_Res2
= ERROR_OBJECT_IN_USE
;
419 packet
->dp_Res2
= ERROR_READ_PROTECTED
;
424 data
->length
= data
->readreq
->ahir_Std
.io_Actual
;
427 data
->readreq
->ahir_Std
.io_Command
= CMD_READ
;
428 data
->readreq
->ahir_Std
.io_Data
= data
->buffer2
;
429 data
->readreq
->ahir_Std
.io_Length
= data
->buffersize
;
430 data
->readreq
->ahir_Type
= data
->type
;
431 data
->readreq
->ahir_Frequency
= data
->freq
;
432 data
->readreq
->ahir_Volume
= data
->vol
;
433 data
->readreq
->ahir_Position
= data
->pos
;
434 SendIO((struct IORequest
*) data
->readreq
);
437 thislength
= min(data
->length
- data
->offset
, length
);
438 CopyMem(data
->buffer1
+ data
->offset
, dest
, thislength
);
440 length
-= thislength
;
441 data
->offset
+= thislength
;
442 data
->totallength
-= thislength
;
445 if(packet
->dp_Res2
== 0) {
446 packet
->dp_Res1
= filled
;
452 /***********************************************************************/
454 case ACTION_WRITE
: /* FHArg1,CPTRBuffer,Length ActLength */
456 struct HandlerData
*data
= (struct HandlerData
*) packet
->dp_Arg1
;
457 UBYTE
*src
= (void *) packet
->dp_Arg2
;
458 LONG length
= packet
->dp_Arg3
, filled
;
461 kprintf("ACTION_WRITE: 0x%08lx, %ld\n", packet
->dp_Arg2
, packet
->dp_Arg3
);
464 if(data
->buffer1
== NULL
) {
467 switch(data
->args
.format
) {
469 if((((ULONG
*) src
)[0] != ID_FORM
)
470 || (((ULONG
*) src
)[2] != ID_AIFF
)) {
471 packet
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
476 if((((ULONG
*) src
)[0] != ID_FORM
)
477 || (((ULONG
*) src
)[2] != ID_AIFC
)) {
478 packet
->dp_Res2
= ERROR_OBJECT_WRONG_TYPE
;
483 if(((ULONG
*) src
)[0] == ID_FORM
) {
484 if(((ULONG
*) src
)[2] == ID_AIFF
) {
485 data
->args
.format
= AIFF
;
487 else if(((ULONG
*) src
)[2] == ID_AIFC
) {
488 data
->args
.format
= AIFC
;
497 if(packet
->dp_Res2
) {
498 packet
->dp_Res1
= -1;
502 if((data
->args
.format
== AIFF
) || (data
->args
.format
== AIFC
)) {
505 skiplen
= ReadCOMMchunk(data
, src
, length
);
510 if( (packet
->dp_Res2
= InitHData(data
)) ) {
511 packet
->dp_Res1
= -1;
515 data
->writing
= TRUE
;
517 data
->buffer1
= AllocVec(data
->buffersize
, MEMF_PUBLIC
);
518 data
->buffer2
= AllocVec(data
->buffersize
, MEMF_PUBLIC
);
520 if((data
->buffer1
== NULL
) || (data
->buffer2
== NULL
)) {
521 packet
->dp_Res1
= -1;
522 packet
->dp_Res2
= ERROR_NO_FREE_STORE
;
527 data
->length
= (data
->buffersize
/ AHI_SampleFrameSize(data
->type
))
528 * AHI_SampleFrameSize(data
->type
);
532 length
= min(data
->totallength
, length
);
533 filled
= min(data
->totallength
, packet
->dp_Arg3
);
538 if(data
->offset
>= data
->length
) {
539 packet
->dp_Res2
= PlayAndSwap(data
, data
->length
);
540 if(packet
->dp_Res2
) {
541 packet
->dp_Res1
= -1;
546 thislength
= min(data
->length
- data
->offset
, length
);
547 CopyMem(src
, data
->buffer1
+ data
->offset
, thislength
);
549 length
-= thislength
;
550 data
->offset
+= thislength
;
551 data
->totallength
-= thislength
;
555 if(packet
->dp_Res2
== 0) {
556 packet
->dp_Res1
= filled
;
561 /***********************************************************************/
563 case ACTION_END
: /* FHArg1 Bool:TRUE */
565 struct HandlerData
*data
= (struct HandlerData
*) packet
->dp_Arg1
;
568 kprintf("ACTION_END\n");
571 // Abort any reading requests
574 AbortIO((struct IORequest
*) data
->readreq
);
575 WaitIO((struct IORequest
*) data
->readreq
);
578 // Finish any playing requests
581 PlayAndSwap(data
, data
->offset
);
583 if(data
->writereq1
) {
584 WaitIO((struct IORequest
*) data
->writereq1
);
586 if(data
->writereq2
) {
587 WaitIO((struct IORequest
*) data
->writereq2
);
598 /***********************************************************************/
600 case ACTION_IS_FILESYSTEM
:
601 packet
->dp_Res1
= DOS_FALSE
;
604 /***********************************************************************/
608 kprintf("Unknown packet!\n");
610 packet
->dp_Res1
= DOS_FALSE
;
611 packet
->dp_Res2
= ERROR_ACTION_NOT_KNOWN
;
620 returnpacket (packet
);
622 kprintf("Retured packet\n");
629 kprintf("Dying..!\n");
636 /******************************************************************************
637 **** PlayAndSwap **************************************************************
638 ******************************************************************************/
641 * Starts to play the current buffer. Handles double buffering.
644 LONG
PlayAndSwap(struct HandlerData
*data
, LONG length
) {
647 temp
= data
->buffer1
;
648 data
->buffer1
= data
->buffer2
;
649 data
->buffer2
= temp
;
651 temp
= data
->writereq1
;
652 data
->writereq1
= data
->writereq2
;
653 data
->writereq2
= temp
;
656 if(data
->writereq1
== NULL
) {
657 data
->writereq1
= AllocVec(sizeof (struct AHIRequest
), MEMF_PUBLIC
);
659 if(data
->writereq1
== NULL
) {
660 return ERROR_NO_FREE_STORE
;
663 CopyMem(AHIio
, data
->writereq1
, sizeof (struct AHIRequest
));
668 data
->writereq1
->ahir_Std
.io_Message
.mn_Node
.ln_Pri
= data
->priority
;
669 data
->writereq1
->ahir_Std
.io_Command
= CMD_WRITE
;
670 data
->writereq1
->ahir_Std
.io_Data
= data
->buffer2
;
671 data
->writereq1
->ahir_Std
.io_Length
= length
;
672 data
->writereq1
->ahir_Std
.io_Offset
= 0;
673 data
->writereq1
->ahir_Type
= data
->type
;
674 data
->writereq1
->ahir_Frequency
= data
->freq
;
675 data
->writereq1
->ahir_Volume
= data
->vol
;
676 data
->writereq1
->ahir_Position
= data
->pos
;
677 data
->writereq1
->ahir_Link
= data
->writereq2
;
678 SendIO((struct IORequest
*) data
->writereq1
);
680 if(data
->writereq2
) {
681 if(WaitIO((struct IORequest
*) data
->writereq2
)) {
682 if(data
->writereq2
->ahir_Std
.io_Error
== AHIE_HALFDUPLEX
) {
683 return ERROR_OBJECT_IN_USE
;
686 return ERROR_WRITE_PROTECTED
;
695 /******************************************************************************
696 **** extended2long ************************************************************
697 ******************************************************************************/
700 * This function translates Apples SANE Extended used in AIFF/AIFC files
701 * to a LONG. Stolen from Olaf `Olsen' Barthel's AIFF datatype.
705 long extended2long(extended
*ex
)
707 unsigned long mantissa
;
710 // We only need 32 bits precision
712 mantissa
= ex
->mantissa
[0];
714 // Is the mantissa positive or negative?
716 exponent
= ex
->exponent
;
718 if(exponent
& 0x8000)
723 // Unbias the exponent
725 exponent
= (exponent
& 0x7FFF) - 0x3FFF;
727 // If the exponent is negative, set the mantissa to zero
740 mantissa
= 0x7FFFFFFF;
742 mantissa
>>= -exponent
; // Let the point float...
747 return(sign
* (long)mantissa
);
751 /******************************************************************************
752 **** ulong2extended ***********************************************************
753 ******************************************************************************/
756 * This function translates an ULONG to Apples SANE Extended
757 * used in AIFF/AIFC files.
760 void ulong2extended (ULONG in
, extended
*ex
)
762 ex
->exponent
=31+16383;
764 while(!(in
& 0x80000000))
773 /******************************************************************************
774 **** FillAIFFheader ***********************************************************
775 ******************************************************************************/
777 void FillAIFFheader(struct HandlerData
*data
) {
779 AIFFHeader
.FORMsize
= data
->totallength
- 8;
780 AIFFHeader
.COMMchunk
.numChannels
= data
->channels
;
781 AIFFHeader
.COMMchunk
.numSampleFrames
=
782 data
->totallength
/ AHI_SampleFrameSize(data
->type
);
783 AIFFHeader
.COMMchunk
.sampleSize
= data
->bits
;
784 ulong2extended(data
->freq
, &AIFFHeader
.COMMchunk
.sampleRate
);
785 AIFFHeader
.SSNDsize
= sizeof(SampledSoundHeader
) + data
->totallength
- sizeof(AIFFHeader
);
789 /******************************************************************************
790 **** FillAIFCheader ***********************************************************
791 ******************************************************************************/
793 void FillAIFCheader(struct HandlerData
*data
) {
795 AIFCHeader
.FORMsize
= data
->totallength
- 8;
796 AIFCHeader
.COMMchunk
.numChannels
= data
->channels
;
797 AIFCHeader
.COMMchunk
.numSampleFrames
=
798 data
->totallength
/ AHI_SampleFrameSize(data
->type
);
799 AIFCHeader
.COMMchunk
.sampleSize
= data
->bits
;
800 ulong2extended(data
->freq
, &AIFCHeader
.COMMchunk
.sampleRate
);
801 AIFCHeader
.SSNDsize
= sizeof(SampledSoundHeader
) + data
->totallength
- sizeof(AIFFHeader
);
805 /******************************************************************************
806 **** ReadCOMMchunk ************************************************************
807 ******************************************************************************/
809 LONG
ReadCOMMchunk(struct HandlerData
*data
, UBYTE
*buffer
, LONG length
) {
810 UWORD
*src
= (UWORD
*) buffer
;
811 LONG len
= (length
>> 1) - 2;
812 ExtCommonChunk
*common
;
815 if(((ULONG
*) src
)[0] == ID_COMM
) {
816 common
= (ExtCommonChunk
*) (src
+ 4);
817 data
->channels
= common
->numChannels
;
818 data
->bits
= common
->sampleSize
;
819 data
->totallength
= common
->numSampleFrames
* common
->numChannels
*
820 (data
->bits
<= 8 ? 1 : (data
->bits
<= 16 ? 2 : (data
->bits
<= 32 ? 4 : 0)));
821 data
->freq
= extended2long(&common
->sampleRate
);
823 if(!data
->args
.channels
)
824 data
->args
.channels
= &data
->channels
;
826 data
->args
.bits
= &data
->bits
;
827 if(!data
->args
.length
)
828 data
->args
.length
= &data
->totallength
;
830 data
->args
.freq
= &data
->freq
;
832 else if(((ULONG
*) src
)[0] == ID_SSND
) {
839 return (LONG
) src
- (LONG
) buffer
;
842 /******************************************************************************
843 **** AllocAudio ***************************************************************
844 ******************************************************************************/
847 * If the device isn't already open, open it now
850 long AllocAudio(int unit
) {
853 if(++AllocCnt
== 1) {
854 if( (AHImp
=CreateMsgPort()) ) {
855 if( (AHIio
=(struct AHIRequest
*)CreateIORequest(
856 AHImp
,sizeof(struct AHIRequest
))) ) {
857 AHIio
->ahir_Version
= 4;
858 AHIDevice
=OpenDevice(AHINAME
,unit
,(struct IORequest
*)AHIio
,NULL
);
863 rc
= ERROR_OBJECT_NOT_FOUND
;
866 AHIBase
=(struct Library
*)AHIio
->ahir_Std
.io_Device
;
873 /******************************************************************************
874 **** FreeAudio ****************************************************************
875 ******************************************************************************/
878 * If we're the last user, close the device now
883 if(--AllocCnt
== 0) {
885 CloseDevice((struct IORequest
*)AHIio
);
887 DeleteIORequest((struct IORequest
*)AHIio
);
889 DeleteMsgPort(AHImp
);
895 /******************************************************************************
896 **** ParseArgs ****************************************************************
897 ******************************************************************************/
900 * Fill out argument array. Returns 0 on success, else a DOS error code.
903 long ParseArgs(struct HandlerData
*data
, char *initstring
) {
906 data
->rdargs
= (struct RDArgs
*) AllocDosObjectTags(DOS_RDARGS
, TAG_DONE
);
909 data
->rdargs
->RDA_Source
.CS_Buffer
= initstring
;
910 data
->rdargs
->RDA_Source
.CS_Length
= strlen(initstring
);
911 data
->rdargs
->RDA_Source
.CS_CurChr
= 0;
912 data
->rdargs
->RDA_Flags
|= RDAF_NOPROMPT
;
914 data
->rdargs2
= ReadArgs(
915 "B=BITS/K/N,C=CHANNELS/K/N,F=FREQUENCY/K/N,T=TYPE/K,V=VOLUME/K/N,P=POSITION/K/N,"
916 "PRI=PRIORITY/K/N,L=LENGTH/K/N,S=SECONDS/K/N,BUF=BUFFER/K/N,UNIT/K/N",
917 (LONG
*) &data
->args
, data
->rdargs
);
919 if(data
->rdargs2
!= NULL
) {
922 if(! data
->args
.type
) {
923 data
->args
.format
= 0;
925 else if(Stricmp("SIGNED", data
->args
.type
) == 0) {
926 data
->args
.format
= SIGNED
;
928 else if(Stricmp("AIFF", data
->args
.type
) == 0) {
929 data
->args
.format
= AIFF
;
931 else if(Stricmp("AIFC", data
->args
.type
) == 0) {
932 data
->args
.format
= AIFC
;
935 rc
= ERROR_BAD_TEMPLATE
;
939 rc
= ERROR_BAD_TEMPLATE
;
943 rc
= ERROR_NO_FREE_STORE
;
949 /******************************************************************************
950 **** InitHData ****************************************************************
951 ******************************************************************************/
954 * Initialize the HandlerData data structure, based on the args structure
955 * (see ParseArgs()). Returns 0 on success, else a DOS error code.
962 #define Sstereoflag 2
964 long InitHData(struct HandlerData
*data
) {
965 ULONG bits
= 8, channels
= 1, freq
= 8000;
966 LONG volume
= 100, position
= 0, priority
= 0,
967 length
= MAXINT
, buffersize
= 32768;
970 data
->initialized
= TRUE
;
972 // Fill in default values
975 data
->args
.bits
= &bits
;
976 if(!data
->args
.channels
)
977 data
->args
.channels
= &channels
;
979 data
->args
.freq
= &freq
;
980 if(!data
->args
.volume
)
981 data
->args
.volume
= &volume
;
982 if(!data
->args
.position
)
983 data
->args
.position
= &position
;
984 if(!data
->args
.priority
)
985 data
->args
.priority
= &priority
;
986 if(!data
->args
.length
)
987 data
->args
.length
= &length
;
988 if(!data
->args
.buffersize
)
989 data
->args
.buffersize
= &buffersize
;
991 if(!data
->args
.format
)
992 data
->args
.format
= SIGNED
;
996 if(*data
->args
.bits
<= 8)
997 data
->type
= S8bitmode
;
998 else if(*data
->args
.bits
<= 16)
999 data
->type
= S16bitmode
;
1000 else if(*data
->args
.bits
> 24 && *data
->args
.bits
<= 32)
1001 data
->type
= S32bitmode
;
1003 rc
= ERROR_OBJECT_WRONG_TYPE
;
1009 if((*data
->args
.channels
> 2) || (*data
->args
.channels
< 1)) {
1010 rc
= ERROR_OBJECT_WRONG_TYPE
;
1014 if(*data
->args
.channels
== 2)
1015 data
->type
|= Sstereoflag
;
1017 data
->bits
= *data
->args
.bits
;
1018 data
->channels
= *data
->args
.channels
;
1019 data
->freq
= *data
->args
.freq
;
1020 data
->vol
= *data
->args
.volume
* 0x10000 / 100;
1021 { // Don't ask why... :(
1023 a
= *data
->args
.position
* 0x8000;
1024 a
= a
/ 100 + 0x8000;
1027 data
->priority
= *data
->args
.priority
;
1029 if(data
->args
.seconds
) {
1030 data
->totallength
= *data
->args
.seconds
* data
->freq
1031 * AHI_SampleFrameSize(data
->type
);
1034 data
->totallength
= (*data
->args
.length
/ AHI_SampleFrameSize(data
->type
))
1035 * AHI_SampleFrameSize(data
->type
);
1038 data
->format
= data
->args
.format
;
1040 switch(data
->format
) {
1043 data
->totallength
= data
->totallength
& ~1; // Make even
1047 data
->buffersize
= *data
->args
.buffersize
;
1063 /******************************************************************************
1064 **** FreeHData ****************************************************************
1065 ******************************************************************************/
1068 * Deallocate the HandlerData structure
1071 void FreeHData(struct HandlerData
*data
) {
1074 FreeArgs(data
->rdargs2
);
1076 FreeDosObject(DOS_RDARGS
, data
->rdargs
);
1078 FreeVec(data
->buffer1
);
1079 FreeVec(data
->buffer2
);
1080 FreeVec(data
->readreq
);
1081 FreeVec(data
->writereq1
);
1082 FreeVec(data
->writereq2
);
1088 /******************************************************************************
1089 **** returnpacket *************************************************************
1090 ******************************************************************************/
1093 * PACKET ROUTINES. Dos Packets are in a rather strange format as you
1094 * can see by this and how the PACKET structure is extracted in the
1095 * GetMsg() of the main routine.
1098 void returnpacket (struct DosPacket
*packet
) {
1099 struct Message
*mess
;
1100 struct MsgPort
*replyPort
;
1102 replyPort
= packet
->dp_Port
;
1103 mess
= packet
->dp_Link
;
1104 packet
->dp_Port
= PktPort
;
1105 mess
->mn_Node
.ln_Name
= (char *) packet
;
1106 PutMsg (replyPort
, mess
);
1110 /******************************************************************************
1111 **** Initialize ***************************************************************
1112 ******************************************************************************/
1115 * During initialization DOS sends us a packet and sets our dn_SegList
1116 * pointer. If we set our dn_Task pointer than every Open's go to the
1117 * same handler (this one). If we set dn_Task to NULL, every Open()
1118 * will create a NEW instance of this process via the seglist, meaning
1119 * our process must be reentrant (i.e. -r option).
1121 * note: dn_Task points to the MESSAGE PORT portion of the process
1122 * (or your own custom message port).
1124 * If we clear the SegList then we also force DOS to reload our process
1125 * from disk, but we also need some way of then UnLoadSeg()ing it ourselves,
1126 * which we CANNOT do from this process since it rips our code out from
1130 void Initialize () {
1131 struct DeviceNode
*dn
;
1132 struct DosPacket
*packet
;
1135 * Handle initial message.
1138 packet
= (struct DosPacket
*) _WBenchMsg
->mn_Node
.ln_Name
;
1140 DevNode
= dn
= BTOC (packet
->dp_Arg3
);
1144 kprintf("Replying it ...\n");
1147 // Make sure startup code does not reply the message on exit
1150 packet
->dp_Res1
= DOS_TRUE
;
1151 packet
->dp_Res2
= 0;
1152 returnpacket (packet
);
1156 /******************************************************************************
1157 **** UnInitialize *************************************************************
1158 ******************************************************************************/
1160 void UnInitialize (void) {
1161 struct DeviceNode
*dn
= DevNode
;
1166 #if defined(__mc68000__) && defined(__libnix__)
1167 void __main(void) {}