grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / AHI / AHI-Handler / main.c
blobe71c1b7cde38539586d915ebf68e5aefc5d18892
1 /*
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,
23 * by the way...
27 //#define DEBUG
29 #include <exec/types.h>
30 #include <exec/nodes.h>
31 #include <exec/ports.h>
32 #include <exec/memory.h>
33 #include <dos/dos.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>
46 #include <stdio.h>
47 #include <stdarg.h>
48 #include <stdlib.h>
49 #include <string.h>
51 #include "main.h"
52 #include "version.h"
56 * Prototypes
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);
65 long AllocAudio(int);
66 void FreeAudio(void);
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);
76 * Some macros
79 #define min(a,b) ((a)<=(b)?(a):(b))
80 #define DOS_TRUE -1
81 #define DOS_FALSE 0
82 #define BTOC(bptr) ((void *)((long)(bptr) << 2))
83 #define CTOB(cptr) ((BPTR)(((long)cptr) >> 2))
87 * My debug stuff....
90 #ifdef DEBUG
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)
98 0x4E75 // RTS
101 void
102 KPrintFArgs( UBYTE* fmt,
103 ULONG* args )
105 RawDoFmt( fmt, args, (void(*)(void)) rawputchar_m68k, SysBase );
108 #define kprintf( fmt, ... ) \
109 ({ \
110 ULONG _args[] = { __VA_ARGS__ }; \
111 KPrintFArgs( (fmt), _args ); \
114 #endif /* DEBUG */
118 * Global variables
121 static const char ID[] = "$VER: AHI-Handler " VERS "\r\n";
123 struct MsgPort *PktPort;
124 struct DeviceNode *DevNode;
125 int AllocCnt;
127 struct MsgPort *AHImp = NULL;
128 struct AHIRequest *AHIio = NULL;
129 BYTE AHIDevice = -1;
130 struct Library *AHIBase;
132 struct AIFCHeader AIFCHeader = {
133 ID_FORM, 0, ID_AIFC,
134 ID_FVER, sizeof(FormatVersionHeader), {
135 AIFCVersion1
137 ID_COMM, sizeof(ExtCommonChunk), {
141 {0,{0,0}},
142 NO_COMPRESSION,
143 {sizeof("not compressed")-1,
144 'n','o','t',' ','c','o','m','p','r','e','s','s','e','d'}
146 ID_SSND, 0, {0,0}
149 struct AIFFHeader AIFFHeader = {
150 ID_FORM, 0, ID_AIFF,
151 ID_COMM, sizeof(CommonChunk),{
155 {0,{0,0}}
157 ID_SSND, 0, {0,0}
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;
171 int main(void)
173 struct DosPacket *packet;
174 struct Process *proc;
176 BOOL Running;
178 #ifdef DEBUG
179 kprintf("The very first call...\n");
180 #endif
182 proc = (struct Process *) FindTask (NULL);
184 PktPort = &proc->pr_MsgPort;
185 Initialize ();
187 Running = TRUE;
188 AllocCnt = 0;
190 #ifdef DEBUG
191 kprintf("Init\n");
192 #endif
195 * Main Loop
198 while(Running) {
199 struct Message *msg;
201 while ((msg = GetMsg (PktPort)) == NULL)
202 Wait (1 << PktPort->mp_SigBit);
203 packet = (struct DosPacket *) msg->mn_Node.ln_Name;
205 #ifdef DEBUG
206 kprintf ("Got packet: %ld\n", packet->dp_Type);
207 #endif
209 * default return value
212 packet->dp_Res1 = DOS_TRUE;
213 packet->dp_Res2 = 0;
216 * switch on packet
219 switch (packet->dp_Type) {
221 case ACTION_DIE: /* ??? */
223 break;
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;
235 char buf[128];
236 struct HandlerData *data;
237 int unit = AHI_DEFAULT_UNIT;
239 // Skip volume name and ':'
241 while(*++base != ':')
242 --len;
243 ++base;
246 // Convert /'s to blanks
248 char *p = base;
250 while(*++p)
251 if(*p == '/')
252 *p = ' ';
255 if (len >= sizeof (buf))
256 len = sizeof (buf) - 1;
258 strncpy (buf, base, len - 1);
259 buf[len - 1] = '\n';
260 buf[len] = 0;
262 #ifdef DEBUG
263 kprintf("ACTION_FIND#?: %s\n", (char *) buf);
264 #endif
266 data = AllocVec(sizeof(struct HandlerData), MEMF_PUBLIC | MEMF_CLEAR);
267 if(! data) {
268 packet->dp_Res1 = DOS_FALSE;
269 packet->dp_Res2 = ERROR_NO_FREE_STORE;
270 break;
273 if( (packet->dp_Res2 = ParseArgs(data, (char *) buf)) ) {
274 FreeHData(data);
275 packet->dp_Res1 = DOS_FALSE;
276 break;
279 if(data->args.unit) {
280 unit = *data->args.unit;
283 if( (packet->dp_Res2 = AllocAudio(unit)) ) {
284 FreeAudio();
285 FreeHData(data);
286 packet->dp_Res1 = DOS_FALSE;
287 break;
291 fh->fh_Arg1 = (ULONG) data;
292 fh->fh_Port = DOS_TRUE;
293 break;
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
311 * buffer pointers.
314 struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
315 UBYTE *dest = (void *) packet->dp_Arg2;
316 LONG length, filled;
318 #ifdef DEBUG
319 kprintf("ACTION_READ: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
320 #endif
322 if(! data->initialized) {
323 packet->dp_Res2 = InitHData(data);
324 if(packet->dp_Res2) {
325 packet->dp_Res1 = -1;
326 break;
330 length = filled = min(data->totallength, packet->dp_Arg3);
332 if(length <= 0) {
333 packet->dp_Res1 = length;
334 data->totallength = -1;
335 break;
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;
349 break;
352 CopyMem(AHIio, data->readreq, sizeof (struct AHIRequest));
354 // Fill buffer 2
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;
377 break;
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;
391 break;
394 FillAIFCheader(data);
396 CopyMem(&AIFCHeader, dest, sizeof(struct AIFCHeader));
397 dest += sizeof(struct AIFCHeader);
398 length -= sizeof(struct AIFCHeader);
403 while(length > 0) {
404 LONG thislength;
406 if(data->offset >= data->length) {
407 void *temp;
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;
418 else {
419 packet->dp_Res2 = ERROR_READ_PROTECTED;
421 break;
424 data->length = data->readreq->ahir_Std.io_Actual;
425 data->offset = 0;
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);
435 } /* if */
437 thislength = min(data->length - data->offset, length);
438 CopyMem(data->buffer1 + data->offset, dest, thislength);
439 dest += thislength;
440 length -= thislength;
441 data->offset += thislength;
442 data->totallength -= thislength;
443 } /* while */
445 if(packet->dp_Res2 == 0) {
446 packet->dp_Res1 = filled;
448 break;
450 } /* ACTION_READ */
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;
460 #ifdef DEBUG
461 kprintf("ACTION_WRITE: 0x%08lx, %ld\n", packet->dp_Arg2, packet->dp_Arg3);
462 #endif
464 if(data->buffer1 == NULL) {
465 // Check headers?
467 switch(data->args.format) {
468 case AIFF:
469 if((((ULONG *) src)[0] != ID_FORM)
470 || (((ULONG *) src)[2] != ID_AIFF)) {
471 packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
473 break;
475 case AIFC:
476 if((((ULONG *) src)[0] != ID_FORM)
477 || (((ULONG *) src)[2] != ID_AIFC)) {
478 packet->dp_Res2 = ERROR_OBJECT_WRONG_TYPE;
480 break;
482 case 0:
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;
491 break;
493 default:
494 break;
497 if(packet->dp_Res2) {
498 packet->dp_Res1 = -1;
499 break;
502 if((data->args.format == AIFF) || (data->args.format == AIFC)) {
503 LONG skiplen = 0;
505 skiplen = ReadCOMMchunk(data, src, length);
506 src += skiplen;
507 length -= skiplen;
510 if( (packet->dp_Res2 = InitHData(data)) ) {
511 packet->dp_Res1 = -1;
512 break;
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;
523 break;
526 data->offset = 0;
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);
535 while(length > 0) {
536 LONG thislength;
538 if(data->offset >= data->length) {
539 packet->dp_Res2 = PlayAndSwap(data, data->length);
540 if(packet->dp_Res2) {
541 packet->dp_Res1 = -1;
542 break;
546 thislength = min(data->length - data->offset, length);
547 CopyMem(src, data->buffer1 + data->offset, thislength);
548 src += thislength;
549 length -= thislength;
550 data->offset += thislength;
551 data->totallength -= thislength;
553 } /* while */
555 if(packet->dp_Res2 == 0) {
556 packet->dp_Res1 = filled;
558 break;
561 /***********************************************************************/
563 case ACTION_END: /* FHArg1 Bool:TRUE */
565 struct HandlerData *data = (struct HandlerData *) packet->dp_Arg1;
567 #ifdef DEBUG
568 kprintf("ACTION_END\n");
569 #endif
571 // Abort any reading requests
573 if(data->readreq) {
574 AbortIO((struct IORequest *) data->readreq);
575 WaitIO((struct IORequest *) data->readreq);
578 // Finish any playing requests
580 if(data->writing) {
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);
591 FreeHData(data);
592 FreeAudio();
595 break;
598 /***********************************************************************/
600 case ACTION_IS_FILESYSTEM:
601 packet->dp_Res1 = DOS_FALSE;
602 break;
604 /***********************************************************************/
606 default:
607 #ifdef DEBUG
608 kprintf("Unknown packet!\n");
609 #endif
610 packet->dp_Res1 = DOS_FALSE;
611 packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
612 break;
614 } /* switch */
616 if(AllocCnt == 0)
617 Running = FALSE;
619 if (packet) {
620 returnpacket (packet);
621 #ifdef DEBUG
622 kprintf("Retured packet\n");
623 #endif
626 } /* for */
628 #ifdef DEBUG
629 kprintf("Dying..!\n");
630 #endif
631 UnInitialize();
632 _exit (0);
636 /******************************************************************************
637 **** PlayAndSwap **************************************************************
638 ******************************************************************************/
641 * Starts to play the current buffer. Handles double buffering.
644 LONG PlayAndSwap(struct HandlerData *data, LONG length) {
645 void *temp;
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));
666 data->offset = 0;
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;
685 else {
686 return ERROR_WRITE_PROTECTED;
691 return 0;
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;
708 long exponent,sign;
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)
719 sign = -1;
720 else
721 sign = 1;
723 // Unbias the exponent
725 exponent = (exponent & 0x7FFF) - 0x3FFF;
727 // If the exponent is negative, set the mantissa to zero
729 if(exponent < 0)
730 mantissa = 0;
731 else
733 // Special meaning?
735 exponent -= 31;
737 // Overflow?
739 if(exponent > 0)
740 mantissa = 0x7FFFFFFF;
741 else
742 mantissa >>= -exponent; // Let the point float...
745 // That's all...
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;
763 ex->mantissa[1]=0;
764 while(!(in & 0x80000000))
766 ex->exponent--;
767 in<<=1;
769 ex->mantissa[0]=in;
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;
814 while(len > 0) {
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;
825 if(!data->args.bits)
826 data->args.bits = &data->bits;
827 if(!data->args.length)
828 data->args.length = &data->totallength;
829 if(!data->args.freq)
830 data->args.freq = &data->freq;
832 else if(((ULONG *) src)[0] == ID_SSND) {
833 src += 8;
834 break;
836 src++;
837 len--;
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) {
851 long rc = 0;
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);
862 if(AHIDevice) {
863 rc = ERROR_OBJECT_NOT_FOUND;
865 else {
866 AHIBase=(struct Library *)AHIio->ahir_Std.io_Device;
869 return rc;
873 /******************************************************************************
874 **** FreeAudio ****************************************************************
875 ******************************************************************************/
878 * If we're the last user, close the device now
881 void FreeAudio(void)
883 if(--AllocCnt == 0) {
884 if(AHIDevice == 0)
885 CloseDevice((struct IORequest *)AHIio);
886 AHIDevice = -1;
887 DeleteIORequest((struct IORequest *)AHIio);
888 AHIio = NULL;
889 DeleteMsgPort(AHImp);
890 AHImp = NULL;
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) {
904 long rc = 0;
906 data->rdargs = (struct RDArgs *) AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
907 if(data->rdargs)
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;
934 else {
935 rc = ERROR_BAD_TEMPLATE;
938 else
939 rc = ERROR_BAD_TEMPLATE;
942 else
943 rc = ERROR_NO_FREE_STORE;
945 return rc;
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.
958 #define S8bitmode 0
959 #define S16bitmode 1
960 #define S32bitmode 8
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;
968 long rc = 0;
970 data->initialized = TRUE;
972 // Fill in default values
974 if(!data->args.bits)
975 data->args.bits = &bits;
976 if(!data->args.channels)
977 data->args.channels = &channels;
978 if(!data->args.freq)
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;
994 // 8, 16 or 32 bit
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;
1002 else {
1003 rc = ERROR_OBJECT_WRONG_TYPE;
1004 goto quit;
1007 // Mono or stereo
1009 if((*data->args.channels > 2) || (*data->args.channels < 1)) {
1010 rc = ERROR_OBJECT_WRONG_TYPE;
1011 goto quit;
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... :(
1022 LONG a;
1023 a = *data->args.position * 0x8000;
1024 a = a / 100 + 0x8000;
1025 data->pos = a;
1027 data->priority = *data->args.priority;
1029 if(data->args.seconds) {
1030 data->totallength = *data->args.seconds * data->freq
1031 * AHI_SampleFrameSize(data->type);
1033 else {
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) {
1041 case AIFF:
1042 case AIFC:
1043 data->totallength = data->totallength & ~1; // Make even
1044 break;
1047 data->buffersize = *data->args.buffersize;
1049 quit:
1050 return rc;
1063 /******************************************************************************
1064 **** FreeHData ****************************************************************
1065 ******************************************************************************/
1068 * Deallocate the HandlerData structure
1071 void FreeHData(struct HandlerData *data) {
1072 if(data) {
1073 if(data->rdargs2)
1074 FreeArgs(data->rdargs2);
1075 if(data->rdargs)
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);
1083 FreeVec(data);
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
1127 * under us.
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);
1141 dn->dn_Task = NULL;
1143 #ifdef DEBUG
1144 kprintf("Replying it ...\n");
1145 #endif
1147 // Make sure startup code does not reply the message on exit
1148 _WBenchMsg = NULL;
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;
1163 dn->dn_Task = NULL;
1166 #if defined(__mc68000__) && defined(__libnix__)
1167 void __main(void) {}
1168 #endif