Fixed compatibility of output.
[AROS.git] / rom / usb / classes / camdmidi / camdusbmidi.class.c
blob79c54b4c7780903cf5fea8c533e384d35b35daf8
1 /*
2 *----------------------------------------------------------------------------
3 * camdusbmidi class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 /* TODO: Somebody needs to port the assembly 68k camd driver to something that is used under AROS! */
10 #include "debug.h"
12 #include "camdusbmidi.class.h"
14 /* /// "Lib Stuff" */
15 static const STRPTR libname = MOD_NAME_STRING;
17 static int libInit(LIBBASETYPEPTR nh)
19 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
21 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
23 #define UtilityBase nh->nh_UtilityBase
25 if(UtilityBase)
27 /* Create default config */
28 nh->nh_CurrentCGC.cgc_ChunkID = AROS_LONG2BE(MAKE_ID('C','M','I','D'));
29 nh->nh_CurrentCGC.cgc_Length = AROS_LONG2BE(sizeof(struct ClsGlobalCfg)-8);
31 NewList(&nh->nh_Bindings);
32 } else {
33 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
34 nh = NULL;
37 KPRINTF(10, ("libInit: Ok\n"));
38 return(nh ? TRUE : FALSE);
41 static int libOpen(LIBBASETYPEPTR nh)
43 KPRINTF(10, ("libOpen nh: 0x%08lx\n", nh));
44 nLoadClassConfig(nh);
45 return(TRUE);
48 static int libExpunge(LIBBASETYPEPTR nh)
50 KPRINTF(10, ("libExpunge nh: 0x%08lx\n", nh));
51 CloseLibrary((struct Library *) UtilityBase);
52 return(TRUE);
55 ADD2INITLIB(libInit, 0)
56 ADD2OPENLIB(libOpen, 0)
57 ADD2EXPUNGELIB(libExpunge, 0)
58 /* \\\ */
61 * ***********************************************************************
62 * * Library functions *
63 * ***********************************************************************
66 #include "CAMDDriver.c"
68 /* /// "usbAttemptInterfaceBinding()" */
69 struct NepClassHid * usbAttemptInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif)
71 struct Library *ps;
72 IPTR ifclass;
73 IPTR subclass;
74 IPTR proto;
76 KPRINTF(1, ("nepHidAttemptInterfaceBinding(%08lx)\n", pif));
77 if((ps = OpenLibrary("poseidon.library", 4)))
79 psdGetAttrs(PGA_INTERFACE, pif,
80 IFA_Class, &ifclass,
81 IFA_SubClass, &subclass,
82 IFA_Protocol, &proto,
83 TAG_DONE);
84 CloseLibrary(ps);
85 if((ifclass == AUDIO_CLASSCODE) && (subclass == AUDIO_MIDI_SUBCLASS))
87 return(usbForceInterfaceBinding(nh, pif));
90 return(NULL);
92 /* \\\ */
94 /* /// "usbForceInterfaceBinding()" */
95 struct NepClassHid * usbForceInterfaceBinding(struct NepHidBase *nh, struct PsdInterface *pif)
97 struct Library *ps;
98 struct Library *DOSBase;
99 struct NepClassHid *nch;
100 struct PsdConfig *pc;
101 struct PsdDevice *pd;
102 STRPTR devname;
103 UBYTE buf[64];
104 struct Task *tmptask;
106 KPRINTF(1, ("nepHidAttemptInterfaceBinding(%08lx)\n", pif));
107 if((ps = OpenLibrary("poseidon.library", 4)))
109 if((nch = psdAllocVec(sizeof(struct NepClassHid))))
111 STRPTR srcpos;
112 STRPTR tarpos;
113 UWORD cnt;
115 psdGetAttrs(PGA_INTERFACE, pif, IFA_Config, &pc, TAG_END);
116 psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END);
117 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
119 // generate ID
120 srcpos = devname;
121 tarpos = nch->nch_ShortID;
122 cnt = 31;
123 while(*srcpos && cnt)
125 if(((*srcpos >= 'A') && (*srcpos <= 'Z')) ||
126 ((*srcpos >= 'a') && (*srcpos <= 'z')) ||
127 ((*srcpos >= '0') && (*srcpos <= '9')))
129 *tarpos++ = *srcpos;
130 cnt--;
132 srcpos++;
134 *tarpos = 0;
136 nch->nch_ClsBase = nh;
137 nch->nch_Device = NULL;
138 nch->nch_Interface = pif;
140 nLoadClassConfig(nh);
142 psdSafeRawDoFmt(buf, 64, "camdusbmidi.class<%08lx>", nch);
143 nch->nch_ReadySignal = SIGB_SINGLE;
144 nch->nch_ReadySigTask = FindTask(NULL);
145 SetSignal(0, SIGF_SINGLE);
146 if((tmptask = psdSpawnSubTask(buf, nHidTask, nch)))
148 psdBorrowLocksWait(tmptask, 1UL<<nch->nch_ReadySignal);
149 if(nch->nch_Task)
151 nch->nch_ReadySigTask = NULL;
152 //FreeSignal(nch->nch_ReadySignal);
153 Forbid();
154 AddTail(&nh->nh_Bindings, &nch->nch_Node);
155 Permit();
157 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
158 "Play it again, '%s'!",
159 devname);
160 if((DOSBase = OpenLibrary("dos.library", 37)))
162 BPTR fh;
163 BPTR lock;
165 psdSafeRawDoFmt(buf, 64, "%s/%s", (STRPTR) "DEVS:Midi", nch->nch_ShortID);
166 fh = Open(buf, MODE_OLDFILE);
167 if(!fh)
169 fh = Open(buf, MODE_NEWFILE);
170 if(!fh)
172 lock = CreateDir("DEVS:Midi");
173 if(lock)
175 UnLock(lock);
176 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
177 "Created directory '%s'!",
178 (STRPTR) "DEVS:Midi");
180 fh = Open(buf, MODE_NEWFILE);
182 if(!fh)
184 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
185 "Couldn't generate CAMD MIDI driver '%s'!",
186 buf);
187 } else {
188 UBYTE *tmpmem = psdAllocVec(sizeof(CAMDDriver));
189 if(tmpmem)
191 CopyMemQuick(CAMDDriver, tmpmem, sizeof(CAMDDriver));
192 // fix name of driver -- position is hardcoded, but unlikely to move
193 strcpy(&tmpmem[0x46], nch->nch_ShortID);
194 Write(fh, tmpmem, sizeof(CAMDDriver));
195 psdFreeVec(tmpmem);
196 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
197 "Generated CAMD MIDI driver '%s'!",
198 buf);
200 Close(fh);
203 } else {
204 Close(fh);
206 CloseLibrary(DOSBase);
208 CloseLibrary(ps);
209 return(nch);
212 nch->nch_ReadySigTask = NULL;
213 //FreeSignal(nch->nch_ReadySignal);
214 psdFreeVec(nch);
216 CloseLibrary(ps);
218 return(NULL);
220 /* \\\ */
222 /* /// "usbReleaseInterfaceBinding()" */
223 void usbReleaseInterfaceBinding(struct NepHidBase *nh, struct NepClassHid *nch)
225 struct Library *ps;
226 struct PsdConfig *pc;
227 struct PsdDevice *pd;
228 STRPTR devname;
230 KPRINTF(1, ("nepHidReleaseInterfaceBinding(%08lx)\n", nch));
231 if((ps = OpenLibrary("poseidon.library", 4)))
233 Forbid();
234 Remove(&nch->nch_Node);
235 nch->nch_ReadySignal = SIGB_SINGLE;
236 nch->nch_ReadySigTask = FindTask(NULL);
237 if(nch->nch_Task)
239 Signal(nch->nch_Task, SIGBREAKF_CTRL_C);
241 Permit();
242 while(nch->nch_Task)
244 Wait(1L<<nch->nch_ReadySignal);
246 //FreeSignal(nch->nch_ReadySignal);
247 psdGetAttrs(PGA_INTERFACE, nch->nch_Interface, IFA_Config, &pc, TAG_END);
248 psdGetAttrs(PGA_CONFIG, pc, CA_Device, &pd, TAG_END);
249 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
250 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
251 "'%s' fell silent!",
252 devname);
253 psdFreeVec(nch);
254 CloseLibrary(ps);
257 /* \\\ */
259 /* /// "usbGetAttrsA()" */
260 AROS_LH3(LONG, usbGetAttrsA,
261 AROS_LHA(ULONG, type, D0),
262 AROS_LHA(APTR, usbstruct, A0),
263 AROS_LHA(struct TagItem *, tags, A1),
264 LIBBASETYPEPTR, nh, 5, nep)
266 AROS_LIBFUNC_INIT
268 struct TagItem *ti;
269 LONG count = 0;
271 KPRINTF(1, ("nepHidGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
272 switch(type)
274 case UGA_CLASS:
275 if((ti = FindTagItem(UCCA_Priority, tags)))
277 *((SIPTR *) ti->ti_Data) = 0;
278 count++;
280 if((ti = FindTagItem(UCCA_Description, tags)))
282 *((STRPTR *) ti->ti_Data) = "USB MIDI CAMD Interface class";
283 count++;
285 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
287 *((IPTR *) ti->ti_Data) = TRUE;
288 count++;
290 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
292 *((IPTR *) ti->ti_Data) = FALSE;
293 count++;
295 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
297 *((IPTR *) ti->ti_Data) = FALSE;
298 count++;
300 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
302 *((IPTR *) ti->ti_Data) = nh->nh_UsingDefaultCfg;
303 count++;
305 break;
307 case UGA_BINDING:
308 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
310 *((IPTR *) ti->ti_Data) = FALSE;
311 count++;
313 break;
315 return(count);
316 AROS_LIBFUNC_EXIT
318 /* \\\ */
320 /* /// "usbSetAttrsA()" */
321 AROS_LH3(LONG, usbSetAttrsA,
322 AROS_LHA(ULONG, type, D0),
323 AROS_LHA(APTR, usbstruct, A0),
324 AROS_LHA(struct TagItem *, tags, A1),
325 LIBBASETYPEPTR, nh, 6, nep)
327 AROS_LIBFUNC_INIT
328 return(0);
329 AROS_LIBFUNC_EXIT
331 /* \\\ */
333 /* /// "usbDoMethodA()" */
334 AROS_LH2(IPTR, usbDoMethodA,
335 AROS_LHA(ULONG, methodid, D0),
336 AROS_LHA(IPTR *, methoddata, A1),
337 LIBBASETYPEPTR, nh, 7, nep)
339 AROS_LIBFUNC_INIT
341 KPRINTF(10, ("Do Method %ld\n", methodid));
342 switch(methodid)
344 case UCM_AttemptInterfaceBinding:
345 return((IPTR) usbAttemptInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
347 case UCM_ForceInterfaceBinding:
348 return((IPTR) usbForceInterfaceBinding(nh, (struct PsdInterface *) methoddata[0]));
350 case UCM_ReleaseInterfaceBinding:
351 usbReleaseInterfaceBinding(nh, (struct NepClassHid *) methoddata[0]);
352 return(TRUE);
354 case UCM_OpenCfgWindow:
355 return(nOpenCfgWindow(nh));
357 case UCM_ConfigChangedEvent:
358 nLoadClassConfig(nh);
359 return(TRUE);
361 default:
362 break;
364 return(0);
365 AROS_LIBFUNC_EXIT
367 /* \\\ */
369 /* /// "usbCAMDOpenPort()" */
370 AROS_LH5(APTR, usbCAMDOpenPort,
371 AROS_LHA(APTR, xmitfct, A0),
372 AROS_LHA(APTR, recvfct, A1),
373 AROS_LHA(APTR, userdata, A2),
374 AROS_LHA(STRPTR, idstr, A3),
375 AROS_LHA(ULONG, port, D0),
376 LIBBASETYPEPTR, nh, 15, nep)
378 AROS_LIBFUNC_INIT
380 struct NepClassHid *nch;
381 struct CAMDAdapter *ca;
383 KPRINTF(10, ("Open Port %ld, ID=%s\n", port, idstr));
384 /* theoretically, we could allow multiple USB Midi devices to map
385 to different ports, but at the moment, this should suffice */
386 nch = (struct NepClassHid *) nh->nh_Bindings.lh_Head;
387 if(!nch->nch_Node.ln_Succ)
389 KPRINTF(20, ("No MIDI device available!\n"));
390 return(0);
392 if(port > 15)
394 KPRINTF(20, ("Port %ld out of range!\n", port));
395 return(0);
397 /* fill adapter structure */
398 ca = &nh->nh_CAMDAdapters[port];
399 ca->ca_PortNum = port;
400 ca->ca_TXFunc = xmitfct;
401 ca->ca_RXFunc = recvfct;
402 ca->ca_UserData = userdata;
403 ca->ca_MsgPort = nch->nch_TaskMsgPort;
404 ca->ca_TXBufSize = 4096;
405 ca->ca_TXBuffer = AllocVec(ca->ca_TXBufSize, MEMF_PUBLIC|MEMF_CLEAR);
406 ca->ca_TXReadPos = 0;
407 ca->ca_TXWritePos = 0;
408 if(!ca->ca_TXBuffer)
410 KPRINTF(20, ("Out of memory!\n"));
411 return(0);
413 return(ca);
415 AROS_LIBFUNC_EXIT
417 /* \\\ */
419 /* /// "usbCAMDClosePort()" */
420 AROS_LH2(void, usbCAMDClosePort,
421 AROS_LHA(ULONG, port, D0),
422 AROS_LHA(STRPTR, idstr, A1),
423 LIBBASETYPEPTR, nh, 16, nep)
425 AROS_LIBFUNC_INIT
427 struct CAMDAdapter *ca;
428 KPRINTF(10, ("Close Port %ld, ID=%s\n", port, idstr));
429 if(port > 15)
431 KPRINTF(10, ("Port %ld out of range!\n", port));
433 ca = &nh->nh_CAMDAdapters[port];
434 ca->ca_IsOpen = FALSE;
435 ca->ca_MsgPort = NULL;
436 FreeVec(ca->ca_TXBuffer);
437 ca->ca_TXBuffer = NULL;
439 AROS_LIBFUNC_EXIT
441 /* \\\ */
443 /**************************************************************************/
445 #undef ps
446 #define ps nch->nch_Base
448 /* /// "nHidTask()" */
449 AROS_UFH0(void, nHidTask)
451 AROS_USERFUNC_INIT
453 struct NepClassHid *nch;
454 struct PsdPipe *pp;
455 ULONG sigmask;
456 ULONG sigs;
457 UBYTE *buf;
458 LONG ioerr;
459 ULONG len;
461 if((nch = nAllocHid()))
463 Forbid();
464 if(nch->nch_ReadySigTask)
466 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
468 Permit();
469 sigmask = (1L<<nch->nch_TaskMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
470 buf = nch->nch_EPInBuf;
471 psdSendPipe(nch->nch_EPInPipe, buf, 1024);
474 sigs = Wait(sigmask);
475 while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort)))
477 if(pp == nch->nch_EPInPipe)
479 if(!(ioerr = psdGetPipeError(pp)))
481 len = psdGetPipeActual(pp);
482 nParseMidi(nch, buf, len);
484 psdSendPipe(nch->nch_EPInPipe, buf, 1024);
485 break;
488 nParseMidiOut(nch);
489 } while(!(sigs & SIGBREAKF_CTRL_C));
490 KPRINTF(20, ("Going down the river!\n"));
491 psdAbortPipe(nch->nch_EPInPipe);
492 psdWaitPipe(nch->nch_EPInPipe);
493 nFreeHid(nch);
496 AROS_USERFUNC_EXIT
498 /* \\\ */
500 /* /// "nParseMidiOut()" */
501 void nParseMidiOut(struct NepClassHid *nch)
503 UBYTE *out = nch->nch_EPOutBuf;
504 UWORD goodpkt = 0;
505 UWORD cnt;
506 struct CAMDAdapter *ca;
507 ca = nch->nch_ClsBase->nh_CAMDAdapters;
508 for(cnt = 0; cnt < 16; cnt++)
510 if(ca->ca_IsOpen && ca->ca_TXReadPos != ca->ca_TXWritePos)
512 ULONG chan = ca->ca_PortNum<<4;
513 ULONG mask = ca->ca_TXBufSize - 1;
514 ULONG len = (ca->ca_TXWritePos + ca->ca_TXBufSize - ca->ca_TXReadPos) & mask;
515 UBYTE *buf = ca->ca_TXBuffer;
516 UBYTE cmd;
517 if(len > 100)
519 KPRINTF(1, ("TXWritePos=%ld, TXReadPos=%ld, len=%ld", ca->ca_TXWritePos, ca->ca_TXReadPos, len));
521 //KPRINTF(1, ("Data OUT %ld\n", len));
524 cmd = buf[ca->ca_TXReadPos];
525 if(cmd & 0x80)
527 if(ca->ca_SysExMode && (cmd != 0xf0) && (cmd != 0xf7))
529 KPRINTF(10, ("SysEx Paused\n"));
530 // sysex paused
531 ca->ca_SysExMode = 2;
533 switch(cmd>>4)
535 case 0x8:
536 case 0x9:
537 case 0xa:
538 case 0xb:
539 case 0xe:
540 if(len < 3)
542 len = 0;
543 break;
545 len -= 3;
546 *out++ = cmd|chan;
547 *out++ = cmd;
548 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
549 *out++ = buf[ca->ca_TXReadPos];
550 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
551 *out++ = buf[ca->ca_TXReadPos];
552 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
553 goodpkt++;
554 break;
556 case 0xc:
557 case 0xd:
558 if(len < 2)
560 len = 0;
561 break;
563 len -= 2;
564 *out++ = cmd|chan;
565 *out++ = cmd;
566 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
567 *out++ = buf[ca->ca_TXReadPos];
568 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
569 *out++ = 0;
570 goodpkt++;
571 break;
573 case 0xf:
574 switch(cmd & 0xf)
576 case 0x0: // SysEx start
577 KPRINTF(10, ("SysEx Starts\n"));
578 if(!ca->ca_SysExMode)
580 ca->ca_SysExMode = 1;
581 ca->ca_SysExData = cmd;
582 ca->ca_SysExNum = 1;
584 len--;
585 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
586 break;
588 case 0x2: // SPP
589 if(len < 3)
591 len = 0;
592 break;
594 len -= 3;
595 *out++ = 0x3|chan;
596 *out++ = cmd;
597 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
598 *out++ = buf[ca->ca_TXReadPos];
599 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
600 *out++ = buf[ca->ca_TXReadPos];
601 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
602 goodpkt++;
603 break;
605 case 0x3: // SongSelect
606 if(len < 2)
608 len = 0;
609 break;
611 len -= 2;
612 *out++ = 0x2|chan;
613 *out++ = cmd;
614 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
615 *out++ = buf[ca->ca_TXReadPos];
616 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
617 *out++ = 0;
618 goodpkt++;
619 break;
621 case 0x7: // SysEx Ends
622 len--;
623 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
624 if(ca->ca_SysExMode)
626 KPRINTF(10, ("SysEx Ends\n"));
627 if(ca->ca_SysExMode == 2)
629 KPRINTF(10, ("SysEx Resume\n"));
630 // was paused, continue
631 ca->ca_SysExMode = 1;
632 break;
635 if(ca->ca_SysExNum == 0)
637 *out++ = 0x5|chan;
638 *out++ = cmd;
639 *out++ = 0;
640 *out++ = 0;
642 else if(ca->ca_SysExNum == 1)
644 *out++ = 0x6|chan;
645 *out++ = ca->ca_SysExData;
646 *out++ = cmd;
647 *out++ = 0;
648 } else {
649 *out++ = 0x7|chan;
650 *out++ = ca->ca_SysExData>>8;
651 *out++ = ca->ca_SysExData;
652 *out++ = cmd;
654 KPRINTF(10, ("LastPkt: %08lx\n", *((ULONG *) &out[-4])));
655 goodpkt++;
656 ca->ca_SysExMode = 0;
657 } else {
658 KPRINTF(10, ("SysEx End Ignored\n"));
660 break;
662 case 0x8: // Timing Clock.
663 case 0x9: // Undefined. (Reserved)
664 case 0xa: // Start.
665 case 0xb: // Continue.
666 case 0xc: // Stop.
667 case 0xd: // Undefined. (Reserved)
668 case 0xe: // Active Sensing.
669 case 0xf: // Reset.
670 len--;
671 *out++ = 0xf|chan;
672 *out++ = cmd;
673 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
674 *out++ = 0;
675 *out++ = 0;
676 goodpkt++;
677 break;
679 break;
681 if(!len)
683 break;
685 } else {
686 if(ca->ca_SysExMode)
688 ca->ca_SysExData <<= 8;
689 ca->ca_SysExData |= cmd;
690 ca->ca_SysExNum++;
691 if(ca->ca_SysExNum == 3)
693 KPRINTF(1, ("Cont 3B SysEx %06lx\n", ca->ca_SysExData));
694 *((ULONG *) out) = ((0x4|chan)<<24)|ca->ca_SysExData;
695 goodpkt++;
696 ca->ca_SysExData = 0;
697 ca->ca_SysExNum = 0;
700 len--;
701 ca->ca_TXReadPos = (ca->ca_TXReadPos+1) & mask;
703 } while(len && (goodpkt < 2040));
705 ca++;
707 if(goodpkt)
709 //KPRINTF(1, ("Sending %ld pkts\n", goodpkt));
710 psdDoPipe(nch->nch_EPOutPipe, nch->nch_EPOutBuf, (ULONG) goodpkt<<2);
713 /* \\\ */
715 /* /// "nParseMidi()" */
716 void nParseMidi(struct NepClassHid *nch, UBYTE *buf, ULONG len)
718 UWORD cmd;
719 UWORD chan;
720 struct CAMDAdapter *ca;
722 while(len > 3)
724 KPRINTF(1, ("Msg: %02lx %02lx %02lx %02lx\n", buf[0], buf[1], buf[2], buf[3]));
725 chan = buf[0] >> 4;
726 ca = &nch->nch_ClsBase->nh_CAMDAdapters[chan];
727 if(ca->ca_IsOpen)
729 cmd = buf[0] & 0x0f;
730 switch(cmd)
732 case 0x0: // Miscellaneous function codes. Reserved for future extensions.
733 case 0x1: // Cable events. Reserved for future expansion.
734 break;
736 case 0x5: // Single-byte System Common Message or SysEx ends with following single byte.
737 case 0xF: // Single Byte
738 *buf = 1;
739 CallHookA(&ca->ca_CAMDRXFunc, (Object *) buf, NULL);
740 break;
742 case 0x2: // Two-byte System Common messages like MTC, SongSelect, etc.
743 case 0x6: // SysEx ends with following two bytes. *** FIXME? ***
744 *buf = 2;
745 CallHookA(&ca->ca_CAMDRXFunc, (Object *) buf, NULL);
746 break;
748 case 0x3: // Three-byte System Common messages like SPP, etc.
749 case 0x4: // SysEx starts or continues *** FIXME? ***
750 case 0x7: // SysEx ends with following three bytes. *** FIXME? ***
751 case 0x8: // Note-off
752 case 0x9: // Note-on
753 case 0xA: // Poly-KeyPress
754 case 0xB: // Control Change
755 case 0xE: // PitchBend Change
756 *buf = 3;
757 CallHookA(&ca->ca_CAMDRXFunc, (Object *) buf, NULL);
758 break;
760 case 0xC: // Program Change
761 case 0xD: // Channel Pressure
762 *buf = 2;
763 CallHookA(&ca->ca_CAMDRXFunc, (Object *) buf, NULL);
764 break;
766 } else {
767 KPRINTF(1, ("Not open\n"));
770 buf += 4;
771 len -= 4;
774 /* \\\ */
776 /* /// "nAllocHid()" */
777 struct NepClassHid * nAllocHid(void)
779 struct Task *thistask;
780 struct NepClassHid *nch;
782 thistask = FindTask(NULL);
783 nch = thistask->tc_UserData;
786 if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4)))
788 Alert(AG_OpenLib);
789 break;
791 psdGetAttrs(PGA_INTERFACE, nch->nch_Interface,
792 IFA_Config, &nch->nch_Config,
793 IFA_InterfaceNum, &nch->nch_IfNum,
794 TAG_END);
795 psdGetAttrs(PGA_CONFIG, nch->nch_Config,
796 CA_Device, &nch->nch_Device,
797 TAG_END);
799 nch->nch_EPIn = psdFindEndpoint(nch->nch_Interface, NULL,
800 EA_IsIn, TRUE,
801 EA_TransferType, USEAF_BULK,
802 TAG_END);
804 nch->nch_EPOut = psdFindEndpoint(nch->nch_Interface, NULL,
805 EA_IsIn, FALSE,
806 EA_TransferType, USEAF_BULK,
807 TAG_END);
808 if(!(nch->nch_EPIn && nch->nch_EPOut))
810 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
811 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
812 "No Bulk-In or Bulk-Out Endpoint!");
813 break;
815 if((nch->nch_TaskMsgPort = CreateMsgPort()))
817 if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL)))
819 if((nch->nch_EPInPipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EPIn)))
821 psdSetAttrs(PGA_PIPE, nch->nch_EPInPipe,
822 PPA_NakTimeout, FALSE,
823 PPA_AllowRuntPackets, TRUE,
824 TAG_END);
826 if((nch->nch_EPOutPipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EPOut)))
828 psdSetAttrs(PGA_PIPE, nch->nch_EPOutPipe,
829 PPA_NakTimeout, TRUE,
830 PPA_AllowRuntPackets, TRUE,
831 PPA_NakTimeoutTime, 5000,
832 TAG_END);
833 if((nch->nch_EPInBuf = psdAllocVec(1024)))
835 if((nch->nch_EPOutBuf = psdAllocVec(8192)))
837 nch->nch_Task = thistask;
838 return(nch);
840 psdFreeVec(nch->nch_EPInBuf);
842 psdFreePipe(nch->nch_EPOutPipe);
844 psdFreePipe(nch->nch_EPInPipe);
846 psdFreePipe(nch->nch_EP0Pipe);
848 DeleteMsgPort(nch->nch_TaskMsgPort);
850 } while(FALSE);
851 CloseLibrary(nch->nch_Base);
852 Forbid();
853 nch->nch_Task = NULL;
854 if(nch->nch_ReadySigTask)
856 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
858 return(NULL);
860 /* \\\ */
862 /* /// "nFreeHid()" */
863 void nFreeHid(struct NepClassHid *nch)
865 UWORD cnt;
866 /* delete all msgport references to this instance, disabling all midi transmissions */
867 Forbid();
868 for(cnt = 0; cnt < 16; cnt++)
870 nch->nch_ClsBase->nh_CAMDAdapters[cnt].ca_MsgPort = NULL;
872 Permit();
873 psdFreeVec(nch->nch_EPOutBuf);
874 psdFreeVec(nch->nch_EPInBuf);
875 psdFreePipe(nch->nch_EPOutPipe);
876 psdFreePipe(nch->nch_EPInPipe);
877 psdFreePipe(nch->nch_EP0Pipe);
878 DeleteMsgPort(nch->nch_TaskMsgPort);
879 CloseLibrary(nch->nch_Base);
880 Forbid();
881 nch->nch_Task = NULL;
882 if(nch->nch_ReadySigTask)
884 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
887 /* \\\ */
889 /**************************************************************************/
891 #undef ps
893 /* /// "nLoadClassConfig()" */
894 BOOL nLoadClassConfig(struct NepHidBase *nh)
896 struct Library *ps;
897 struct ClsGlobalCfg *cgc;
898 struct PsdIFFContext *pic;
900 KPRINTF(10, ("Loading Class Config...\n"));
901 if(!(ps = OpenLibrary("poseidon.library", 4)))
903 return(FALSE);
905 Forbid();
906 nh->nh_UsingDefaultCfg = TRUE;
907 pic = psdGetClsCfg(libname);
908 if(pic)
910 if((cgc = psdGetCfgChunk(pic, AROS_LONG2BE(nh->nh_CurrentCGC.cgc_ChunkID))))
912 CopyMem(((UBYTE *) cgc) + 8, ((UBYTE *) &nh->nh_CurrentCGC) + 8, min(AROS_LONG2BE(cgc->cgc_Length), AROS_LONG2BE(nh->nh_CurrentCGC.cgc_Length)));
913 psdFreeVec(cgc);
914 nh->nh_UsingDefaultCfg = FALSE;
917 Permit();
918 CloseLibrary(ps);
919 return(FALSE);
921 /* \\\ */
923 /* /// "nOpenCfgWindow()" */
924 LONG nOpenCfgWindow(struct NepHidBase *nh)
926 struct Library *ps;
927 KPRINTF(10, ("Opening GUI...\n"));
928 if(!(ps = OpenLibrary("poseidon.library", 4)))
930 return(FALSE);
932 Forbid();
933 if(!nh->nh_GUITask)
935 if((nh->nh_GUITask = psdSpawnSubTask(MOD_NAME_STRING " GUI", nGUITask, nh)))
937 Permit();
938 CloseLibrary(ps);
939 return(TRUE);
942 Permit();
943 CloseLibrary(ps);
944 return(FALSE);
946 /* \\\ */
948 /* /// "nGUITask()" */
949 AROS_UFH0(void, nGUITask)
951 AROS_USERFUNC_INIT
953 struct Task *thistask;
954 struct NepHidBase *nh;
955 APTR pic;
957 thistask = FindTask(NULL);
958 #undef ps
959 #define ps nh->nh_PsdBase
960 #undef IntuitionBase
961 #define IntuitionBase nh->nh_IntBase
962 #undef MUIMasterBase
963 #define MUIMasterBase nh->nh_MUIBase
965 nh = thistask->tc_UserData;
966 ++nh->nh_Library.lib_OpenCnt;
967 if(!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MUIMASTER_VMIN)))
969 KPRINTF(10, ("Couldn't open muimaster.library.\n"));
970 nGUITaskCleanup(nh);
971 return;
974 if(!(IntuitionBase = OpenLibrary("intuition.library", 39)))
976 KPRINTF(10, ("Couldn't open intuition.library.\n"));
977 nGUITaskCleanup(nh);
978 return;
980 if(!(ps = OpenLibrary("poseidon.library", 4)))
982 KPRINTF(10, ("Couldn't open poseidon.library.\n"));
983 nGUITaskCleanup(nh);
984 return;
987 nh->nh_App = ApplicationObject,
988 MUIA_Application_Title , (IPTR)libname,
989 MUIA_Application_Version , (IPTR)VERSION_STRING,
990 MUIA_Application_Copyright , (IPTR)"©2006-2009 Chris Hodges",
991 MUIA_Application_Author , (IPTR)"Chris Hodges <chrisly@platon42.de>",
992 MUIA_Application_Description, (IPTR)"Settings for the camdusbmidi.class",
993 MUIA_Application_Base , (IPTR)"CAMDUSBMIDI",
994 MUIA_Application_HelpFile , (IPTR)"HELP:Poseidon.guide",
995 MUIA_Application_Menustrip , (IPTR)MenustripObject,
996 Child, (IPTR)MenuObjectT((IPTR)"Project"),
997 Child, (IPTR)(nh->nh_AboutMI = MenuitemObject,
998 MUIA_Menuitem_Title, (IPTR)"About...",
999 MUIA_Menuitem_Shortcut, (IPTR)"?",
1000 End),
1001 End,
1002 Child, (IPTR)MenuObjectT((IPTR)"Settings"),
1003 Child, (IPTR)(nh->nh_UseMI = MenuitemObject,
1004 MUIA_Menuitem_Title, (IPTR)"Save",
1005 MUIA_Menuitem_Shortcut, (IPTR)"S",
1006 End),
1007 Child, (IPTR)MenuitemObject,
1008 MUIA_Menuitem_Title, (IPTR)NM_BARLABEL,
1009 End,
1010 Child, (IPTR)(nh->nh_MUIPrefsMI = MenuitemObject,
1011 MUIA_Menuitem_Title, (IPTR)"MUI Settings",
1012 MUIA_Menuitem_Shortcut, (IPTR)"M",
1013 End),
1014 End,
1015 End,
1017 SubWindow, (IPTR)(nh->nh_MainWindow = WindowObject,
1018 MUIA_Window_ID , MAKE_ID('M','A','I','N'),
1019 MUIA_Window_Title, (IPTR)libname,
1020 MUIA_HelpNode, (IPTR)libname,
1022 WindowContents, (IPTR)VGroup,
1023 Child, (IPTR)ColGroup(2), GroupFrameT("Global Settings"),
1024 Child, (IPTR)Label((IPTR) "None"),
1025 Child, (IPTR)HSpace(0),
1026 End,
1027 Child, (IPTR)VSpace(0),
1028 Child, (IPTR)HGroup,
1029 MUIA_Group_SameWidth, TRUE,
1030 Child, (IPTR)(nh->nh_UseObj = TextObject, ButtonFrame,
1031 MUIA_Background, MUII_ButtonBack,
1032 MUIA_CycleChain, 1,
1033 MUIA_InputMode, MUIV_InputMode_RelVerify,
1034 MUIA_Text_Contents, (IPTR)"\33c Save ",
1035 End),
1036 Child, (IPTR)(nh->nh_CloseObj = TextObject, ButtonFrame,
1037 MUIA_Background, MUII_ButtonBack,
1038 MUIA_CycleChain, 1,
1039 MUIA_InputMode, MUIV_InputMode_RelVerify,
1040 MUIA_Text_Contents, (IPTR)"\33c Use ",
1041 End),
1042 End,
1043 End,
1044 End),
1045 End;
1047 if(!nh->nh_App)
1049 KPRINTF(10, ("Couldn't create application\n"));
1050 nGUITaskCleanup(nh);
1051 return;
1053 DoMethod(nh->nh_MainWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
1054 nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1055 DoMethod(nh->nh_UseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1056 nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1057 DoMethod(nh->nh_CloseObj, MUIM_Notify, MUIA_Pressed, FALSE,
1058 nh->nh_App, 2, MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);
1060 DoMethod(nh->nh_AboutMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1061 nh->nh_App, 2, MUIM_Application_ReturnID, ID_ABOUT);
1062 DoMethod(nh->nh_UseMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1063 nh->nh_App, 2, MUIM_Application_ReturnID, ID_STORE_CONFIG);
1064 DoMethod(nh->nh_MUIPrefsMI, MUIM_Notify, MUIA_Menuitem_Trigger, MUIV_EveryTime,
1065 nh->nh_App, 2, MUIM_Application_OpenConfigWindow, 0);
1068 IPTR isopen = 0;
1069 IPTR iconify = 0;
1070 ULONG sigs;
1071 ULONG sigmask;
1072 LONG retid;
1074 get(nh->nh_App, MUIA_Application_Iconified, &iconify);
1075 set(nh->nh_MainWindow, MUIA_Window_Open, TRUE);
1076 get(nh->nh_MainWindow, MUIA_Window_Open, &isopen);
1077 if(!(isopen || iconify))
1079 nGUITaskCleanup(nh);
1080 return;
1082 sigmask = 0;
1085 retid = DoMethod(nh->nh_App, MUIM_Application_NewInput, &sigs);
1086 switch(retid)
1088 case ID_STORE_CONFIG:
1089 case MUIV_Application_ReturnID_Quit:
1090 pic = psdGetClsCfg(libname);
1091 if(!pic)
1093 psdSetClsCfg(libname, NULL);
1094 pic = psdGetClsCfg(libname);
1096 if(pic)
1098 if(psdAddCfgEntry(pic, &nh->nh_CurrentCGC))
1100 if(retid != MUIV_Application_ReturnID_Quit)
1102 psdSaveCfgToDisk(NULL, FALSE);
1104 retid = MUIV_Application_ReturnID_Quit;
1107 break;
1109 case ID_ABOUT:
1110 MUI_RequestA(nh->nh_App, nh->nh_MainWindow, 0, NULL, "Marvellous!", VERSION_STRING, NULL);
1111 break;
1113 if(retid == MUIV_Application_ReturnID_Quit)
1115 break;
1117 if(sigs)
1119 sigs = Wait(sigs | sigmask | SIGBREAKF_CTRL_C);
1120 if(sigs & SIGBREAKF_CTRL_C)
1122 break;
1125 } while(TRUE);
1126 set(nh->nh_MainWindow, MUIA_Window_Open, FALSE);
1128 nGUITaskCleanup(nh);
1130 AROS_USERFUNC_EXIT
1132 /* \\\ */
1134 /* /// "nGUITaskCleanup()" */
1135 void nGUITaskCleanup(struct NepHidBase *nh)
1137 if(nh->nh_App)
1139 MUI_DisposeObject(nh->nh_App);
1140 nh->nh_App = NULL;
1142 if(MUIMasterBase)
1144 CloseLibrary(MUIMasterBase);
1145 MUIMasterBase = NULL;
1147 if(IntuitionBase)
1149 CloseLibrary(IntuitionBase);
1150 IntuitionBase = NULL;
1152 if(ps)
1154 CloseLibrary(ps);
1155 ps = NULL;
1157 Forbid();
1158 nh->nh_GUITask = NULL;
1159 --nh->nh_Library.lib_OpenCnt;
1161 /* \\\ */