grub2: bring back build of aros-side grub2 tools
[AROS.git] / rom / usb / poseidon / poseidon.library.c
blob54d7472835d246892dff5a032c576021dedd4b97
1 /****************************************************************************
3 __ __ V/\V. /\
4 |" | |" | mMMnw, || []
5 | | | | (o o)W () || ||
6 |__|_|_"| | / |Mw || ||//
7 (" " \| \ -'_/mw \\||/
8 \______) ~%%/WM" \||
9 _____ ___ ______ _____ __ _____ ___ __ __/~~__ ~~\ _||
10 |"(" \()/\" \ ()/"_ )|"(___) ) )|"(" \ ()/\" \(__)/" ) /" ) " \ /_)O
11 | ) )/" \ \ (_/"\__/ | )_ ( ( | )_ ) /" \ \ / /|/ / ·\ \/ ,|O
12 | (___/( (_\__) _\ \_ | (__) ) )| (__) |( (_\__)/ /"/ / |\ '_|O
13 | | _ \ / / /" \_/ ) | ")__ ( ( | )" ) \ / // /|/ / . .|/\__/ ||
14 |__| (_) \/__/ (______/ |_(___) )_)|_(___/ . \/__/(__/ (__/ .:.:| ||
15 _____
16 |" __ \ Poseidon -- The divine USB stack for Amiga computers
17 | (__) )
18 | __ ( Designed and written by
19 |"(__) ) Chris Hodges <chrisly@platon42.de>
20 |_____/ Copyright ©2002-2009 Chris Hodges. All rights reserved.
22 ****************************************************************************/
25 *----------------------------------------------------------------------------
26 * Poseidon main library
27 *----------------------------------------------------------------------------
28 * By Chris Hodges <chrisly@platon42.de>
31 #include "debug.h"
33 #include "poseidon.library.h"
35 #include "numtostr.h"
37 #include <proto/exec.h>
38 #include <proto/dos.h>
39 #include <proto/utility.h>
40 #include <proto/usbclass.h>
41 #include <proto/timer.h>
43 #ifdef __AROS__
44 #include <aros/bootloader.h>
45 #include <proto/bootloader.h>
46 #endif
48 #define NewList(list) NEWLIST(list)
50 #define min(x,y) (((x) < (y)) ? (x) : (y))
51 #define max(x,y) (((x) > (y)) ? (x) : (y))
53 extern const struct PsdWStringMap usbclasscodestr[];
54 extern const struct PsdULStringMap usbcomboclasscodestr[];
55 extern const struct PsdULStringMap usbdesctypestr[];
56 extern const struct PsdWStringMap usbhwioerrstr[];
57 extern const struct PsdUWStringMap usblangids[];
58 extern const struct PsdUWStringMap usbvendorids[];
60 extern struct ExecBase *SysBase;
62 /* Static data */
63 const char GM_UNIQUENAME(libname)[] = MOD_NAME_STRING;
65 #define UsbClsBase puc->puc_ClassBase
66 #define DOSBase ps->ps_DosBase
67 #define TimerBase ps->ps_TimerIOReq.tr_node.io_Device
69 /* LibInit */
70 static int GM_UNIQUENAME(libInit)(LIBBASETYPEPTR ps)
72 KPRINTF(10, ("libInit ps: 0x%p SysBase: 0x%p\n",
73 ps, SysBase));
75 ps->ps_StackInit = FALSE;
76 ps->ps_UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 39);
78 #define UtilityBase ps->ps_UtilityBase
80 if (UtilityBase)
82 #ifdef __AROS__
83 APTR BootLoaderBase = OpenResource("bootloader.resource");
85 if (BootLoaderBase)
87 struct List *args = GetBootInfo(BL_Args);
89 if (args)
91 struct Node *node;
93 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
95 if (stricmp(node->ln_Name, "usbdebug") == 0)
97 ps->ps_Flags = PSF_KLOG;
98 break;
103 #endif
105 NewList(&ps->ps_Hardware);
106 NewList(&ps->ps_Classes);
107 NewList(&ps->ps_ErrorMsgs);
108 NewList(&ps->ps_EventHooks);
109 ps->ps_EventReplyPort.mp_Flags = PA_IGNORE;
110 NewList(&ps->ps_EventReplyPort.mp_MsgList);
111 NewList(&ps->ps_ConfigRoot);
112 NewList(&ps->ps_AlienConfigs);
114 NewList(&ps->ps_DeadlockDebug);
116 InitSemaphore(&ps->ps_ReentrantLock);
117 InitSemaphore(&ps->ps_PoPoLock);
119 if((ps->ps_MemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC|MEMF_SEM_PROTECTED, 16384, 1024)))
121 if((ps->ps_SemaMemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC, 16*sizeof(struct PsdReadLock), sizeof(struct PsdBorrowLock))))
123 pInitSem(ps, &ps->ps_Lock, "PBase");
124 pInitSem(ps, &ps->ps_ConfigLock, "ConfigLock");
125 KPRINTF(20, ("libInit: Done!\n"));
126 return TRUE;
128 DeletePool(ps->ps_MemPool);
129 } else {
130 KPRINTF(20, ("libInit: CreatePool() failed!\n"));
132 CloseLibrary((struct Library *) UtilityBase);
133 } else {
134 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
136 return FALSE;
139 /* LibOpen */
140 static int GM_UNIQUENAME(libOpen)(LIBBASETYPEPTR ps)
142 struct PsdIFFContext *pic;
144 KPRINTF(10, ("libOpen ps: 0x%p\n", ps));
145 ObtainSemaphore(&ps->ps_ReentrantLock);
146 if(!ps->ps_StackInit)
148 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
149 ps->ps_TimerIOReq.tr_node.io_Message.mn_ReplyPort = NULL;
150 ps->ps_TimerIOReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest);
151 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) &ps->ps_TimerIOReq, 0))
153 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Name = "Poseidon";
154 ps->ps_TimerIOReq.tr_node.io_Command = TR_ADDREQUEST;
156 ps->ps_ReleaseVersion = RELEASEVERSION;
157 ps->ps_OSVersion = MAKE_ID('A','R','O','S');
159 pic = pAllocForm(ps, NULL, IFFFORM_PSDCFG);
160 if((ps->ps_GlobalCfg = psdAllocVec(sizeof(struct PsdGlobalCfg))))
162 ps->ps_GlobalCfg->pgc_ChunkID = AROS_LONG2BE(IFFCHNK_GLOBALCFG);
163 ps->ps_GlobalCfg->pgc_Length = AROS_LONG2BE(sizeof(struct PsdGlobalCfg)-8);
164 ps->ps_GlobalCfg->pgc_LogInfo = TRUE;
165 ps->ps_GlobalCfg->pgc_LogWarning = TRUE;
166 ps->ps_GlobalCfg->pgc_LogError = TRUE;
167 ps->ps_GlobalCfg->pgc_LogFailure = TRUE;
168 ps->ps_GlobalCfg->pgc_BootDelay = 2;
169 ps->ps_GlobalCfg->pgc_SubTaskPri = 5;
170 ps->ps_GlobalCfg->pgc_PopupDeviceNew = PGCP_ISNEW;
171 ps->ps_GlobalCfg->pgc_PopupDeviceGone = TRUE;
172 ps->ps_GlobalCfg->pgc_PopupDeviceDeath = TRUE;
173 ps->ps_GlobalCfg->pgc_PopupCloseDelay = 5;
174 ps->ps_GlobalCfg->pgc_PopupActivateWin = FALSE;
175 ps->ps_GlobalCfg->pgc_PopupWinToFront = TRUE;
176 ps->ps_GlobalCfg->pgc_AutoDisableLP = FALSE;
177 ps->ps_GlobalCfg->pgc_AutoDisableDead = FALSE;
178 ps->ps_GlobalCfg->pgc_AutoRestartDead = TRUE;
179 ps->ps_GlobalCfg->pgc_PowerSaving = FALSE;
180 ps->ps_GlobalCfg->pgc_ForceSuspend = FALSE;
181 ps->ps_GlobalCfg->pgc_SuspendTimeout = 30;
183 ps->ps_GlobalCfg->pgc_PrefsVersion = 0; // is updated on writing
184 ps->ps_ConfigRead = FALSE;
185 if(pic)
187 pic = pAllocForm(ps, pic, IFFFORM_STACKCFG);
188 if(pic)
190 pAddCfgChunk(ps, pic, ps->ps_GlobalCfg);
193 ps->ps_PoPo.po_InsertSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Connect.iff");
194 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Disconnect.iff");
197 STRPTR tmpstr;
198 tmpstr = psdCopyStr((STRPTR) VERSION_STRING);
199 if(tmpstr)
201 tmpstr[strlen(tmpstr)-2] = 0;
202 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s (%p)!", tmpstr, ps->ps_ReleaseVersion);
203 psdFreeVec(tmpstr);
204 } else {
205 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s", VERSION_STRING);
209 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "This is the AROS port.");
211 KPRINTF(10, ("libOpen: Ok\n"));
212 ps->ps_StackInit = TRUE;
213 ReleaseSemaphore(&ps->ps_ReentrantLock);
214 pStartEventHandler(ps);
216 return TRUE;
217 } else {
218 KPRINTF(20, ("libOpen: No memory for cfg!\n"));
220 } else {
221 KPRINTF(20, ("libOpen: OpenDevice(timer.device) failed!\n"));
223 ReleaseSemaphore(&ps->ps_ReentrantLock);
224 return FALSE;
226 ReleaseSemaphore(&ps->ps_ReentrantLock);
227 KPRINTF(5, ("libOpen: openCnt = %ld\n", ps->ps_Library.lib_OpenCnt));
228 return TRUE;
231 int GM_UNIQUENAME(libExpunge)(LIBBASETYPEPTR ps)
233 struct PsdHardware *phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
234 struct PsdUsbClass *puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
235 struct PsdErrorMsg *pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
236 struct PsdIFFContext *pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
237 KPRINTF(10, ("libExpunge ps: 0x%p\n", ps));
238 while(phw->phw_Node.ln_Succ)
240 psdRemHardware(phw);
241 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
243 while(puc->puc_Node.ln_Succ)
245 psdRemClass(puc);
246 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
248 while(pem->pem_Node.ln_Succ)
250 psdRemErrorMsg(pem);
251 pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
254 while(pic->pic_Node.ln_Succ)
256 pFreeForm(ps, pic);
257 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
260 if(ps->ps_PoPo.po_Task)
262 ps->ps_PoPo.po_ReadySignal = SIGB_SINGLE;
263 ps->ps_PoPo.po_ReadySigTask = FindTask(NULL);
264 Signal(ps->ps_PoPo.po_Task, SIGBREAKF_CTRL_C);
265 while(ps->ps_PoPo.po_Task)
267 Wait(1L<<ps->ps_PoPo.po_ReadySignal);
269 ps->ps_PoPo.po_ReadySigTask = NULL;
270 //FreeSignal(ps->ps_PoPo.po_ReadySignal);
272 if(ps->ps_EventHandler.ph_Task)
274 ps->ps_EventHandler.ph_ReadySignal = SIGB_SINGLE;
275 ps->ps_EventHandler.ph_ReadySigTask = FindTask(NULL);
276 Signal(ps->ps_EventHandler.ph_Task, SIGBREAKF_CTRL_C);
277 while(ps->ps_EventHandler.ph_Task)
279 Wait(1L<<ps->ps_EventHandler.ph_ReadySignal);
281 ps->ps_EventHandler.ph_ReadySigTask = NULL;
282 //FreeSignal(ps->ps_EventHandler.ph_ReadySignal);
284 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
285 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
286 pGarbageCollectEvents(ps);
288 CloseDevice((struct IORequest *) &ps->ps_TimerIOReq);
289 DeletePool(ps->ps_SemaMemPool);
290 DeletePool(ps->ps_MemPool);
292 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%p\n",
293 UtilityBase));
294 CloseLibrary((struct Library *) UtilityBase);
296 CloseLibrary(DOSBase);
298 KPRINTF(1, ("libExpunge: removing library node 0x%p\n",
299 &ps->ps_Library.lib_Node));
300 Remove(&ps->ps_Library.lib_Node);
302 return TRUE;
304 /* \\\ */
306 ADD2INITLIB(GM_UNIQUENAME(libInit), 0)
307 ADD2OPENLIB(GM_UNIQUENAME(libOpen), 0)
308 ADD2EXPUNGELIB(GM_UNIQUENAME(libExpunge), 0);
311 * ***********************************************************************
312 * * Library functions *
313 * ***********************************************************************
316 static const ULONG *PsdPTArray[PGA_LAST+1];
318 /* *** Memory *** */
320 /* /// "psdAllocVec()" */
321 AROS_LH1(APTR, psdAllocVec,
322 AROS_LHA(ULONG, size, D0),
323 LIBBASETYPEPTR, ps, 5, psd)
325 AROS_LIBFUNC_INIT
326 ULONG *pmem;
327 KPRINTF(1, ("psdAllocVec(%ld)\n", size));
328 #ifndef MEMDEBUG
329 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)))))
331 #else
332 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)) + 1024)))
334 ULONG upos = size + (1*sizeof(ULONG));
335 UWORD unum = 1024;
336 UBYTE *dbptr = (UBYTE *) pmem;
337 while(unum--)
339 dbptr[upos] = upos;
340 upos++;
342 #endif
343 *pmem++ = size;
344 ps->ps_MemAllocated += size;
345 return((APTR) pmem);
347 return(NULL);
348 AROS_LIBFUNC_EXIT
350 /* \\\ */
352 /* /// "psdFreeVec()" */
353 AROS_LH1(void, psdFreeVec,
354 AROS_LHA(APTR, pmem, A1),
355 LIBBASETYPEPTR, ps, 6, psd)
357 AROS_LIBFUNC_INIT
358 ULONG size;
360 KPRINTF(1, ("psdFreeVec(%p)\n", pmem));
361 if(pmem)
363 size = ((ULONG *) pmem)[-1];
364 ps->ps_MemAllocated -= size;
366 #ifdef MEMDEBUG
367 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)) + 1024);
368 #else
369 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)));
370 #endif
372 AROS_LIBFUNC_EXIT
374 /* \\\ */
376 /* *** PBase *** */
378 /* /// "pDebugSemaInfo()" */
379 void pDebugSemaInfo(LIBBASETYPEPTR ps, struct PsdSemaInfo *psi)
381 struct PsdReadLock *prl;
382 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
383 "Semaphore %p %s (Excl/SharedLockCount %ld/%ld) (Owner: %s):",
384 psi->psi_LockSem,
385 psi->psi_LockSem->pls_Node.ln_Name,
386 psi->psi_LockSem->pls_ExclLockCount,
387 psi->psi_LockSem->pls_SharedLockCount,
388 psi->psi_LockSem->pls_Owner ? (const char *)psi->psi_LockSem->pls_Owner->tc_Node.ln_Name : "None");
390 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_WaitQueue.lh_Head;
391 while(prl->prl_Node.ln_Succ)
393 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
394 " Waiting Task: %p (%s) %s",
395 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
396 prl->prl_IsExcl ? "Excl" : "Shared");
397 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
399 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_ReadLocks.lh_Head;
400 while(prl->prl_Node.ln_Succ)
402 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
403 " Readlock Task: %p (%s), Count %ld",
404 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
405 prl->prl_Count);
406 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
409 /* \\\ */
411 /* /// "pInitSem()" */
412 void pInitSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls, STRPTR name)
414 struct PsdSemaInfo *psi = NULL;
415 NewList(&pls->pls_WaitQueue);
416 NewList(&pls->pls_ReadLocks);
417 pls->pls_Node.ln_Name = name;
418 // struct should be nulled anyway
419 pls->pls_Owner = NULL;
420 pls->pls_ExclLockCount = 0;
421 pls->pls_SharedLockCount = 0;
422 pls->pls_Dead = FALSE;
424 Forbid();
425 psi = (struct PsdSemaInfo *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdSemaInfo));
426 if(!psi)
428 Permit();
429 return;
431 psi->psi_LockSem = pls;
432 AddTail(&ps->ps_DeadlockDebug, &psi->psi_Node);
433 Permit();
435 /* \\\ */
437 /* /// "pDeleteSem()" */
438 void pDeleteSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
440 struct PsdSemaInfo *psi;
441 Forbid();
442 pls->pls_Dead = TRUE;
443 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
444 while(psi->psi_Node.ln_Succ)
446 if(psi->psi_LockSem == pls)
448 if(pls->pls_SharedLockCount + pls->pls_ExclLockCount)
450 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Semaphore still locked when attempting to delete it!\n");
451 pDebugSemaInfo(ps, psi);
452 } else {
453 Remove(&psi->psi_Node);
454 FreePooled(ps->ps_SemaMemPool, psi, sizeof(struct PsdSemaInfo));
456 break;
458 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
460 Permit();
462 /* \\\ */
464 /* /// "pLockSemExcl()" */
465 void pLockSemExcl(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
467 struct PsdReadLock waitprl;
468 struct Task *thistask = FindTask(NULL);
470 waitprl.prl_Task = thistask;
471 waitprl.prl_IsExcl = TRUE;
473 Forbid();
476 // it's already mine!!
477 if(thistask == pls->pls_Owner)
479 break;
481 if(!pls->pls_ExclLockCount)
483 // easy case: no shared locks, no exclusive locker
484 if(!pls->pls_SharedLockCount)
486 break;
488 // sole readlock promotion case
489 if((pls->pls_SharedLockCount == 1) && ((struct PsdReadLock *) pls->pls_ReadLocks.lh_Head)->prl_Task == thistask)
491 KPRINTF(1, ("Promoting read lock (%p) to write lock!\n", thistask));
492 break;
496 // okay, bad luck, we've got to wait somehow
497 AddHead(&pls->pls_WaitQueue, &waitprl.prl_Node);
498 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
500 Wait(SIGF_SINGLE);
502 Remove(&waitprl.prl_Node);
503 } while(TRUE);
504 pls->pls_Owner = thistask;
505 pls->pls_ExclLockCount++;
506 Permit();
508 /* \\\ */
510 /* /// "pLockSemShared()" */
511 void pLockSemShared(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
513 struct PsdReadLock *prl;
514 struct Task *thistask = FindTask(NULL);
516 Forbid();
517 // is this already locked exclusively by me?
518 if(thistask == pls->pls_Owner)
520 // yes? then just increase exclusive lock count
521 pls->pls_ExclLockCount++;
522 Permit();
523 return;
526 // find existing readlock
527 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
528 while(prl->prl_Node.ln_Succ)
530 if(prl->prl_Task == thistask)
532 KPRINTF(1, ("Increasing ReadLock (%p) count to %ld\n", thistask, prl->prl_Count));
533 prl->prl_Count++;
534 Permit();
535 return;
537 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
540 // this is a new readlock, generate context
541 if(!(prl = (struct PsdReadLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdReadLock))))
543 KPRINTF(20, ("No mem for shared lock! context (%p) on %p\n", thistask, pls));
544 // try exclusive lock as fallback (needs no memory)
545 Permit();
546 pLockSemExcl(ps, pls);
547 return;
550 KPRINTF(1, ("New ReadLockShared context (%p) on %p\n", thistask, pls));
551 prl->prl_Task = thistask;
552 prl->prl_Count = 0;
553 prl->prl_IsExcl = FALSE;
555 // if it's exclusively locked, wait for this lock to vanish
556 while(pls->pls_Owner)
558 AddTail(&pls->pls_WaitQueue, &prl->prl_Node);
559 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
561 Wait(SIGF_SINGLE);
563 Remove(&prl->prl_Node);
566 if(prl->prl_IsExcl)
568 // we got promoted by BorrowLocks during the process! So we don't need the shared stuff anymore
569 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
570 pls->pls_Owner = thistask;
571 pls->pls_ExclLockCount++;
572 } else {
573 // got the lock!
574 AddHead(&pls->pls_ReadLocks, &prl->prl_Node);
575 prl->prl_Count++;
576 pls->pls_SharedLockCount++;
578 Permit();
579 return;
581 /* \\\ */
583 /* /// "pUnlockSem()" */
584 void pUnlockSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
586 struct PsdReadLock *prl;
587 struct Task *thistask = FindTask(NULL);
588 BOOL gotit = FALSE;
590 Forbid();
591 if(pls->pls_Owner)
593 // exclusively locked, this means unlocking task must be owner
594 if(pls->pls_Owner != thistask)
596 Permit();
597 psdDebugSemaphores();
598 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
599 "Attempt to unlock exclusive semaphore %p not owned by task %s!",
600 pls, thistask->tc_Node.ln_Name);
601 return;
604 if(--pls->pls_ExclLockCount)
606 // still locked
607 Permit();
608 return;
610 pls->pls_Owner = NULL;
611 // otherwise drop through and notify
612 } else {
613 if(!pls->pls_SharedLockCount)
615 Permit();
616 psdDebugSemaphores();
617 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
618 "Attempt to unlock (free) semaphore %p once too often by task %s!",
619 pls, thistask->tc_Node.ln_Name);
620 return;
622 // find readlock
623 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
624 while(prl->prl_Node.ln_Succ)
626 if(prl->prl_Task == thistask)
628 if(--prl->prl_Count)
630 // can't be the last lock, so just reduce count and return
631 Permit();
632 return;
634 // remove read lock, it's no longer needed
635 KPRINTF(1, ("Removing read lock context (%p) on %p!\n", thistask, pls));
636 Remove(&prl->prl_Node);
637 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
638 gotit = TRUE;
639 // losing a designated lock
640 pls->pls_SharedLockCount--;
641 break;
643 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
645 if(!gotit)
647 Permit();
648 psdDebugSemaphores();
649 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
650 "Attempt to unlock (shared) semaphore %p once too often by task %s!",
651 pls, thistask->tc_Node.ln_Name);
652 return;
655 // we need to notify anyway, because the waiter could already have a shared lock
656 // on the same semaphore, and if we only notified on LockCount reaching zero,
657 // the locker would wait forever.
660 // notify waiting tasks
661 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
662 while(prl->prl_Node.ln_Succ)
664 Signal(prl->prl_Task, SIGF_SINGLE);
665 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
667 Permit();
669 /* \\\ */
671 /* /// "psdDebugSemaphores()" */
672 AROS_LH0(void, psdDebugSemaphores,
673 LIBBASETYPEPTR, ps, 81, psd)
675 AROS_LIBFUNC_INIT
676 struct Task *thistask = FindTask(NULL);
677 struct PsdSemaInfo *psi;
679 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
680 "Debug Semaphores (%p)", thistask);
682 Forbid();
683 // search for context
684 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
685 while(psi->psi_Node.ln_Succ)
687 pDebugSemaInfo(ps, psi);
688 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
690 Permit();
691 AROS_LIBFUNC_EXIT
693 /* \\\ */
695 /* /// "psdLockReadPBase()" */
696 AROS_LH0(void, psdLockReadPBase,
697 LIBBASETYPEPTR, ps, 8, psd)
699 AROS_LIBFUNC_INIT
700 KPRINTF(2, ("psdLockReadPBase(%p)\n", FindTask(NULL)));
701 pLockSemShared(ps, &ps->ps_Lock);
702 AROS_LIBFUNC_EXIT
704 /* \\\ */
706 /* /// "psdLockWritePBase()" */
707 AROS_LH0(void, psdLockWritePBase,
708 LIBBASETYPEPTR, ps, 7, psd)
710 AROS_LIBFUNC_INIT
711 KPRINTF(2, ("psdLockWritePBase(%p)\n", FindTask(NULL)));
712 pLockSemExcl(ps, &ps->ps_Lock);
713 AROS_LIBFUNC_EXIT
715 /* \\\ */
717 /* /// "psdUnlockPBase()" */
718 AROS_LH0(void, psdUnlockPBase,
719 LIBBASETYPEPTR, ps, 9, psd)
721 AROS_LIBFUNC_INIT
722 KPRINTF(2, ("psdUnlockPBase(%p)\n", FindTask(NULL)));
723 pUnlockSem(ps, &ps->ps_Lock);
724 AROS_LIBFUNC_EXIT
726 /* \\\ */
728 /* /// "psdBorrowLocksWait()" */
729 AROS_LH2(ULONG, psdBorrowLocksWait,
730 AROS_LHA(struct Task *, task, A1),
731 AROS_LHA(ULONG, signals, D0),
732 LIBBASETYPEPTR, ps, 97, psd)
734 AROS_LIBFUNC_INIT
735 struct Task *thistask = FindTask(NULL);
736 ULONG cnt = 0;
737 ULONG sigmask;
738 struct PsdSemaInfo *psi;
739 struct PsdLockSem *pls;
740 struct PsdReadLock *prl;
741 struct PsdBorrowLock *pbl;
742 struct List borrows;
743 struct List reclaims;
744 BOOL moveowner;
746 XPRINTF(10, ("Borrowing locks from %p (%s) to %p (%s)!\n",
747 thistask, thistask->tc_Node.ln_Name, task, task->tc_Node.ln_Name));
749 Forbid();
750 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
751 while(psi->psi_Node.ln_Succ)
753 pls = psi->psi_LockSem;
754 if(pls->pls_Owner == thistask)
756 cnt++;
758 if(pls->pls_SharedLockCount)
760 struct PsdReadLock *prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
763 if(prl->prl_Task == thistask)
765 cnt++;
766 break;
768 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
770 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
772 if(!cnt)
774 Permit();
775 XPRINTF(10, ("Nothing to borrow!\n"));
776 return(Wait(signals));
779 NewList(&borrows);
780 NewList(&reclaims);
781 XPRINTF(10, ("Borrowing %ld locks\n", cnt));
783 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
784 while(psi->psi_Node.ln_Succ)
786 moveowner = TRUE;
787 pls = psi->psi_LockSem;
788 if(pls->pls_Owner == thistask)
790 // check if the target task is already waiting for that lock
791 // in this case, we simply remove our exclusive lock and let
792 // the other task catch it
793 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
794 while(prl->prl_Node.ln_Succ)
796 if(prl->prl_Task == task)
798 if(!prl->prl_IsExcl)
800 // if we hand over the excl lock, we have to make sure that the exclusiveness is kept
801 // and no other thread may catch it while it is shared.
802 // hence we will need set this lock exclusive aswell
803 // this no optimal solution, but it guarantees the same
804 // behaviour with pending lock and no pending lock
805 prl->prl_IsExcl = TRUE;
806 XPRINTF(10, ("Promo waiting lock to excl\n"));
808 // move shared lock to top of the list
809 Remove(&prl->prl_Node);
810 AddHead(&pls->pls_WaitQueue, &prl->prl_Node);
811 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
813 pbl->pbl_LockSem = pls;
814 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
815 AddTail(&reclaims, &pbl->pbl_Node);
817 // unlock exclusive lock
818 pls->pls_ExclLockCount = 0;
819 pls->pls_Owner = NULL;
820 Signal(task, SIGF_SINGLE);
821 XPRINTF(10, ("Waiting lock %p transfer\n", pls));
823 moveowner = FALSE;
824 break;
826 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
828 if(moveowner)
830 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
832 pbl->pbl_LockSem = pls;
833 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
834 AddTail(&borrows, &pbl->pbl_Node);
835 pls->pls_Owner = task;
836 XPRINTF(10, ("Lock %p transfer\n", pls));
840 if(pls->pls_SharedLockCount)
842 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
845 if(prl->prl_Task == thistask)
847 // check if target task is waiting for this task
848 struct PsdReadLock *prl2 = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
849 while(prl2->prl_Node.ln_Succ)
851 if(prl2->prl_Task == task)
853 // move lock to top of the list
854 Remove(&prl2->prl_Node);
855 AddHead(&pls->pls_WaitQueue, &prl2->prl_Node);
856 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
858 pbl->pbl_LockSem = pls;
859 pbl->pbl_ReadLock = prl;
860 pbl->pbl_Count = prl->prl_Count;
861 AddHead(&reclaims, &pbl->pbl_Node);
863 // unlock shared lock
864 Remove(&prl->prl_Node);
865 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
866 pls->pls_SharedLockCount--;
867 Signal(task, SIGF_SINGLE);
869 moveowner = FALSE;
870 XPRINTF(10, ("Waiting shared lock %p transfer\n", pls));
871 break;
873 prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ;
875 if(moveowner)
877 // check if target task already has a shared lock on this
878 prl2 = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
881 if(prl2->prl_Task == task)
883 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
885 // we redirect to this other lock
886 pbl->pbl_LockSem = pls;
887 pbl->pbl_ReadLock = prl2;
888 pbl->pbl_Count = prl->prl_Count; // save the old lock count
889 AddTail(&borrows, &pbl->pbl_Node);
891 // unlock shared lock
892 Remove(&prl->prl_Node);
893 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
894 pls->pls_SharedLockCount--;
895 // just increase lockcount, so a split occurs automatically
896 prl2->prl_Count += pbl->pbl_Count;
898 XPRINTF(10, ("Already locked %p transfer\n", pls));
899 moveowner = FALSE;
900 break;
902 } while((prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ)->prl_Node.ln_Succ);
904 if(moveowner)
906 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
908 pbl->pbl_LockSem = pls;
909 pbl->pbl_ReadLock = prl;
910 pbl->pbl_Count = prl->prl_Count;
911 AddTail(&borrows, &pbl->pbl_Node);
912 prl->prl_Task = task;
913 XPRINTF(10, ("Std lock %p transfer\n", pls));
916 break;
918 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
920 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
923 sigmask = Wait(signals);
925 // try to get moved locks back first
926 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
927 while(pbl->pbl_Node.ln_Succ)
929 Remove(&pbl->pbl_Node);
930 pls = pbl->pbl_LockSem;
931 if(pbl->pbl_ExclLockCount)
933 if(pbl->pbl_ExclLockCount == pls->pls_ExclLockCount)
935 // all fine, other task didn't use the locks or returned them already
936 pls->pls_Owner = thistask;
937 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
938 } else {
939 // okay, bad thing, release lock and try to obtain it again -- eventually the other task should free the lock again
940 pls->pls_ExclLockCount -= pbl->pbl_ExclLockCount;
941 AddTail(&reclaims, &pbl->pbl_Node);
943 } else {
944 if(pls->pls_Owner == task)
946 // oh, damn. The other task converted our shared lock into an exclusive lock --
947 // we cannot claim this back right now. This gets tricky now.
948 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
950 // luckily, the count didn't change, so we just release the shared lock and requeue us into the reclaim list
951 Remove(&pbl->pbl_ReadLock->prl_Node);
952 FreePooled(ps->ps_SemaMemPool, pbl->pbl_ReadLock, sizeof(struct PsdReadLock));
953 pbl->pbl_ReadLock = NULL;
954 pls->pls_SharedLockCount--; // should turn to 0
955 } else {
956 // can it get worse? obviously, the alien task also has added some read locks
957 // this means we need to split up!
958 // therefore we leave a few lock counts and requeue
959 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
960 pbl->pbl_ReadLock = NULL;
962 AddHead(&reclaims, &pbl->pbl_Node);
963 } else {
964 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
966 // the count didn't change, just so just change owner
967 pbl->pbl_ReadLock->prl_Task = thistask;
968 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
969 } else {
970 // the alien task still has some read locks
971 // this means we need to split up!
972 // therefore we leave a few lock counts and requeue
973 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
974 pbl->pbl_ReadLock = NULL;
975 AddHead(&reclaims, &pbl->pbl_Node);
979 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
982 // try to reclaim released locks
983 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
984 while(pbl->pbl_Node.ln_Succ)
986 Remove(&pbl->pbl_Node);
987 pls = pbl->pbl_LockSem;
988 while(pbl->pbl_Count)
990 pLockSemShared(ps, pls);
991 --pbl->pbl_Count;
993 while(pbl->pbl_ExclLockCount)
995 pLockSemExcl(ps, pls);
996 --pbl->pbl_ExclLockCount;
998 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
999 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
1001 Permit();
1003 return(sigmask);
1004 AROS_LIBFUNC_EXIT
1006 /* \\\ */
1008 /* *** Support *** */
1010 /* /// "psdCopyStr()" */
1011 AROS_LH1(STRPTR, psdCopyStr,
1012 AROS_LHA(CONST_STRPTR, name, A0),
1013 LIBBASETYPEPTR, ps, 10, psd)
1015 AROS_LIBFUNC_INIT
1016 STRPTR rs = psdAllocVec((ULONG) strlen(name)+1);
1017 KPRINTF(1, ("psdCopyStr(%s)\n", name));
1018 if(rs)
1020 strcpy(rs, name);
1022 return(rs);
1023 AROS_LIBFUNC_EXIT
1025 /* \\\ */
1027 /* /// "psdSafeRawDoFmtA()" */
1028 AROS_LH4(void, psdSafeRawDoFmtA,
1029 AROS_LHA(STRPTR, buf, A0),
1030 AROS_LHA(ULONG, len, D0),
1031 AROS_LHA(CONST_STRPTR, fmtstr, A1),
1032 AROS_LHA(RAWARG, fmtdata, A2),
1033 LIBBASETYPEPTR, ps, 42, psd)
1035 AROS_LIBFUNC_INIT
1036 struct PsdRawDoFmt rdf;
1038 if(len > 0)
1040 rdf.rdf_Len = len;
1041 rdf.rdf_Buf = buf;
1042 RawDoFmt(fmtstr, fmtdata, (void (*)()) pPutChar, &rdf);
1043 buf[len-1] = 0;
1045 AROS_LIBFUNC_EXIT
1047 /* \\\ */
1049 /* /// "pPutChar()" */
1050 AROS_UFH2(void, pPutChar,
1051 AROS_UFHA(char, ch, D0),
1052 AROS_UFHA(struct PsdRawDoFmt *, rdf, A3))
1054 AROS_USERFUNC_INIT
1055 if(rdf->rdf_Len)
1057 rdf->rdf_Len--;
1058 *rdf->rdf_Buf++ = ch;
1060 AROS_USERFUNC_EXIT
1062 /* \\\ */
1064 /* /// "psdCopyStrFmtA()" */
1065 AROS_LH2(STRPTR, psdCopyStrFmtA,
1066 AROS_LHA(CONST_STRPTR, fmtstr, A0),
1067 AROS_LHA(RAWARG, fmtdata, A1),
1068 LIBBASETYPEPTR, ps, 68, psd)
1070 AROS_LIBFUNC_INIT
1071 ULONG len = 0;
1072 STRPTR buf;
1074 RawDoFmt(fmtstr, fmtdata, (void (*)()) pRawFmtLength, &len);
1075 buf = psdAllocVec(len+1);
1076 if(buf)
1078 psdSafeRawDoFmtA(buf, len+1, fmtstr, fmtdata);
1080 return(buf);
1081 AROS_LIBFUNC_EXIT
1083 /* \\\ */
1085 /* /// "pRawFmtLength()" */
1086 AROS_UFH2(void, pRawFmtLength,
1087 AROS_UFHA(char, ch, D0),
1088 AROS_UFHA(ULONG *, len, A3))
1090 AROS_USERFUNC_INIT
1091 (*len)++;
1092 AROS_USERFUNC_EXIT
1094 /* \\\ */
1096 /* /// "psdDelayMS()" */
1097 AROS_LH1(void, psdDelayMS,
1098 AROS_LHA(ULONG, milli, D0),
1099 LIBBASETYPEPTR, ps, 11, psd)
1101 AROS_LIBFUNC_INIT
1102 struct MsgPort mp;
1103 struct timerequest tr;
1105 KPRINTF(1, ("psdDelayMS(%ld)\n", milli));
1106 mp.mp_Flags = PA_SIGNAL;
1107 mp.mp_SigBit = SIGB_SINGLE;
1108 mp.mp_SigTask = FindTask(NULL);
1109 NewList(&mp.mp_MsgList);
1110 CopyMem(&ps->ps_TimerIOReq, &tr, sizeof(tr));
1111 tr.tr_node.io_Message.mn_ReplyPort = &mp;
1112 tr.tr_time.tv_secs = 0;
1113 tr.tr_time.tv_micro = milli * 1000;
1114 DoIO((struct IORequest *) &tr);
1115 AROS_LIBFUNC_EXIT
1117 /* \\\ */
1119 /* /// "psdGetAttrsA()" */
1120 AROS_LH3(LONG, psdGetAttrsA,
1121 AROS_LHA(ULONG, type, D0),
1122 AROS_LHA(APTR, psdstruct, A0),
1123 AROS_LHA(struct TagItem *, tags, A1),
1124 LIBBASETYPEPTR, ps, 22, psd)
1126 AROS_LIBFUNC_INIT
1127 struct TagItem *ti;
1128 ULONG count = 0;
1129 ULONG *packtab = NULL;
1131 KPRINTF(1, ("psdGetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1133 if(type <= PGA_LAST)
1135 packtab = (ULONG *) PsdPTArray[type];
1138 switch(type)
1140 case PGA_STACK:
1141 psdstruct = ps;
1142 if((ti = FindTagItem(PA_HardwareList, tags)))
1144 *((struct List **) ti->ti_Data) = &ps->ps_Hardware;
1145 count++;
1147 if((ti = FindTagItem(PA_ClassList, tags)))
1149 *((struct List **) ti->ti_Data) = &ps->ps_Classes;
1150 count++;
1152 if((ti = FindTagItem(PA_ErrorMsgList, tags)))
1154 *((struct List **) ti->ti_Data) = &ps->ps_ErrorMsgs;
1155 count++;
1157 break;
1159 case PGA_HARDWARE:
1160 if((ti = FindTagItem(HA_DeviceList, tags)))
1162 *((struct List **) ti->ti_Data) = &(((struct PsdHardware *) psdstruct)->phw_Devices);
1163 count++;
1165 break;
1167 case PGA_DEVICE:
1168 if((ti = FindTagItem(DA_ConfigList, tags)))
1170 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Configs);
1171 count++;
1173 if((ti = FindTagItem(DA_DescriptorList, tags)))
1175 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Descriptors);
1176 count++;
1178 break;
1180 case PGA_CONFIG:
1181 if((ti = FindTagItem(CA_InterfaceList, tags)))
1183 *((struct List **) ti->ti_Data) = &(((struct PsdConfig *) psdstruct)->pc_Interfaces);
1184 count++;
1186 break;
1188 case PGA_INTERFACE:
1189 if((ti = FindTagItem(IFA_EndpointList, tags)))
1191 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_EPs);
1192 count++;
1194 if((ti = FindTagItem(IFA_AlternateIfList, tags)))
1196 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_AlterIfs);
1197 count++;
1199 break;
1201 case PGA_ERRORMSG:
1202 if((ti = FindTagItem(EMA_DateStamp, tags)))
1204 *((struct DateStamp **) ti->ti_Data) = &(((struct PsdErrorMsg *) psdstruct)->pem_DateStamp);
1205 count++;
1207 break;
1209 case PGA_PIPE:
1210 if((ti = FindTagItem(PPA_IORequest, tags)))
1212 *((struct IOUsbHWReq **) ti->ti_Data) = &(((struct PsdPipe *) psdstruct)->pp_IOReq);
1213 count++;
1215 break;
1217 case PGA_STACKCFG:
1218 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1220 count++;
1221 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_InsertSndFile;
1223 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1225 count++;
1226 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_RemoveSndFile;
1228 break;
1230 if(packtab)
1232 return((LONG) (UnpackStructureTags(psdstruct, (ULONG *) packtab, tags)+count));
1233 } else {
1234 return(-1);
1236 AROS_LIBFUNC_EXIT
1238 /* \\\ */
1240 /* /// "psdSetAttrsA()" */
1241 AROS_LH3(LONG, psdSetAttrsA,
1242 AROS_LHA(ULONG, type, D0),
1243 AROS_LHA(APTR, psdstruct, A0),
1244 AROS_LHA(struct TagItem *, tags, A1),
1245 LIBBASETYPEPTR, ps, 23, psd)
1247 AROS_LIBFUNC_INIT
1248 struct TagItem *ti;
1249 ULONG count = 0;
1250 ULONG *packtab = NULL;
1251 BOOL savepopocfg = FALSE;
1252 BOOL checkcfgupdate = FALSE;
1253 BOOL powercalc = FALSE;
1254 LONG res;
1256 KPRINTF(1, ("psdSetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1258 if(type <= PGA_LAST)
1260 packtab = (ULONG *) PsdPTArray[type];
1263 switch(type)
1265 case PGA_DEVICE:
1266 if(FindTagItem(DA_InhibitPopup, tags) || FindTagItem(DA_InhibitClassBind, tags))
1268 savepopocfg = TRUE;
1270 if(FindTagItem(DA_OverridePowerInfo, tags))
1272 savepopocfg = TRUE;
1273 powercalc = TRUE;
1275 break;
1277 case PGA_STACK:
1278 psdstruct = ps;
1279 break;
1281 case PGA_STACKCFG:
1282 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1284 count++;
1285 if(strcmp(ps->ps_PoPo.po_InsertSndFile, (STRPTR) ti->ti_Data))
1287 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
1288 ps->ps_PoPo.po_InsertSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1291 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1293 count++;
1294 if(strcmp(ps->ps_PoPo.po_RemoveSndFile, (STRPTR) ti->ti_Data))
1296 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
1297 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1300 checkcfgupdate = TRUE;
1301 break;
1303 case PGA_PIPESTREAM:
1305 struct PsdPipeStream *pps = (struct PsdPipeStream *) psdstruct;
1306 struct PsdPipe *pp;
1307 ULONG oldbufsize = pps->pps_BufferSize;
1308 ULONG oldnumpipes = pps->pps_NumPipes;
1309 ULONG cnt;
1311 KPRINTF(1, ("SetAttrs PIPESTREAM\n"));
1312 ObtainSemaphore(&pps->pps_AccessLock);
1313 if((ti = FindTagItem(PSA_MessagePort, tags)))
1315 count++;
1316 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
1318 KPRINTF(1, ("Deleting old MsgPort\n"));
1319 DeleteMsgPort(pps->pps_MsgPort);
1320 pps->pps_MsgPort = NULL;
1322 pps->pps_Flags &= ~PSFF_OWNMSGPORT;
1324 count += PackStructureTags(psdstruct, packtab, tags);
1325 KPRINTF(1, ("Pipes = %ld (old: %ld), BufferSize = %ld (old: %ld)\n",
1326 pps->pps_NumPipes, oldnumpipes, pps->pps_BufferSize, oldbufsize));
1327 if(pps->pps_NumPipes < 1)
1329 pps->pps_NumPipes = 1; /* minimal */
1331 if(pps->pps_BufferSize < pps->pps_Endpoint->pep_MaxPktSize)
1333 pps->pps_BufferSize = pps->pps_Endpoint->pep_MaxPktSize; /* minimal */
1335 if(!pps->pps_MsgPort)
1337 if((pps->pps_MsgPort = CreateMsgPort()))
1339 KPRINTF(1, ("Creating MsgPort\n"));
1340 pps->pps_Flags |= PSFF_OWNMSGPORT;
1343 /* do we need to reallocate? */
1344 if((oldbufsize != pps->pps_BufferSize) ||
1345 (oldnumpipes != pps->pps_NumPipes) ||
1346 (!pps->pps_Pipes) ||
1347 (!pps->pps_Buffer))
1349 if(pps->pps_Pipes)
1351 KPRINTF(1, ("freeing %ld old pipes\n", oldnumpipes));
1352 for(cnt = 0; cnt < oldnumpipes; cnt++)
1354 pp = pps->pps_Pipes[cnt];
1355 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1357 KPRINTF(1, ("Abort %ld\n", cnt));
1358 psdAbortPipe(pp);
1359 KPRINTF(1, ("Wait %ld\n", cnt));
1360 psdWaitPipe(pp);
1362 KPRINTF(1, ("Free %ld\n", cnt));
1363 psdFreePipe(pp);
1365 psdFreeVec(pps->pps_Pipes);
1367 psdFreeVec(pps->pps_Buffer);
1368 /* reset stuff */
1369 NewList(&pps->pps_FreePipes);
1370 NewList(&pps->pps_ReadyPipes);
1371 pps->pps_Offset = 0;
1372 pps->pps_BytesPending = 0;
1373 pps->pps_ReqBytes = 0;
1374 pps->pps_ActivePipe = NULL;
1375 pps->pps_Buffer = psdAllocVec(pps->pps_NumPipes * pps->pps_BufferSize);
1376 pps->pps_Pipes = psdAllocVec(pps->pps_NumPipes * sizeof(struct PsdPipe *));
1377 if(pps->pps_Pipes && pps->pps_Buffer)
1379 KPRINTF(1, ("allocating %ld new pipes\n", pps->pps_NumPipes));
1380 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
1382 pp = psdAllocPipe(pps->pps_Device, pps->pps_MsgPort, pps->pps_Endpoint);
1383 if((pps->pps_Pipes[cnt] = pp))
1385 pp->pp_Num = cnt;
1386 if(pps->pps_Flags & PSFF_NOSHORTPKT) pp->pp_IOReq.iouh_Flags |= UHFF_NOSHORTPKT;
1387 if(pps->pps_Flags & PSFF_NAKTIMEOUT) pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
1388 if(pps->pps_Flags & PSFF_ALLOWRUNT) pp->pp_IOReq.iouh_Flags |= UHFF_ALLOWRUNTPKTS;
1389 pp->pp_IOReq.iouh_NakTimeout = pps->pps_NakTimeoutTime;
1390 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
1391 } else {
1392 KPRINTF(1, ("Allocating Pipe %ld failed!\n", cnt));
1395 } else {
1396 KPRINTF(1, ("Allocating Pipe array failed!\n"));
1397 psdFreeVec(pps->pps_Buffer);
1398 pps->pps_Buffer = NULL;
1399 psdFreeVec(pps->pps_Pipes);
1400 pps->pps_Pipes = NULL;
1403 ReleaseSemaphore(&pps->pps_AccessLock);
1404 return((LONG) count);
1408 if(packtab)
1410 res = (LONG) PackStructureTags(psdstruct, packtab, tags);
1411 } else {
1412 res = -1;
1414 if(savepopocfg)
1416 struct PsdDevice *pd = (struct PsdDevice *) psdstruct;
1417 struct PsdIFFContext *pic;
1419 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1420 if(!pic)
1422 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
1423 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1425 if(pic)
1427 pAddCfgChunk(ps, pic, &pd->pd_PoPoCfg);
1428 checkcfgupdate = TRUE;
1431 if(checkcfgupdate)
1433 pUpdateGlobalCfg(ps, (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head);
1434 pCheckCfgChanged(ps);
1436 if(powercalc)
1438 psdCalculatePower(((struct PsdDevice *) psdstruct)->pd_Hardware);
1440 return(res);
1441 AROS_LIBFUNC_EXIT
1443 /* \\\ */
1445 /* /// "psdSpawnSubTask()" */
1446 AROS_LH3(struct Task *, psdSpawnSubTask,
1447 AROS_LHA(STRPTR, name, A0),
1448 AROS_LHA(APTR, initpc, A1),
1449 AROS_LHA(APTR, userdata, A2),
1450 LIBBASETYPEPTR, ps, 39, psd)
1452 AROS_LIBFUNC_INIT
1453 #define SUBTASKSTACKSIZE 8192
1454 struct
1456 struct MemList mrm_ml;
1457 struct MemEntry mtm_me[2];
1458 } memlist;
1460 struct MemList *newmemlist;
1461 struct MemEntry *me;
1462 struct Task *nt;
1463 struct Process *subtask;
1465 if(!(name && initpc))
1467 return(NULL);
1470 /* If there's dos available, create a process instead of a task */
1471 if(pOpenDOS(ps))
1473 subtask = CreateNewProcTags(NP_Entry, initpc,
1474 NP_StackSize, SUBTASKSTACKSIZE,
1475 NP_Priority, ps->ps_GlobalCfg->pgc_SubTaskPri,
1476 NP_Name, name,
1477 NP_CopyVars, FALSE,
1478 NP_UserData, userdata,
1479 TAG_END);
1480 return((struct Task *) subtask);
1483 /* Allocate memory of memlist */
1485 memlist.mrm_ml.ml_Node.ln_Type = NT_MEMORY;
1486 memlist.mrm_ml.ml_Node.ln_Pri = 0;
1487 memlist.mrm_ml.ml_Node.ln_Name = NULL;
1488 memlist.mrm_ml.ml_NumEntries = 3;
1489 me = &memlist.mrm_ml.ml_ME[0];
1490 me[1].me_Un.meu_Reqs = memlist.mrm_ml.ml_ME[0].me_Un.meu_Reqs = MEMF_CLEAR|MEMF_PUBLIC;
1491 me[0].me_Length = sizeof(struct Task);
1492 me[1].me_Length = SUBTASKSTACKSIZE;
1493 me[2].me_Un.meu_Reqs = MEMF_PUBLIC;
1494 me[2].me_Length = strlen(name) + 1;
1496 #ifdef __AROS__
1497 newmemlist = NewAllocEntry(&memlist.mrm_ml, NULL);
1498 if (!newmemlist)
1499 #else
1500 newmemlist = AllocEntry(&memlist.mrm_ml);
1501 if((IPTR) newmemlist & 0x80000000)
1502 #endif
1504 return(NULL);
1506 me = &newmemlist->ml_ME[0];
1507 nt = me[0].me_Un.meu_Addr;
1508 nt->tc_Node.ln_Name = me[2].me_Un.meu_Addr;
1509 strcpy(nt->tc_Node.ln_Name, name);
1510 nt->tc_Node.ln_Type = NT_TASK;
1511 nt->tc_Node.ln_Pri = ps->ps_GlobalCfg->pgc_SubTaskPri;
1512 nt->tc_SPLower = me[1].me_Un.meu_Addr;
1513 nt->tc_SPUpper = nt->tc_SPReg = (APTR) ((IPTR) nt->tc_SPLower + SUBTASKSTACKSIZE);
1514 nt->tc_UserData = userdata;
1515 NewList(&nt->tc_MemEntry);
1516 AddTail(&nt->tc_MemEntry, (struct Node *) newmemlist);
1517 KPRINTF(1, ("TDNestCnt=%ld\n", SysBase->TDNestCnt));
1518 if((nt = AddTask(nt, initpc, NULL)))
1520 XPRINTF(10, ("Started task %p (%s)\n", nt, name));
1521 return(nt);
1523 FreeEntry(newmemlist);
1524 return(NULL);
1525 AROS_LIBFUNC_EXIT
1527 /* \\\ */
1529 /* /// "psdNumToStr()" */
1530 AROS_LH3(STRPTR, psdNumToStr,
1531 AROS_LHA(UWORD, type, D0),
1532 AROS_LHA(LONG, idx, D1),
1533 AROS_LHA(STRPTR, defstr, A0),
1534 LIBBASETYPEPTR, ps, 38, psd)
1536 AROS_LIBFUNC_INIT
1537 switch(type)
1539 case NTS_IOERR:
1541 const struct PsdWStringMap *psm = usbhwioerrstr;
1542 while(psm->psm_ID)
1544 if(psm->psm_ID == idx)
1546 return(psm->psm_String);
1548 psm++;
1550 break;
1553 case NTS_LANGID:
1555 const struct PsdUWStringMap *psm = usblangids;
1556 while(psm->psm_ID)
1558 if(psm->psm_ID == idx)
1560 return(psm->psm_String);
1562 psm++;
1564 break;
1567 case NTS_TRANSTYPE:
1568 switch(idx)
1570 case USEAF_CONTROL:
1571 return("control");
1572 case USEAF_ISOCHRONOUS:
1573 return("isochronous");
1574 case USEAF_BULK:
1575 return("bulk");
1576 case USEAF_INTERRUPT:
1577 return("interrupt");
1579 break;
1581 case NTS_SYNCTYPE:
1582 switch(idx)
1584 case USEAF_NOSYNC:
1585 return("no synchronization");
1586 case USEAF_ASYNC:
1587 return("asynchronous");
1588 case USEAF_ADAPTIVE:
1589 return("adaptive");
1590 case USEAF_SYNC:
1591 return("synchronous");
1593 break;
1595 case NTS_USAGETYPE:
1596 switch(idx)
1598 case USEAF_DATA:
1599 return("data");
1600 case USEAF_FEEDBACK:
1601 return("feedback");
1602 case USEAF_IMPLFEEDBACK:
1603 return("implicit feedback data");
1605 break;
1607 case NTS_VENDORID:
1609 const struct PsdUWStringMap *psm = usbvendorids;
1610 while(psm->psm_ID)
1612 if(psm->psm_ID == idx)
1614 return(psm->psm_String);
1616 psm++;
1618 break;
1621 case NTS_CLASSCODE:
1623 const struct PsdWStringMap *psm = usbclasscodestr;
1624 while(psm->psm_ID)
1626 if(psm->psm_ID == idx)
1628 return(psm->psm_String);
1630 psm++;
1632 break;
1635 case NTS_DESCRIPTOR:
1637 const struct PsdULStringMap *psm = usbdesctypestr;
1638 while(psm->psm_ID)
1640 if(psm->psm_ID == idx)
1642 return(psm->psm_String);
1644 psm++;
1646 break;
1649 case NTS_COMBOCLASS:
1651 const struct PsdULStringMap *psm = usbcomboclasscodestr;
1652 if(idx & (NTSCCF_CLASS|NTSCCF_SUBCLASS|NTSCCF_PROTO))
1654 while(psm->psm_ID)
1656 BOOL take;
1657 take = TRUE;
1658 if(psm->psm_ID & NTSCCF_CLASS)
1660 if((!(idx & NTSCCF_CLASS)) || ((idx & 0x0000ff) != (psm->psm_ID & 0x0000ff)))
1662 take = FALSE;
1665 if(psm->psm_ID & NTSCCF_SUBCLASS)
1667 if((!(idx & NTSCCF_SUBCLASS)) || ((idx & 0x00ff00) != (psm->psm_ID & 0x00ff00)))
1669 take = FALSE;
1672 if(psm->psm_ID & NTSCCF_PROTO)
1674 if((!(idx & NTSCCF_PROTO)) || ((idx & 0xff0000) != (psm->psm_ID & 0xff0000)))
1676 take = FALSE;
1679 if(take)
1681 return(psm->psm_String);
1683 psm++;
1686 break;
1689 return(defstr);
1690 AROS_LIBFUNC_EXIT
1692 /* \\\ */
1694 /* *** Endpoint *** */
1696 /* /// "pFreeEndpoint()" */
1697 void pFreeEndpoint(struct PsdEndpoint *pep)
1699 LIBBASETYPEPTR ps = pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Base;
1700 KPRINTF(2, (" FreeEndpoint()\n"));
1701 Remove(&pep->pep_Node);
1702 psdFreeVec(pep);
1704 /* \\\ */
1706 /* /// "pAllocEndpoint()" */
1707 struct PsdEndpoint * pAllocEndpoint(struct PsdInterface *pif)
1709 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1710 struct PsdEndpoint *pep;
1711 if((pep = psdAllocVec(sizeof(struct PsdEndpoint))))
1713 pep->pep_Interface = pif;
1714 AddTail(&pif->pif_EPs, &pep->pep_Node);
1715 return(pep);
1717 return(NULL);
1719 /* \\\ */
1721 /* /// "psdFindEndpointA()" */
1722 AROS_LH3(struct PsdEndpoint *, psdFindEndpointA,
1723 AROS_LHA(struct PsdInterface *, pif, A0),
1724 AROS_LHA(struct PsdEndpoint *, pep, A2),
1725 AROS_LHA(struct TagItem *, tags, A1),
1726 LIBBASETYPEPTR, ps, 67, psd)
1728 AROS_LIBFUNC_INIT
1729 struct TagItem *ti;
1730 BOOL takeit;
1732 KPRINTF(2, ("psdFindEndpointA(%p, %p, %p)\n", pif, pep, tags));
1733 if(!pep)
1735 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1736 } else {
1737 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1739 while(pep->pep_Node.ln_Succ)
1741 takeit = TRUE;
1742 if((ti = FindTagItem(EA_IsIn, tags)))
1744 if((ti->ti_Data && !pep->pep_Direction) || (!ti->ti_Data && pep->pep_Direction))
1746 takeit = FALSE;
1749 if((ti = FindTagItem(EA_EndpointNum, tags)))
1751 if(ti->ti_Data != pep->pep_EPNum)
1753 takeit = FALSE;
1756 if((ti = FindTagItem(EA_TransferType, tags)))
1758 if(ti->ti_Data != pep->pep_TransType)
1760 takeit = FALSE;
1763 if((ti = FindTagItem(EA_MaxPktSize, tags)))
1765 if(ti->ti_Data != pep->pep_MaxPktSize)
1767 takeit = FALSE;
1770 if((ti = FindTagItem(EA_Interval, tags)))
1772 if(ti->ti_Data != pep->pep_Interval)
1774 takeit = FALSE;
1778 if(takeit)
1780 return(pep);
1782 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1784 return(NULL);
1785 AROS_LIBFUNC_EXIT
1787 /* \\\ */
1789 /* *** Interface *** */
1791 /* /// "pFreeInterface()" */
1792 void pFreeInterface(struct PsdInterface *pif)
1794 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1795 struct PsdEndpoint *pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1796 struct PsdInterface *altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1797 KPRINTF(2, (" FreeInterface()\n"));
1798 /* Remove alternate interfaces */
1799 while(altif->pif_Node.ln_Succ)
1801 pFreeInterface(altif);
1802 altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1804 /* Remove endpoints */
1805 while(pep->pep_Node.ln_Succ)
1807 pFreeEndpoint(pep);
1808 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1810 psdFreeVec(pif->pif_IfStr);
1811 psdFreeVec(pif->pif_IDString);
1812 Remove(&pif->pif_Node);
1813 psdFreeVec(pif);
1815 /* \\\ */
1817 /* /// "pAllocInterface()" */
1818 struct PsdInterface * pAllocInterface(struct PsdConfig *pc)
1820 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
1821 struct PsdInterface *pif;
1822 if((pif = psdAllocVec(sizeof(struct PsdInterface))))
1824 pif->pif_Config = pc;
1825 NewList(&pif->pif_EPs);
1826 NewList(&pif->pif_AlterIfs);
1827 AddTail(&pc->pc_Interfaces, &pif->pif_Node);
1828 return(pif);
1830 return(NULL);
1832 /* \\\ */
1834 /* /// "psdFindInterfaceA()" */
1835 AROS_LH3(struct PsdInterface *, psdFindInterfaceA,
1836 AROS_LHA(struct PsdDevice *, pd, A0),
1837 AROS_LHA(struct PsdInterface *, pif, A2),
1838 AROS_LHA(struct TagItem *, tags, A1),
1839 LIBBASETYPEPTR, ps, 66, psd)
1841 AROS_LIBFUNC_INIT
1842 struct PsdConfig *pc;
1843 struct TagItem *ti;
1844 BOOL takeit;
1845 BOOL searchalt = FALSE;
1846 BOOL isalt = FALSE;
1847 struct PsdInterface *oldpif = NULL;
1849 KPRINTF(2, ("psdFindInterfaceA(%p, %p, %p)\n", pd, pif, tags));
1850 if(!pif)
1852 pc = pd->pd_CurrentConfig;
1853 if(pc)
1855 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
1857 if(!pif)
1859 return(NULL);
1861 } else {
1862 if(FindTagItem(IFA_AlternateNum, tags))
1864 searchalt = TRUE;
1866 if(pif->pif_ParentIf)
1868 // special case: we are in an alternate interface right now
1869 searchalt = TRUE;
1870 if(pif->pif_Node.ln_Succ)
1872 isalt = TRUE;
1873 oldpif = pif->pif_ParentIf;
1874 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1875 } else {
1876 pif = (struct PsdInterface *) pif->pif_ParentIf->pif_Node.ln_Succ;
1878 } else {
1879 // go into alt interfaces
1880 if(searchalt && pif->pif_AlterIfs.lh_Head->ln_Succ)
1882 isalt = TRUE;
1883 oldpif = pif;
1884 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1885 } else {
1886 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1891 while(pif->pif_Node.ln_Succ)
1893 takeit = TRUE;
1894 if((ti = FindTagItem(IFA_InterfaceNum, tags)))
1896 if(ti->ti_Data != pif->pif_IfNum)
1898 takeit = FALSE;
1901 if((ti = FindTagItem(IFA_AlternateNum, tags)))
1903 searchalt = TRUE;
1904 if(ti->ti_Data <= 0xff) // if alternate number is greater than 0xff, don't check compliance, but just enable alternate interface searching
1906 if(ti->ti_Data != pif->pif_Alternate)
1908 takeit = FALSE;
1912 if((ti = FindTagItem(IFA_NumEndpoints, tags)))
1914 if(ti->ti_Data != pif->pif_NumEPs)
1916 takeit = FALSE;
1919 if((ti = FindTagItem(IFA_Class, tags)))
1921 if(ti->ti_Data != pif->pif_IfClass)
1923 takeit = FALSE;
1926 if((ti = FindTagItem(IFA_SubClass, tags)))
1928 if(ti->ti_Data != pif->pif_IfSubClass)
1930 takeit = FALSE;
1933 if((ti = FindTagItem(IFA_Protocol, tags)))
1935 if(ti->ti_Data != pif->pif_IfProto)
1937 takeit = FALSE;
1940 if((ti = FindTagItem(IFA_Binding, tags)))
1942 if((APTR) ti->ti_Data != pif->pif_IfBinding)
1944 takeit = FALSE;
1947 if((ti = FindTagItem(IFA_InterfaceName, tags)))
1949 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IfStr))
1951 takeit = FALSE;
1954 if((ti = FindTagItem(IFA_IDString, tags)))
1956 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IDString))
1958 takeit = FALSE;
1962 if(takeit)
1964 return(pif);
1966 if(searchalt)
1968 if(isalt)
1970 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1971 if(!pif->pif_Node.ln_Succ)
1973 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1974 isalt = FALSE;
1976 } else {
1977 oldpif = pif;
1978 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1979 if(!pif->pif_Node.ln_Succ)
1981 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1982 } else {
1983 isalt = TRUE;
1986 } else {
1987 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1990 return(NULL);
1991 AROS_LIBFUNC_EXIT
1993 /* \\\ */
1995 /* *** Config *** */
1997 /* /// "pFreeConfig()" */
1998 void pFreeConfig(struct PsdConfig *pc)
2000 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
2001 struct PsdInterface *pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2002 KPRINTF(2, (" FreeConfig()\n"));
2003 while(pif->pif_Node.ln_Succ)
2005 psdReleaseIfBinding(pif);
2006 pFreeInterface(pif);
2007 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2009 psdFreeVec(pc->pc_CfgStr);
2010 Remove(&pc->pc_Node);
2011 psdFreeVec(pc);
2013 /* \\\ */
2015 /* /// "pAllocConfig()" */
2016 struct PsdConfig * pAllocConfig(struct PsdDevice *pd)
2018 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2019 struct PsdConfig *pc;
2020 KPRINTF(2, (" AllocConfig()\n"));
2021 if((pc = psdAllocVec(sizeof(struct PsdConfig))))
2023 pc->pc_Device = pd;
2024 NewList(&pc->pc_Interfaces);
2025 AddTail(&pd->pd_Configs, &pc->pc_Node);
2026 return(pc);
2028 return(NULL);
2030 /* \\\ */
2032 /* *** Descriptors *** */
2034 /* /// "pFreeDescriptor()" */
2035 void pFreeDescriptor(struct PsdDescriptor *pdd)
2037 LIBBASETYPEPTR ps = pdd->pdd_Device->pd_Hardware->phw_Base;
2038 KPRINTF(2, (" FreeDescriptor()\n"));
2039 //psdFreeVec(pdd->pdd_Data); // part of the structure alloc
2040 Remove(&pdd->pdd_Node);
2041 psdFreeVec(pdd);
2043 /* \\\ */
2045 /* /// "pAllocDescriptor()" */
2046 struct PsdDescriptor * pAllocDescriptor(struct PsdDevice *pd, UBYTE *buf)
2048 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2049 struct PsdDescriptor *pdd;
2051 KPRINTF(2, (" AllocDescriptor()\n"));
2052 if((pdd = psdAllocVec(sizeof(struct PsdDescriptor) + (ULONG) buf[0])))
2054 pdd->pdd_Device = pd;
2055 pdd->pdd_Data = ((UBYTE *) pdd) + sizeof(struct PsdDescriptor);
2056 pdd->pdd_Length = buf[0];
2057 pdd->pdd_Type = buf[1];
2058 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
2060 pdd->pdd_CSSubType = buf[2];
2062 pdd->pdd_Name = psdNumToStr(NTS_DESCRIPTOR, (LONG) pdd->pdd_Type, "<unknown>");
2063 CopyMem(buf, pdd->pdd_Data, (ULONG) buf[0]);
2064 AddTail(&pd->pd_Descriptors, &pdd->pdd_Node);
2065 return(pdd);
2067 return(NULL);
2069 /* \\\ */
2071 /* /// "psdFindDescriptorA()" */
2072 AROS_LH3(struct PsdDescriptor *, psdFindDescriptorA,
2073 AROS_LHA(struct PsdDevice *, pd, A0),
2074 AROS_LHA(struct PsdDescriptor *, pdd, A2),
2075 AROS_LHA(struct TagItem *, tags, A1),
2076 LIBBASETYPEPTR, ps, 91, psd)
2078 AROS_LIBFUNC_INIT
2079 struct PsdConfig *pc = pd->pd_CurrentConfig;
2080 struct TagItem *ti;
2081 BOOL takeit;
2083 KPRINTF(2, ("psdFindDescriptorA(%p, %p, %p)\n", pd, pdd, tags));
2084 if(!pdd)
2086 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2087 } else {
2088 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2091 while(pdd->pdd_Node.ln_Succ)
2093 takeit = TRUE;
2095 if((ti = FindTagItem(DDA_Config, tags)))
2097 // special case to workaround default: with NULL given, all configs are matched
2098 if(ti->ti_Data && (((struct PsdConfig *) ti->ti_Data) != pdd->pdd_Config))
2100 takeit = FALSE;
2102 } else {
2103 // only take descriptors from the current configuration by default
2104 if(pc != pdd->pdd_Config)
2106 takeit = FALSE;
2109 if((ti = FindTagItem(DDA_Interface, tags)))
2111 if(((struct PsdInterface *) ti->ti_Data) != pdd->pdd_Interface)
2113 takeit = FALSE;
2116 if((ti = FindTagItem(DDA_Endpoint, tags)))
2118 if(((struct PsdEndpoint *) ti->ti_Data) != pdd->pdd_Endpoint)
2120 takeit = FALSE;
2123 if((ti = FindTagItem(DDA_DescriptorType, tags)))
2125 if(ti->ti_Data != pdd->pdd_Type)
2127 takeit = FALSE;
2130 if((ti = FindTagItem(DDA_CS_SubType, tags)))
2132 if(ti->ti_Data != pdd->pdd_CSSubType)
2134 takeit = FALSE;
2137 if((ti = FindTagItem(DDA_DescriptorLength, tags)))
2139 if(ti->ti_Data != pdd->pdd_Length)
2141 takeit = FALSE;
2145 if(takeit)
2147 return(pdd);
2149 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2151 return(NULL);
2152 AROS_LIBFUNC_EXIT
2154 /* \\\ */
2156 /* *** Device *** */
2158 /* /// "pFreeBindings()" */
2159 void pFreeBindings(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2161 struct PsdHardware *phw = pd->pd_Hardware;
2162 struct PsdConfig *pc;
2163 struct PsdInterface *pif;
2164 KPRINTF(3, (" FreeBindings(%p)\n", pd));
2166 /* move device to list of dead devices first
2167 This caused a lot of trouble as it could
2168 happen that a device got into class scan
2169 right after the bindings had been released. */
2170 psdLockWritePBase();
2171 Remove(&pd->pd_Node);
2172 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2173 psdUnlockPBase();
2175 /* If there are bindings, get rid of them. */
2176 psdLockWriteDevice(pd);
2177 psdReleaseDevBinding(pd);
2179 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2180 while(pc->pc_Node.ln_Succ)
2182 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2183 while(pif->pif_Node.ln_Succ)
2185 psdReleaseIfBinding(pif);
2186 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2188 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2190 psdUnlockDevice(pd);
2192 /* \\\ */
2194 /* /// "pFreeDevice()" */
2195 void pFreeDevice(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2197 struct PsdHardware *phw = pd->pd_Hardware;
2198 struct PsdConfig *pc;
2199 struct PsdDescriptor *pdd;
2201 psdCalculatePower(phw);
2202 psdLockWriteDevice(pd);
2203 if(pd->pd_UseCnt)
2205 KPRINTF(20, ("Couldn't free device, use cnt %ld\n", pd->pd_UseCnt));
2206 pd->pd_Flags &= ~PDFF_CONNECTED;
2207 pd->pd_Flags |= PDFF_DELEXPUNGE;
2208 psdUnlockDevice(pd);
2209 } else {
2210 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2211 while(pc->pc_Node.ln_Succ)
2213 pFreeConfig(pc);
2214 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2217 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2218 while(pdd->pdd_Node.ln_Succ)
2220 pFreeDescriptor(pdd);
2221 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2224 psdFreeVec(pd->pd_LangIDArray);
2225 pd->pd_LangIDArray = NULL;
2226 psdFreeVec(pd->pd_MnfctrStr);
2227 pd->pd_MnfctrStr = NULL;
2228 /*if(!ps->ps_PoPo.po_Task) // keep name at least
2230 psdFreeVec(pd->pd_ProductStr);
2231 pd->pd_ProductStr = NULL;
2233 psdFreeVec(pd->pd_OldProductStr);
2234 pd->pd_OldProductStr = NULL;
2235 psdFreeVec(pd->pd_SerNumStr);
2236 pd->pd_SerNumStr = NULL;
2237 psdFreeVec(pd->pd_IDString);
2238 pd->pd_IDString = NULL;
2239 if(pd->pd_DevAddr)
2241 KPRINTF(5,("Released DevAddr %ld\n", pd->pd_DevAddr));
2242 phw->phw_DevArray[pd->pd_DevAddr] = NULL;
2244 psdUnlockDevice(pd);
2245 psdLockWritePBase();
2246 Remove(&pd->pd_Node);
2247 psdUnlockPBase();
2248 pDeleteSem(ps, &pd->pd_Lock);
2249 /* cannot free this vector -- tasks might still call LockDevice */
2250 //psdFreeVec(pd);
2252 KPRINTF(3, ("FreeDevice done\n"));
2254 /* \\\ */
2256 /* /// "psdFreeDevice()" */
2257 AROS_LH1(void, psdFreeDevice,
2258 AROS_LHA(struct PsdDevice *, pd, A0),
2259 LIBBASETYPEPTR, ps, 16, psd)
2261 AROS_LIBFUNC_INIT
2262 struct PsdHardware *phw = pd->pd_Hardware;
2263 struct PsdConfig *pc;
2264 struct PsdInterface *pif;
2265 struct PsdRTIsoHandler *prt;
2266 struct PsdRTIsoHandler *nextprt;
2268 KPRINTF(3, (" FreeDevice(%p)\n", pd));
2270 /* move device to list of dead devices first
2271 This caused a lot of trouble as it could
2272 happen that a device got into class scan
2273 right after the bindings had been released. */
2274 psdLockWritePBase();
2275 Remove(&pd->pd_Node);
2276 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2277 pd->pd_Flags &= ~PDFF_DELEXPUNGE;
2278 psdUnlockPBase();
2280 psdLockWriteDevice(pd);
2282 /* Inform all ISO handlers about the device going offline */
2283 prt = (struct PsdRTIsoHandler *) pd->pd_RTIsoHandlers.lh_Head;
2284 while((nextprt = (struct PsdRTIsoHandler *) prt->prt_Node.ln_Succ))
2286 if(prt->prt_ReleaseHook)
2288 CallHookPkt(prt->prt_ReleaseHook, prt, NULL);
2290 prt = nextprt;
2293 /* If there are bindings, get rid of them. */
2294 psdHubReleaseDevBinding(pd);
2296 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2297 while(pc->pc_Node.ln_Succ)
2299 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2300 while(pif->pif_Node.ln_Succ)
2302 psdHubReleaseIfBinding(pif);
2303 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2305 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2307 psdUnlockDevice(pd);
2309 pFreeDevice(ps, pd);
2310 AROS_LIBFUNC_EXIT
2312 /* \\\ */
2314 /* /// "psdAllocDevice()" */
2315 AROS_LH1(struct PsdDevice *, psdAllocDevice,
2316 AROS_LHA(struct PsdHardware *, phw, A0),
2317 LIBBASETYPEPTR, ps, 15, psd)
2319 AROS_LIBFUNC_INIT
2320 struct PsdDevice *pd;
2321 KPRINTF(2, ("psdAllocDevice(%p)\n", phw));
2322 if((pd = psdAllocVec(sizeof(struct PsdDevice))))
2324 pd->pd_Hardware = phw;
2325 pd->pd_Hub = NULL;
2326 pd->pd_MaxPktSize0 = 8;
2328 pInitSem(ps, &pd->pd_Lock, "Device");
2330 NewList(&pd->pd_Configs);
2331 NewList(&pd->pd_Descriptors);
2332 NewList(&pd->pd_RTIsoHandlers);
2334 // init prefs
2335 pd->pd_PoPoCfg.poc_ChunkID = AROS_LONG2BE(IFFCHNK_POPUP);
2336 pd->pd_PoPoCfg.poc_Length = AROS_LONG2BE(sizeof(struct PsdPoPoCfg) - 8);
2337 pd->pd_PoPoCfg.poc_InhibitPopup = FALSE;
2338 pd->pd_PoPoCfg.poc_NoClassBind = FALSE;
2339 pd->pd_PoPoCfg.poc_OverridePowerInfo = POCP_TRUST_DEVICE;
2341 psdLockWritePBase();
2342 AddTail(&phw->phw_Devices, &pd->pd_Node);
2343 psdUnlockPBase();
2344 return(pd);
2345 } else {
2346 KPRINTF(20, ("psdAllocDevice(): out of memory!\n"));
2348 return(NULL);
2349 AROS_LIBFUNC_EXIT
2351 /* \\\ */
2353 /* /// "psdLockReadDevice()" */
2354 AROS_LH1(void, psdLockReadDevice,
2355 AROS_LHA(struct PsdDevice *, pd, A0),
2356 LIBBASETYPEPTR, ps, 17, psd)
2358 AROS_LIBFUNC_INIT
2359 KPRINTF(2, ("psdLockReadDevice(%p, %p)\n", pd, FindTask(NULL)));
2360 pLockSemShared(ps, &pd->pd_Lock);
2361 AROS_LIBFUNC_EXIT
2363 /* \\\ */
2365 /* /// "psdLockWriteDevice()" */
2366 AROS_LH1(void, psdLockWriteDevice,
2367 AROS_LHA(struct PsdDevice *, pd, A0),
2368 LIBBASETYPEPTR, ps, 18, psd)
2370 AROS_LIBFUNC_INIT
2371 KPRINTF(2, ("psdLockWriteDevice(%p, %p)\n", pd, FindTask(NULL)));
2372 pLockSemExcl(ps, &pd->pd_Lock);
2373 AROS_LIBFUNC_EXIT
2375 /* \\\ */
2377 /* /// "psdUnlockDevice()" */
2378 AROS_LH1(void, psdUnlockDevice,
2379 AROS_LHA(struct PsdDevice *, pd, A0),
2380 LIBBASETYPEPTR, ps, 19, psd)
2382 AROS_LIBFUNC_INIT
2383 KPRINTF(2, ("psdUnlockDevice(%p, %p)\n", pd, FindTask(NULL)));
2384 pUnlockSem(ps, &pd->pd_Lock);
2385 AROS_LIBFUNC_EXIT
2387 /* \\\ */
2389 /* /// "pAllocDevAddr()" */
2390 UWORD pAllocDevAddr(struct PsdDevice *pd)
2392 struct PsdHardware *phw = pd->pd_Hardware;
2393 UWORD da;
2394 if(pd->pd_DevAddr)
2396 return(pd->pd_DevAddr);
2398 for(da = 1; da < 128; da++)
2400 if(!phw->phw_DevArray[da])
2402 phw->phw_DevArray[da] = pd;
2403 pd->pd_DevAddr = da;
2404 return(da);
2407 return(0);
2409 /* \\\ */
2411 /* /// "psdGetStringDescriptor()" */
2412 AROS_LH2(STRPTR, psdGetStringDescriptor,
2413 AROS_LHA(struct PsdPipe *, pp, A1),
2414 AROS_LHA(UWORD, idx, D0),
2415 LIBBASETYPEPTR, ps, 33, psd)
2417 AROS_LIBFUNC_INIT
2418 struct PsdDevice *pd = pp->pp_Device;
2419 ULONG len;
2420 UBYTE buf[256];
2421 UWORD *tmpptr;
2422 UWORD *tmpbuf;
2423 STRPTR rs;
2424 STRPTR cbuf;
2425 LONG ioerr;
2426 UWORD widechar;
2427 KPRINTF(1, ("psdGetStringDescriptor(%p, %ld)\n", pp, idx));
2429 buf[0] = 0;
2430 if(!pd->pd_LangIDArray)
2432 KPRINTF(10,("Trying to get language array...\n"));
2433 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2434 USR_GET_DESCRIPTOR, UDT_STRING<<8, 0);
2435 ioerr = psdDoPipe(pp, buf, 2);
2436 if(ioerr == UHIOERR_OVERFLOW)
2438 ioerr = 0;
2439 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Language array overflow.");
2441 if(ioerr)
2443 ioerr = psdDoPipe(pp, buf, 256);
2444 if(ioerr == UHIOERR_RUNTPACKET)
2446 ioerr = 0;
2449 if(!ioerr)
2451 len = buf[0];
2452 if((pd->pd_LangIDArray = psdAllocVec(max(len, 4))))
2454 tmpbuf = tmpptr = pd->pd_LangIDArray;
2455 KPRINTF(1, ("Getting LangID Array length %ld\n", len));
2456 // generate minimal sized array
2457 if(len < 4)
2459 len = 4;
2460 *tmpbuf++ = 0;
2461 *tmpbuf = AROS_WORD2LE(0x0409);
2462 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2463 "Language array descriptor too small (len %ld), using dummy.",
2464 len);*/
2465 ioerr = 0;
2466 } else {
2467 ioerr = psdDoPipe(pp, tmpbuf++, len);
2469 if(!ioerr)
2471 len >>= 1;
2472 while(--len)
2474 KPRINTF(1, ("LangID: %04lx\n", AROS_WORD2LE(*tmpbuf)));
2475 *tmpptr++ = AROS_WORD2LE(*tmpbuf);
2476 tmpbuf++;
2478 *tmpptr = 0;
2479 tmpptr = pd->pd_LangIDArray;
2480 pd->pd_CurrLangID = *tmpptr;
2481 while(*tmpptr)
2483 if(*tmpptr == 0x0409)
2485 pd->pd_CurrLangID = *tmpptr;
2486 break;
2488 tmpptr++;
2490 } else {
2491 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2492 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2493 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2494 KPRINTF(15, ("Error reading lang array descriptor (%ld) failed %ld\n", len, ioerr));
2495 *tmpptr = 0;
2497 } else {
2498 KPRINTF(20, ("No langid array memory!\n"));
2500 } else {
2501 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2502 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2503 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2504 KPRINTF(15, ("Error reading lang array descriptor (2) failed %ld\n", ioerr));
2505 /* Create empty array */
2506 if((pd->pd_LangIDArray = psdAllocVec(2)))
2508 *pd->pd_LangIDArray = 0;
2512 buf[0] = 0;
2513 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2514 USR_GET_DESCRIPTOR, (UDT_STRING<<8)|idx, pd->pd_CurrLangID);
2515 ioerr = psdDoPipe(pp, buf, 2);
2516 if(ioerr == UHIOERR_OVERFLOW)
2518 ioerr = 0;
2519 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "String %ld overflow.", idx);
2521 if(ioerr)
2523 ioerr = psdDoPipe(pp, buf, 256);
2525 if(!ioerr)
2527 len = buf[0];
2528 if(len > 2)
2530 tmpptr = (UWORD *) buf;
2531 KPRINTF(1, ("Getting String Descriptor %ld, length %ld\n", idx, len));
2532 ioerr = psdDoPipe(pp, tmpptr++, len);
2533 if(ioerr == UHIOERR_RUNTPACKET)
2535 len = pp->pp_IOReq.iouh_Actual;
2536 if(len > 3)
2538 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2539 "String descriptor %ld truncated to %ld, requested %ld",
2540 idx, len, buf[0]);
2541 ioerr = 0;
2544 else if(ioerr)
2546 ioerr = psdDoPipe(pp, buf, 256);
2548 if(!ioerr)
2550 if((cbuf = rs = psdAllocVec(len>>1)))
2552 len >>= 1;
2553 while(--len)
2555 widechar = *tmpptr++;
2556 widechar = AROS_LE2WORD(widechar);
2557 if(widechar == 0)
2559 break;
2561 if((widechar < 0x20) || (widechar > 255))
2563 *cbuf++ = '?';
2564 } else {
2565 *cbuf++ = widechar;
2568 *cbuf = 0;
2569 KPRINTF(1, ("String \"%s\"\n", rs));
2570 if(*rs)
2572 return(rs);
2573 } else {
2574 psdFreeVec(rs);
2575 return(NULL);
2577 } else {
2578 KPRINTF(20, ("No memory for string!\n"));
2580 } else {
2581 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2582 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2583 idx, len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2584 KPRINTF(15, ("Error reading string descriptor %ld (%ld) failed %ld\n",
2585 idx, len, ioerr));
2587 } else {
2588 KPRINTF(5, ("Empty string\n"));
2589 return(psdCopyStr(""));
2591 } else {
2592 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2593 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2594 idx, 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2595 KPRINTF(15, ("Error reading string descriptor %ld (2) failed %ld\n", idx, ioerr));
2597 return(NULL);
2598 AROS_LIBFUNC_EXIT
2600 /* \\\ */
2602 /* /// "psdSetDeviceConfig()" */
2603 AROS_LH2(BOOL, psdSetDeviceConfig,
2604 AROS_LHA(struct PsdPipe *, pp, A1),
2605 AROS_LHA(UWORD, cfgnum, D0),
2606 LIBBASETYPEPTR, ps, 34, psd)
2608 AROS_LIBFUNC_INIT
2609 struct PsdConfig *pc;
2610 struct PsdDevice *pd = pp->pp_Device;
2611 //UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2612 LONG ioerr;
2613 BOOL res = FALSE;
2615 KPRINTF(2, ("Setting configuration to %ld...\n", cfgnum));
2616 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2617 USR_SET_CONFIGURATION, cfgnum, 0);
2618 ioerr = psdDoPipe(pp, NULL, 0);
2619 if(!ioerr)
2621 #if 0 // MacOS X does not verify the configuration set. And as we don't check the results anyway, don't obtain current configuration to avoid bad devices breaking down
2622 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2623 USR_GET_CONFIGURATION, 0, 0);
2624 ioerr = psdDoPipe(pp, buf, 1);
2625 if(!ioerr)
2627 pd->pd_CurrCfg = buf[0];
2628 if(cfgnum != buf[0])
2630 pd->pd_CurrCfg = cfgnum;
2631 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2632 "Broken: SetConfig/GetConfig mismatch (%ld != %ld) for %s!",
2633 cfgnum, buf[0], pp->pp_Device->pd_ProductStr);
2635 res = TRUE;
2636 } else {
2637 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2638 "GET_CONFIGURATION failed: %s (%ld)",
2639 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2640 pd->pd_CurrCfg = cfgnum;
2641 KPRINTF(15, ("GET_CONFIGURATION failed %ld!\n", ioerr));
2643 #else
2644 pd->pd_CurrCfg = cfgnum;
2645 res = TRUE;
2646 #endif
2647 } else {
2648 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2649 "SET_CONFIGURATION failed: %s (%ld)",
2650 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2651 KPRINTF(15, ("SET_CONFIGURATION failed %ld!\n", ioerr));
2653 // update direct link
2654 Forbid();
2655 pd->pd_CurrentConfig = NULL;
2656 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2657 while(pc->pc_Node.ln_Succ)
2659 if(pc->pc_CfgNum == pd->pd_CurrCfg)
2661 pd->pd_CurrentConfig = pc;
2662 break;
2664 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2666 Permit();
2667 if(!pd->pd_CurrentConfig)
2669 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "No current configuration, huh?");
2670 } else {
2671 UWORD status = 0;
2672 // power saving stuff
2673 if(ps->ps_GlobalCfg->pgc_PowerSaving && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
2675 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2676 USR_SET_FEATURE, UFS_DEVICE_REMOTE_WAKEUP, 0);
2677 ioerr = psdDoPipe(pp, NULL, 0);
2678 if(ioerr)
2680 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2681 "SET_DEVICE_REMOTE_WAKEUP failed: %s (%ld)",
2682 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2683 KPRINTF(15, ("SET_DEVICE_REMOTE_WAKEUP failed %ld!\n", ioerr));
2685 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2686 ioerr = psdDoPipe(pp, &status, 2);
2687 if(!ioerr)
2689 if(status & U_GSF_REMOTE_WAKEUP)
2691 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2692 "Enabled remote wakeup feature for '%s'.",
2693 pd->pd_ProductStr);
2694 } else {
2695 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_REMOTE_WAKEUP;
2696 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2697 "Remote wakeup feature for '%s' could not be enabled.",
2698 pd->pd_ProductStr);
2700 } else {
2701 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2702 "GET_STATUS failed: %s (%ld)",
2703 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2704 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2706 } else {
2707 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2708 ioerr = psdDoPipe(pp, &status, 2);
2710 if(!ioerr)
2712 if((status & U_GSF_SELF_POWERED) && (!(pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED)))
2714 pd->pd_CurrentConfig->pc_Attr |= USCAF_SELF_POWERED;
2715 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2716 "Device '%s' says it is currently self-powered. Fixing config.",
2717 pd->pd_ProductStr);
2719 else if((!(status & U_GSF_SELF_POWERED)) && (pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED))
2721 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_SELF_POWERED;
2722 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2723 "Device '%s' says it is currently bus-powered. Fixing config.",
2724 pd->pd_ProductStr);
2726 } else {
2727 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2728 "GET_STATUS failed: %s (%ld)",
2729 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2730 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2734 return(res);
2735 AROS_LIBFUNC_EXIT
2737 /* \\\ */
2739 /* /// "psdSetAltInterface()" */
2740 AROS_LH2(BOOL, psdSetAltInterface,
2741 AROS_LHA(struct PsdPipe *, pp, A1),
2742 AROS_LHA(struct PsdInterface *, pif, A0),
2743 LIBBASETYPEPTR, ps, 43, psd)
2745 AROS_LIBFUNC_INIT
2746 struct PsdConfig *pc = pif->pif_Config;
2747 struct PsdInterface *curif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2748 struct PsdInterface *tmpif;
2749 struct PsdDevice *pd = pc->pc_Device;
2750 UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2751 LONG ioerr;
2752 UWORD ifnum = pif->pif_IfNum;
2753 UWORD altnum = pif->pif_Alternate;
2755 KPRINTF(2, ("Setting interface %ld to alt %ld...\n", ifnum, altnum));
2756 psdLockWriteDevice(pd);
2758 /* Find root config structure */
2759 while(curif->pif_Node.ln_Succ)
2761 if(curif->pif_IfNum == ifnum)
2763 break;
2765 curif = (struct PsdInterface *) curif->pif_Node.ln_Succ;
2767 if(!curif->pif_Node.ln_Succ)
2769 KPRINTF(20, ("Where did you get that fucking interface from?!?"));
2770 psdUnlockDevice(pd);
2771 return(FALSE);
2773 if(curif == pif) /* Is already the current alternate setting */
2775 psdUnlockDevice(pd);
2776 return(TRUE);
2778 KPRINTF(1, ("really setting interface...\n"));
2779 if(pp)
2781 psdPipeSetup(pp, URTF_STANDARD|URTF_INTERFACE,
2782 USR_SET_INTERFACE, altnum, ifnum);
2783 ioerr = psdDoPipe(pp, NULL, 0);
2784 } else {
2785 ioerr = 0;
2787 if((!ioerr) || (ioerr == UHIOERR_STALL))
2789 if(pp)
2791 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_INTERFACE,
2792 USR_GET_INTERFACE, 0, ifnum);
2793 ioerr = psdDoPipe(pp, buf, 1);
2794 } else {
2795 buf[0] = altnum;
2797 if(!ioerr)
2799 if(altnum == buf[0])
2801 KPRINTF(1, ("resorting list..."));
2802 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2803 "Changed to alt %ld",
2804 altnum);*/
2805 Forbid();
2806 /* Remove pif from alt list */
2807 Remove(&pif->pif_Node);
2808 pif->pif_ParentIf = NULL;
2809 /* Now move bindings */
2810 pif->pif_ClsBinding = curif->pif_ClsBinding;
2811 pif->pif_IfBinding = curif->pif_IfBinding;
2812 curif->pif_IfBinding = NULL;
2813 curif->pif_ClsBinding = NULL;
2814 /* Insert it after root interface */
2815 Insert(&pc->pc_Interfaces, (struct Node *) &pif->pif_Node, (struct Node *) &curif->pif_Node);
2816 /* Unlink root interface */
2817 Remove(&curif->pif_Node);
2818 /* Now move all remaining alt interfaces to the new root interface */
2819 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2820 while(tmpif->pif_Node.ln_Succ)
2822 Remove(&tmpif->pif_Node);
2823 AddTail(&pif->pif_AlterIfs, &tmpif->pif_Node);
2824 tmpif->pif_ParentIf = pif;
2825 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2827 /* Add old root to the end of the alt list */
2828 AddTail(&pif->pif_AlterIfs, &curif->pif_Node);
2829 curif->pif_ParentIf = pif;
2830 Permit();
2831 psdUnlockDevice(pd);
2832 return(TRUE);
2833 } else {
2834 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2835 "Attempt to change interface %ld to alt %ld remained at alt %ld.",
2836 ifnum, altnum, buf[0]);
2838 } else {
2839 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2840 "GET_INTERFACE(%ld) failed: %s (%ld)",
2841 ifnum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2842 KPRINTF(15, ("GET_INTERFACE failed %ld!\n", ioerr));
2844 } else {
2845 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2846 "SET_INTERFACE(%ld)=%ld failed: %s (%ld)",
2847 ifnum, altnum,
2848 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2849 KPRINTF(15, ("SET_INTERFACE failed %ld!\n", ioerr));
2851 psdUnlockDevice(pd);
2852 return(FALSE);
2853 AROS_LIBFUNC_EXIT
2855 /* \\\ */
2857 /* /// "psdEnumerateDevice()" */
2858 AROS_LH1(struct PsdDevice *, psdEnumerateDevice,
2859 AROS_LHA(struct PsdPipe *, pp, A1),
2860 LIBBASETYPEPTR, ps, 20, psd)
2862 AROS_LIBFUNC_INIT
2864 struct PsdDevice *pd = pp->pp_Device;
2865 struct PsdDevice *itpd = pp->pp_Device;
2866 struct PsdConfig *pc;
2867 struct PsdInterface *pif;
2868 struct UsbStdDevDesc usdd;
2870 UWORD oldflags;
2871 ULONG oldnaktimeout;
2873 LONG ioerr;
2875 STRPTR classname;
2876 STRPTR vendorname;
2878 ULONG devclass;
2880 IPTR islowspeed;
2882 BOOL hasprodname;
2883 BOOL haspopupinhibit;
2885 UWORD cfgnum;
2887 struct PsdIFFContext *pic;
2889 ULONG *chnk;
2891 #ifdef AROS_USB30_CODE
2892 struct UsbStdBOSDesc usbosd;
2893 LONG ioerr_bos;
2894 #endif
2896 KPRINTF(2, ("psdEnumerateDevice(%p)\n", pp));
2898 psdLockWriteDevice(pd);
2899 if(pAllocDevAddr(pd)) {
2901 oldflags = pp->pp_IOReq.iouh_Flags;
2902 oldnaktimeout = pp->pp_IOReq.iouh_NakTimeout;
2903 pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
2904 pp->pp_IOReq.iouh_NakTimeout = 1000;
2905 pp->pp_IOReq.iouh_DevAddr = 0;
2908 64 bytes is the maximum packet size for control transfers in fullspeed and highspeed devices
2910 psdGetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, &islowspeed, TAG_END);
2911 if(islowspeed)
2913 pp->pp_IOReq.iouh_MaxPktSize = 8;
2914 } else {
2915 pp->pp_IOReq.iouh_MaxPktSize = 64;
2918 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2919 ioerr = psdDoPipe(pp, &usdd, 8);
2920 if(ioerr && (ioerr != UHIOERR_RUNTPACKET)) {
2921 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "GET_DESCRIPTOR (8) failed: %s (%ld)", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2922 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
2925 KPRINTF(1, ("Setting DevAddr %ld...\n", pd->pd_DevAddr));
2926 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, USR_SET_ADDRESS, pd->pd_DevAddr, 0);
2927 ioerr = psdDoPipe(pp, NULL, 0);
2929 This is tricky: Maybe the device has accepted the command,
2930 but failed to send an ACK. Now, every resend trial will
2931 go to the wrong address!
2933 if((ioerr == UHIOERR_TIMEOUT) || (ioerr == UHIOERR_STALL)) {
2934 KPRINTF(1, ("First attempt failed, retrying new address\n"));
2935 /*pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;*/
2936 psdDelayMS(250);
2937 ioerr = psdDoPipe(pp, NULL, 0);
2938 /*pp->pp_IOReq.iouh_DevAddr = 0;*/
2941 if(!ioerr) {
2942 pd->pd_Flags |= PDFF_HASDEVADDR|PDFF_CONNECTED;
2943 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
2945 psdDelayMS(50); /* Allowed time to settle */
2948 We have already received atleast the first 8 bytes from the descriptor, asking again may confuse some devices
2949 This is somewhat similar to how Windows enumerates USB devices
2951 KPRINTF(1, ("Getting MaxPktSize0...\n"));
2952 switch(usdd.bMaxPacketSize0)
2954 case 8:
2955 case 16:
2956 case 32:
2957 case 64:
2958 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = usdd.bMaxPacketSize0;
2959 break;
2960 #ifdef AROS_USB30_CODE
2961 case 9:
2962 if((AROS_LE2WORD(usdd.bcdUSB) >= 0x0300)) {
2963 /* 9 is the only valid value for superspeed mode and it is the exponent of 2 =512 bytes */
2964 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = (1<<9);
2965 break;
2967 #endif
2968 default:
2969 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Illegal MaxPktSize0=%ld for endpoint 0", (ULONG) usdd.bMaxPacketSize0);
2970 KPRINTF(2, ("Illegal MaxPktSize0=%ld!\n", usdd.bMaxPacketSize0));
2971 //pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = 8;
2972 ioerr = UHIOERR_CRCERROR;
2973 break;
2976 KPRINTF(1, (" MaxPktSize0 = %ld\n", pd->pd_MaxPktSize0));
2978 KPRINTF(1, ("Getting full descriptor...\n"));
2980 We have set a new address for the device so we need to setup the pipe again
2982 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2983 ioerr = psdDoPipe(pp, &usdd, sizeof(struct UsbStdDevDesc));
2984 if(!ioerr)
2986 pAllocDescriptor(pd, (UBYTE *) &usdd);
2987 pd->pd_Flags |= PDFF_HASDEVDESC;
2988 pd->pd_USBVers = AROS_WORD2LE(usdd.bcdUSB);
2989 pd->pd_DevClass = usdd.bDeviceClass;
2990 pd->pd_DevSubClass = usdd.bDeviceSubClass;
2991 pd->pd_DevProto = usdd.bDeviceProtocol;
2992 pd->pd_VendorID = AROS_WORD2LE(usdd.idVendor);
2993 pd->pd_ProductID = AROS_WORD2LE(usdd.idProduct);
2994 pd->pd_DevVers = AROS_WORD2LE(usdd.bcdDevice);
2995 vendorname = psdNumToStr(NTS_VENDORID, (LONG) pd->pd_VendorID, NULL);
2997 // patch to early determine highspeed roothubs
2998 if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x200) && (pd->pd_USBVers < 0x300)) {
2999 pd->pd_Flags |= PDFF_HIGHSPEED;
3002 #ifdef AROS_USB30_CODE
3003 if(((!pd->pd_Hub) && pd->pd_USBVers >= 0x300)) {
3004 pd->pd_Flags |= PDFF_SUPERSPEED;
3008 The USB 3.0 and USB 2.0 LPM specifications define a new USB descriptor called the Binary Device Object Store (BOS)
3009 for a USB device, which reports a bcdUSB value greater than 0x0200 in their device descriptor
3011 if((pd->pd_USBVers > 0x200)) {
3012 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_BOS<<8, 0);
3013 ioerr_bos = psdDoPipe(pp, &usbosd, sizeof(struct UsbStdBOSDesc));
3014 if(!ioerr_bos) {
3015 XPRINTF(1, ("BOS descriptor received...\n"));
3018 BOS descriptor bLength = sizeof(struct UsbStdBOSDesc)
3019 BOS descriptor bNumDeviceCaps != 0
3020 BOS descriptor wTotalLength >= bLength + (bNumDeviceCaps * sizeof(protocol specific capability descriptor))
3022 if(usbosd.bLength != sizeof(struct UsbStdBOSDesc)) {
3023 XPRINTF(1, ("Invalid BOS descriptor bLength!\n"));
3026 if(usbosd.bNumDeviceCaps == 0) {
3027 XPRINTF(1, ("Invalid BOS descriptor bNumDeviceCaps!\n"));
3028 }else if(usbosd.wTotalLength < (usbosd.bLength + (usbosd.bNumDeviceCaps * 2))) {
3029 XPRINTF(1, ("Invalid BOS descriptor wTotalLength!\n"));
3032 } else {
3033 XPRINTF(1, ("GET_DESCRIPTOR (5) failed %ld!\n", ioerr_bos));
3036 #endif
3038 if(usdd.iManufacturer) {
3039 pd->pd_MnfctrStr = psdGetStringDescriptor(pp, usdd.iManufacturer);
3042 if(usdd.iProduct) {
3043 pd->pd_ProductStr = psdGetStringDescriptor(pp, usdd.iProduct);
3046 if(usdd.iSerialNumber) {
3047 pd->pd_SerNumStr = psdGetStringDescriptor(pp, usdd.iSerialNumber);
3050 if(!pd->pd_MnfctrStr) {
3051 pd->pd_MnfctrStr = psdCopyStr(vendorname ? vendorname : (STRPTR) "n/a");
3054 if(!pd->pd_ProductStr) {
3055 hasprodname = FALSE;
3056 classname = psdNumToStr(NTS_CLASSCODE, (LONG) pd->pd_DevClass, NULL);
3057 if(classname) {
3058 pd->pd_ProductStr = psdCopyStrFmt("%s: Vdr=%04lx/PID=%04lx", classname, pd->pd_VendorID, pd->pd_ProductID);
3059 } else {
3060 pd->pd_ProductStr = psdCopyStrFmt("Cls=%ld/Vdr=%04lx/PID=%04lx", pd->pd_DevClass, pd->pd_VendorID, pd->pd_ProductID);
3062 } else {
3063 hasprodname = TRUE;
3066 if(!pd->pd_SerNumStr) {
3067 pd->pd_SerNumStr = psdCopyStr("n/a");
3070 KPRINTF(2, ("Product : %s\n"
3071 "Manufacturer: %s\n"
3072 "SerialNumber: %s\n",
3073 pd->pd_ProductStr, pd->pd_MnfctrStr, pd->pd_SerNumStr));
3074 KPRINTF(2, ("USBVersion: %04lx\n"
3075 "Class : %ld\n"
3076 "SubClass : %ld\n"
3077 "DevProto : %ld\n"
3078 "VendorID : %ld\n"
3079 "ProductID : %ld\n"
3080 "DevVers : %04lx\n",
3081 pd->pd_USBVers, pd->pd_DevClass, pd->pd_DevSubClass, pd->pd_DevProto,
3082 pd->pd_VendorID, pd->pd_ProductID, pd->pd_DevVers));
3084 /* check for clones */
3085 itpd = NULL;
3086 while((itpd = psdGetNextDevice(itpd)))
3088 if(itpd != pd)
3090 if((itpd->pd_ProductID == pd->pd_ProductID) &&
3091 (itpd->pd_VendorID == pd->pd_VendorID) &&
3092 (!strcmp(itpd->pd_SerNumStr, pd->pd_SerNumStr)) &&
3093 (itpd->pd_CloneCount == pd->pd_CloneCount))
3095 pd->pd_CloneCount++;
3096 itpd = NULL;
3101 pd->pd_IDString = psdCopyStrFmt("%s-%04lx-%04lx-%s-%02lx", pd->pd_ProductStr, pd->pd_VendorID, pd->pd_ProductID, pd->pd_SerNumStr, pd->pd_CloneCount);
3103 pStripString(ps, pd->pd_MnfctrStr);
3104 pStripString(ps, pd->pd_ProductStr);
3105 pStripString(ps, pd->pd_SerNumStr);
3107 /* get custom name of device */
3108 pLockSemExcl(ps, &ps->ps_ConfigLock); // Exclusive lock to avoid deadlock situation when promoting read to write
3109 pd->pd_OldProductStr = pd->pd_ProductStr;
3110 pd->pd_ProductStr = NULL;
3111 haspopupinhibit = FALSE;
3112 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
3113 if(pic)
3115 pd->pd_IsNewToMe = FALSE;
3116 if((pd->pd_ProductStr = pGetStringChunk(ps, pic, IFFCHNK_NAME)))
3118 hasprodname = TRUE;
3120 if((chnk = pFindCfgChunk(ps, pic, IFFCHNK_POPUP)))
3122 struct PsdPoPoCfg *poc = (struct PsdPoPoCfg *) chnk;
3123 CopyMem(((UBYTE *) poc) + 8, ((UBYTE *) &pd->pd_PoPoCfg) + 8, min(AROS_LONG2BE(poc->poc_Length), AROS_LONG2BE(pd->pd_PoPoCfg.poc_Length)));
3124 haspopupinhibit = TRUE;
3126 } else {
3127 pd->pd_IsNewToMe = TRUE;
3128 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
3130 if(!pd->pd_ProductStr)
3132 pd->pd_ProductStr = psdCopyStr(pd->pd_OldProductStr);
3134 if(!haspopupinhibit)
3136 if(pd->pd_DevClass == HUB_CLASSCODE) // hubs default to true
3138 pd->pd_PoPoCfg.poc_InhibitPopup = TRUE;
3141 pUnlockSem(ps, &ps->ps_ConfigLock);
3143 pd->pd_NumCfgs = usdd.bNumConfigurations;
3144 KPRINTF(10, ("Device has %ld different configurations\n", pd->pd_NumCfgs));
3146 if(pGetDevConfig(pp))
3148 cfgnum = 1;
3149 if(pd->pd_Configs.lh_Head->ln_Succ)
3151 cfgnum = ((struct PsdConfig *) pd->pd_Configs.lh_Head)->pc_CfgNum;
3153 psdSetDeviceConfig(pp, cfgnum); /* *** FIXME *** Workaround for USB2.0 devices */
3155 if(!hasprodname)
3157 devclass = pd->pd_DevClass;
3158 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
3159 while(pc->pc_Node.ln_Succ)
3161 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3162 while(pif->pif_Node.ln_Succ)
3164 if(pif->pif_IfClass)
3166 if(!devclass)
3168 devclass = pif->pif_IfClass;
3169 } else {
3170 if(devclass != pif->pif_IfClass)
3172 devclass = 0;
3173 break;
3177 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3179 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
3181 if(devclass)
3183 classname = psdNumToStr(NTS_CLASSCODE, (LONG) devclass, NULL);
3184 if(classname)
3186 psdFreeVec(pd->pd_ProductStr);
3187 if(vendorname)
3189 pd->pd_ProductStr = psdCopyStrFmt("%s (%s/%04lx)",
3190 classname, vendorname, pd->pd_ProductID);
3191 } else {
3192 pd->pd_ProductStr = psdCopyStrFmt("%s (%04lx/%04lx)",
3193 classname, pd->pd_VendorID, pd->pd_ProductID);
3198 pFixBrokenConfig(pp);
3199 pp->pp_IOReq.iouh_Flags = oldflags;
3200 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3201 psdUnlockDevice(pd);
3202 psdCalculatePower(pd->pd_Hardware);
3203 return(pd);
3204 } /*else {
3205 KPRINTF(15, ("SetDeviceConfig(1) failed\n"));
3207 } else {
3208 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3209 "Could not acquire device configuration for %s",
3210 pd->pd_ProductStr ? pd->pd_ProductStr : (STRPTR) "new device");
3211 KPRINTF(15, ("GetDevConfig() failed\n"));
3213 /* Although the device failed to configure fully, maybe
3214 some firmware will able to use this device anyway? */
3215 pp->pp_IOReq.iouh_Flags = oldflags;
3216 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3217 psdUnlockDevice(pd);
3218 return(pd);
3219 } else {
3220 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3221 "GET_DESCRIPTOR (len 18) failed: %s (%ld)",
3222 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3223 KPRINTF(15, ("GET_DESCRIPTOR (18) failed %ld!\n", ioerr));
3225 } else {
3226 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
3227 "SET_ADDRESS failed: %s (%ld)",
3228 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3229 KPRINTF(15, ("SET_ADDRESS failed %ld!\n", ioerr));
3231 pp->pp_IOReq.iouh_Flags = oldflags;
3232 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3233 } else {
3234 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "This cannot happen! More than 127 devices on the bus???");
3235 KPRINTF(20, ("out of addresses???\n"));
3238 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Device enumeration failed, sorry.");
3239 psdUnlockDevice(pd);
3240 return(NULL);
3241 AROS_LIBFUNC_EXIT
3243 /* \\\ */
3245 /* /// "psdGetNextDevice()" */
3246 AROS_LH1(struct PsdDevice *, psdGetNextDevice,
3247 AROS_LHA(struct PsdDevice *, pd, A0),
3248 LIBBASETYPEPTR, ps, 21, psd)
3250 AROS_LIBFUNC_INIT
3251 struct PsdHardware *phw;
3253 KPRINTF(1, ("psdGetNextDevice(%p)\n", pd));
3254 if(pd)
3256 /* Is there another device node in the current hardware? */
3257 if(pd->pd_Node.ln_Succ->ln_Succ)
3259 return((struct PsdDevice *) pd->pd_Node.ln_Succ);
3261 /* No, then check if there's another hardware to scan */
3262 phw = (struct PsdHardware *) pd->pd_Hardware->phw_Node.ln_Succ;
3263 } else {
3264 /* No context, start with first hardware */
3265 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3267 while(phw->phw_Node.ln_Succ)
3269 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3270 /* Is this an valid entry, or is the list empty? */
3271 if(pd->pd_Node.ln_Succ)
3273 return(pd);
3275 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3277 /* End of list reached */
3278 return(NULL);
3279 AROS_LIBFUNC_EXIT
3281 /* \\\ */
3283 /* /// "psdSuspendBindings()" */
3284 AROS_LH1(BOOL, psdSuspendBindings,
3285 AROS_LHA(struct PsdDevice *, pd, A0),
3286 LIBBASETYPEPTR, ps, 100, psd)
3288 AROS_LIBFUNC_INIT
3289 struct PsdUsbClass *puc;
3290 struct PsdConfig *pc;
3291 struct PsdInterface *pif;
3292 BOOL res = FALSE;
3293 IPTR suspendable;
3294 BOOL force = FALSE;
3296 KPRINTF(5, ("psdSuspendBindings(%p)\n", pd));
3297 if(pd)
3299 if(ps->ps_GlobalCfg->pgc_ForceSuspend && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
3301 force = TRUE;
3303 // ask existing bindings to go to suspend first -- if they don't support it, break off
3304 if(pd->pd_DevBinding)
3306 if(pd->pd_Flags & PDFF_APPBINDING)
3308 if(!force)
3310 // can't suspend application binding devices
3311 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3312 "Cannot suspend with application binding on '%s'.",
3313 pd->pd_ProductStr);
3314 return FALSE;
3316 psdReleaseDevBinding(pd);
3318 if((puc = pd->pd_ClsBinding))
3320 suspendable = 0;
3321 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3322 if(suspendable)
3324 res = usbDoMethod(UCM_AttemptSuspendDevice, pd->pd_DevBinding);
3325 if(!res)
3327 // didn't want to suspend
3328 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3329 "Class '%s' failed to suspend device '%s'.",
3330 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3331 return FALSE;
3333 } else {
3334 if(pd->pd_IOBusyCount)
3336 if(!force)
3338 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3339 "Class '%s' does not support suspending.",
3340 puc->puc_Node.ln_Name);
3341 return FALSE;
3342 } else {
3343 psdReleaseDevBinding(pd);
3345 } else {
3346 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3347 "Class '%s' does not support suspending, but has no active IO. Suspending anyway.",
3348 puc->puc_Node.ln_Name);
3353 pc = pd->pd_CurrentConfig;
3354 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3355 while(pif->pif_Node.ln_Succ)
3357 if(pif->pif_IfBinding)
3359 if((puc = pif->pif_ClsBinding))
3361 suspendable = 0;
3362 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3363 if(suspendable)
3365 res = usbDoMethod(UCM_AttemptSuspendDevice, pif->pif_IfBinding);
3366 if(!res)
3368 // didn't want to suspend
3369 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3370 "%s failed to suspend device '%s'.",
3371 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3372 return FALSE;
3374 } else {
3375 if(pd->pd_IOBusyCount)
3377 if(!force)
3380 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3381 "%s does not support suspending.",
3382 puc->puc_Node.ln_Name);
3383 return FALSE;
3384 } else {
3385 psdReleaseIfBinding(pif);
3387 } else {
3388 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3389 "%s does not support suspending, but has no active IO. Suspending anyway.",
3390 puc->puc_Node.ln_Name);
3395 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3397 return TRUE;
3399 return FALSE;
3400 AROS_LIBFUNC_EXIT
3402 /* \\\ */
3404 /* /// "psdSuspendDevice()" */
3405 AROS_LH1(BOOL, psdSuspendDevice,
3406 AROS_LHA(struct PsdDevice *, pd, A0),
3407 LIBBASETYPEPTR, ps, 98, psd)
3409 AROS_LIBFUNC_INIT
3410 struct PsdUsbClass *puc;
3411 struct PsdDevice *hubpd;
3412 APTR binding;
3413 BOOL res = FALSE;
3415 KPRINTF(5, ("psdSuspendDevice(%p)\n", pd));
3416 if(pd)
3418 if(pd->pd_Flags & PDFF_SUSPENDED)
3420 return TRUE;
3422 hubpd = pd->pd_Hub;
3423 if(!hubpd) // suspend root hub
3425 // suspend whole USB, using the HCI UHCMD_USBSUSPEND command
3426 // FIXME currently unsupported!
3427 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Suspending of root hub currently not supported.");
3428 return FALSE;
3431 psdLockWriteDevice(pd);
3432 res = psdSuspendBindings(pd);
3433 psdUnlockDevice(pd);
3434 if(res)
3436 psdLockReadDevice(pd);
3437 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3439 res = usbDoMethod(UCM_HubSuspendDevice, binding, pd);
3441 psdUnlockDevice(pd);
3444 if(!res)
3446 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3447 "Suspending of device '%s' failed.",
3448 pd->pd_ProductStr);
3450 return(res);
3451 AROS_LIBFUNC_EXIT
3453 /* \\\ */
3455 /* /// "psdResumeBindings()" */
3456 AROS_LH1(BOOL, psdResumeBindings,
3457 AROS_LHA(struct PsdDevice *, pd, A0),
3458 LIBBASETYPEPTR, ps, 101, psd)
3460 AROS_LIBFUNC_INIT
3461 struct PsdUsbClass *puc;
3462 struct PsdConfig *pc;
3463 struct PsdInterface *pif;
3464 BOOL res = FALSE;
3465 BOOL rescan = FALSE;
3467 KPRINTF(5, ("psdResumeBindings(%p)\n", pd));
3468 if(pd)
3470 // ask existing bindings to resume -- if they don't support it, rebind
3471 if(pd->pd_DevBinding)
3473 if(!(pd->pd_Flags & PDFF_APPBINDING))
3475 if((puc = pd->pd_ClsBinding))
3477 res = usbDoMethod(UCM_AttemptResumeDevice, pd->pd_DevBinding);
3478 if(!res)
3480 // if the device couldn't resume, better get rid of the binding
3481 psdReleaseDevBinding(pd);
3482 rescan = TRUE;
3487 pc = pd->pd_CurrentConfig;
3488 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3489 while(pif->pif_Node.ln_Succ)
3491 if(pif->pif_IfBinding)
3493 if((puc = pif->pif_ClsBinding))
3495 res = usbDoMethod(UCM_AttemptResumeDevice, pif->pif_IfBinding);
3496 if(!res)
3498 // didn't want to suspend
3499 psdReleaseIfBinding(pif);
3500 rescan = TRUE;
3503 break;
3505 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3507 if(rescan)
3509 psdClassScan();
3512 return(TRUE);
3513 AROS_LIBFUNC_EXIT
3515 /* \\\ */
3517 /* /// "psdResumeDevice()" */
3518 AROS_LH1(BOOL, psdResumeDevice,
3519 AROS_LHA(struct PsdDevice *, pd, A0),
3520 LIBBASETYPEPTR, ps, 99, psd)
3522 AROS_LIBFUNC_INIT
3523 struct PsdUsbClass *puc;
3524 struct PsdDevice *hubpd;
3525 APTR binding;
3526 BOOL res = FALSE;
3528 KPRINTF(5, ("psdResumeDevice(%p)\n", pd));
3529 if(pd)
3531 if(!(pd->pd_Flags & PDFF_SUSPENDED))
3533 return(TRUE);
3535 hubpd = pd->pd_Hub;
3536 if(!hubpd) // resume root hub
3538 // resume whole USB, using the HCI UHCMD_USBRESUME command
3539 // FIXME currently unsupported!
3540 return(FALSE);
3542 psdLockWriteDevice(pd);
3543 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3545 res = usbDoMethod(UCM_HubResumeDevice, binding, pd);
3547 psdUnlockDevice(pd);
3549 if(res)
3551 psdResumeBindings(pd);
3555 return(res);
3556 AROS_LIBFUNC_EXIT
3558 /* \\\ */
3560 /* /// "psdFindDeviceA()" */
3561 AROS_LH2(struct PsdDevice *, psdFindDeviceA,
3562 AROS_LHA(struct PsdDevice *, pd, A0),
3563 AROS_LHA(struct TagItem *, tags, A1),
3564 LIBBASETYPEPTR, ps, 44, psd)
3566 AROS_LIBFUNC_INIT
3567 struct TagItem *ti;
3568 BOOL takeit;
3569 KPRINTF(2, ("psdFindDeviceA(%p, %p)\n", pd, tags));
3570 while((pd = psdGetNextDevice(pd)))
3572 takeit = TRUE;
3573 if((ti = FindTagItem(DA_ProductID, tags)))
3575 if(ti->ti_Data != pd->pd_ProductID)
3577 takeit = FALSE;
3580 if((ti = FindTagItem(DA_VendorID, tags)))
3582 if(ti->ti_Data != pd->pd_VendorID)
3584 takeit = FALSE;
3587 if((ti = FindTagItem(DA_Class, tags)))
3589 if(ti->ti_Data != pd->pd_DevClass)
3591 takeit = FALSE;
3594 if((ti = FindTagItem(DA_SubClass, tags)))
3596 if(ti->ti_Data != pd->pd_DevSubClass)
3598 takeit = FALSE;
3601 if((ti = FindTagItem(DA_Protocol, tags)))
3603 if(ti->ti_Data != pd->pd_DevProto)
3605 takeit = FALSE;
3608 if((ti = FindTagItem(DA_Version, tags)))
3610 if(ti->ti_Data != pd->pd_DevVers)
3612 takeit = FALSE;
3615 if((ti = FindTagItem(DA_SerialNumber, tags)))
3617 if(strcmp((STRPTR) ti->ti_Data, pd->pd_SerNumStr))
3619 takeit = FALSE;
3622 if((ti = FindTagItem(DA_ProductName, tags)))
3624 if(strcmp((STRPTR) ti->ti_Data, pd->pd_ProductStr))
3626 takeit = FALSE;
3629 if((ti = FindTagItem(DA_Manufacturer, tags)))
3631 if(strcmp((STRPTR) ti->ti_Data, pd->pd_MnfctrStr))
3633 takeit = FALSE;
3636 if((ti = FindTagItem(DA_IDString, tags)))
3638 if(strcmp((STRPTR) ti->ti_Data, pd->pd_IDString))
3640 takeit = FALSE;
3643 if((ti = FindTagItem(DA_Binding, tags)))
3645 if(ti->ti_Data != (IPTR) pd->pd_DevBinding)
3647 takeit = FALSE;
3650 if((ti = FindTagItem(DA_HubDevice, tags)))
3652 if(ti->ti_Data != (IPTR) pd->pd_Hub)
3654 takeit = FALSE;
3658 if(takeit)
3660 return(pd);
3663 return(NULL);
3664 AROS_LIBFUNC_EXIT
3666 /* \\\ */
3668 /* *** Hardware *** */
3670 /* /// "pFindHardware()" */
3671 struct PsdHardware * pFindHardware(LIBBASETYPEPTR ps, STRPTR name, ULONG unit)
3673 struct PsdHardware *phw;
3674 Forbid();
3675 while(*name)
3677 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3678 while(phw->phw_Node.ln_Succ)
3680 if((phw->phw_Unit == unit) && (!strcmp(phw->phw_DevName, name)))
3682 Permit();
3683 return(phw);
3685 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3689 if((*name == '/') || (*name == ':'))
3691 ++name;
3692 break;
3694 } while(*(++name));
3696 Permit();
3697 return(NULL);
3699 /* \\\ */
3701 /* /// "psdEnumerateHardware()" */
3702 AROS_LH1(struct PsdDevice *, psdEnumerateHardware,
3703 AROS_LHA(struct PsdHardware *, phw, A0),
3704 LIBBASETYPEPTR, ps, 14, psd)
3706 AROS_LIBFUNC_INIT
3707 struct PsdDevice *pd = NULL;
3708 struct PsdPipe *pp;
3709 struct MsgPort *mp;
3710 #ifdef AROS_USB30_CODE
3711 LONG ioerr;
3712 #endif
3713 KPRINTF(2, ("psdEnumerateHardware(%p)\n", phw));
3715 if((mp = CreateMsgPort()))
3717 Forbid();
3718 if((pd = psdAllocDevice(phw)))
3720 Permit();
3721 if((pp = psdAllocPipe(pd, mp, NULL)))
3723 //pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
3724 //pp->pp_IOReq.iouh_NakTimeout = 1000;
3725 pd->pd_Flags |= PDFF_CONNECTED;
3727 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_USBRESET;
3728 #ifdef AROS_USB30_CODE
3729 ioerr = psdDoPipe(pp, NULL, 0);
3730 if(ioerr == UHIOERR_HOSTERROR) {
3731 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "UHCMD_USBRESET reset failed.");
3732 psdFreePipe(pp);
3733 pFreeBindings(ps, pd);
3734 pFreeDevice(ps, pd);
3735 DeleteMsgPort(mp);
3736 return(NULL);
3738 #else
3739 psdDoPipe(pp, NULL, 0);
3740 #endif
3741 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3742 psdDelayMS(100); // wait for root hub to settle
3743 if(psdEnumerateDevice(pp))
3745 KPRINTF(1, ("Enumeration finished!\n"));
3746 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Root hub has been enumerated.");
3747 psdFreePipe(pp);
3748 DeleteMsgPort(mp);
3749 phw->phw_RootDevice = pd;
3750 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
3751 return(pd);
3753 psdFreePipe(pp);
3755 pFreeBindings(ps, pd);
3756 pFreeDevice(ps, pd);
3757 } else {
3758 Permit();
3760 DeleteMsgPort(mp);
3762 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Root hub enumeration failed. Blame your hardware driver programmer.");
3763 return(NULL);
3764 AROS_LIBFUNC_EXIT
3766 /* \\\ */
3768 /* /// "psdRemHardware()" */
3769 AROS_LH1(void, psdRemHardware,
3770 AROS_LHA(struct PsdHardware *, phw, A0),
3771 LIBBASETYPEPTR, ps, 13, psd)
3773 AROS_LIBFUNC_INIT
3774 struct PsdDevice *pd;
3775 ULONG cnt;
3777 KPRINTF(5, ("FreeHardware(%p)\n", phw));
3779 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3780 while(pd->pd_Node.ln_Succ)
3782 pFreeBindings(ps, pd);
3783 pFreeDevice(ps, pd);
3784 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3785 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3787 cnt = 0;
3788 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3789 while(pd->pd_Node.ln_Succ)
3791 if(pd->pd_UseCnt)
3793 KPRINTF(20, ("Can't remove device, usecnt %ld\n", pd->pd_UseCnt));
3794 if(++cnt == 5)
3796 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3797 "Can't remove device '%s', there are still %ld pipes in use...",
3798 pd->pd_ProductStr, pd->pd_UseCnt);
3800 if(++cnt == 30)
3802 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3803 "Okay, going down with device '%s' anyway, maybe the driver crashed?",
3804 pd->pd_ProductStr);
3805 pd->pd_UseCnt = 0;
3806 cnt--;
3807 } else {
3808 psdDelayMS(1000);
3810 } else {
3811 pFreeDevice(ps, pd);
3812 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3814 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3817 Forbid();
3818 /* Note that the subtask unlinks the hardware! */
3819 phw->phw_ReadySignal = SIGB_SINGLE;
3820 phw->phw_ReadySigTask = FindTask(NULL);
3821 if(phw->phw_Task)
3823 Signal(phw->phw_Task, SIGBREAKF_CTRL_C);
3825 Permit();
3826 while(phw->phw_Task)
3828 Wait(1L<<phw->phw_ReadySignal);
3830 //FreeSignal(phw->phw_ReadySignal);
3831 KPRINTF(1, ("FreeHardware(%p) freevec name\n", phw));
3832 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3833 "Removed hardware %s/%ld. Bye bye!",
3834 phw->phw_DevName, phw->phw_Unit);
3835 psdFreeVec(phw->phw_DevName);
3836 psdFreeVec(phw->phw_ProductName);
3837 psdFreeVec(phw->phw_Manufacturer);
3838 psdFreeVec(phw->phw_Description);
3839 psdFreeVec(phw->phw_Copyright);
3840 psdFreeVec(phw);
3841 psdSendEvent(EHMB_REMHARDWARE, phw, NULL);
3842 KPRINTF(1, ("FreeHardware(%p) done\n", phw));
3843 AROS_LIBFUNC_EXIT
3845 /* \\\ */
3847 /* /// "psdAddHardware()" */
3848 AROS_LH2(struct PsdHardware *,psdAddHardware,
3849 AROS_LHA(STRPTR, name, A0),
3850 AROS_LHA(ULONG, unit, D0),
3851 LIBBASETYPEPTR, ps, 12, psd)
3853 AROS_LIBFUNC_INIT
3854 struct PsdHardware *phw;
3855 char buf[64];
3856 struct Task *tmptask;
3857 KPRINTF(5, ("psdAddHardware(%s, %ld)\n", name, unit));
3859 if((phw = psdAllocVec(sizeof(struct PsdHardware))))
3861 NewList(&phw->phw_Devices);
3862 NewList(&phw->phw_DeadDevices);
3863 phw->phw_Unit = unit;
3864 phw->phw_Base = ps;
3865 if((phw->phw_Node.ln_Name = phw->phw_DevName = psdCopyStr(name)))
3867 psdSafeRawDoFmt(buf, 64, "usbhw<%s/%ld>", name, unit);
3868 phw->phw_ReadySignal = SIGB_SINGLE;
3869 phw->phw_ReadySigTask = FindTask(NULL);
3870 SetSignal(0, SIGF_SINGLE); // clear single bit
3871 if((tmptask = psdSpawnSubTask(buf, pDeviceTask, phw)))
3873 psdBorrowLocksWait(tmptask, 1UL<<phw->phw_ReadySignal);
3874 if(phw->phw_Task)
3876 phw->phw_ReadySigTask = NULL;
3877 //FreeSignal(phw->phw_ReadySignal);
3878 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3879 "New hardware %s/%ld added (%s).",
3880 phw->phw_DevName,
3881 phw->phw_Unit,
3882 phw->phw_ProductName);
3883 psdSendEvent(EHMB_ADDHARDWARE, phw, NULL);
3884 return(phw);
3887 phw->phw_ReadySigTask = NULL;
3888 //FreeSignal(phw->phw_ReadySignal);
3889 psdFreeVec(phw->phw_DevName);
3891 psdFreeVec(phw);
3893 return(NULL);
3894 AROS_LIBFUNC_EXIT
3896 /* \\\ */
3898 /* /// "psdCalculatePower()" */
3899 AROS_LH1(void, psdCalculatePower,
3900 AROS_LHA(struct PsdHardware *, phw, A0),
3901 LIBBASETYPEPTR, ps, 78, psd)
3903 AROS_LIBFUNC_INIT
3904 struct PsdDevice *roothub = NULL;
3905 struct PsdDevice *pd;
3907 psdLockReadPBase();
3908 /* goto root */
3909 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3910 while(pd->pd_Node.ln_Succ)
3912 if(!pd->pd_Hub)
3914 roothub = pd;
3915 break;
3917 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
3919 if(!roothub)
3921 psdUnlockPBase();
3922 return;
3924 roothub->pd_PowerDrain = 0;
3925 roothub->pd_PowerSupply = 500;
3927 /* calculate drain */
3928 pPowerRecurseDrain(ps, roothub);
3930 /* calculate supply */
3931 pPowerRecurseSupply(ps, roothub);
3932 psdUnlockPBase();
3933 AROS_LIBFUNC_EXIT
3935 /* \\\ */
3937 /* *** Pipes *** */
3939 /* /// "psdAllocPipe()" */
3940 AROS_LH3(struct PsdPipe *, psdAllocPipe,
3941 AROS_LHA(struct PsdDevice *, pd, A0),
3942 AROS_LHA(struct MsgPort *, mp, A1),
3943 AROS_LHA(struct PsdEndpoint *, pep, A2),
3944 LIBBASETYPEPTR, ps, 24, psd)
3946 AROS_LIBFUNC_INIT
3947 struct PsdPipe *pp;
3948 struct PsdDevice *hubpd;
3950 KPRINTF(2, ("psdAllocPipe(%p, %p, %p)\n", pd, mp, pep));
3951 if(!mp || !pd)
3953 return(NULL);
3955 if(pep && (pep->pep_TransType == USEAF_ISOCHRONOUS) && (!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_ISO)))
3957 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support iso transfers. Sorry.");
3958 return(NULL);
3961 if((pp = psdAllocVec(sizeof(struct PsdPipe))))
3963 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
3964 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = mp;
3965 pp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
3966 pp->pp_Device = pd;
3967 pp->pp_Endpoint = pep;
3968 pp->pp_IOReq = *(pd->pd_Hardware->phw_RootIOReq);
3969 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
3970 if(pd->pd_Flags & PDFF_LOWSPEED)
3972 pp->pp_IOReq.iouh_Flags |= UHFF_LOWSPEED;
3974 if(pd->pd_Flags & PDFF_HIGHSPEED)
3976 pp->pp_IOReq.iouh_Flags |= UHFF_HIGHSPEED;
3977 if(pep)
3979 switch(pep->pep_NumTransMuFr)
3981 case 2:
3982 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_2;
3983 break;
3984 case 3:
3985 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_3;
3986 break;
3988 default:
3989 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3991 } else {
3992 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3995 #ifdef AROS_USB30_CODE
3996 if(pd->pd_Flags & PDFF_SUPERSPEED)
3998 pp->pp_IOReq.iouh_Flags |= UHFF_SUPERSPEED;
4000 #endif
4001 if(pd->pd_Flags & PDFF_NEEDSSPLIT)
4003 /* USB1.1 device connected to a USB2.0 hub */
4004 pp->pp_IOReq.iouh_Flags |= UHFF_SPLITTRANS;
4005 hubpd = pd->pd_Hub;
4006 pp->pp_IOReq.iouh_SplitHubPort = pd->pd_HubPort;
4007 // find the root USB 2.0 hub in the tree
4008 while(hubpd && !(hubpd->pd_Flags & PDFF_HIGHSPEED))
4010 pp->pp_IOReq.iouh_SplitHubPort = hubpd->pd_HubPort;
4011 hubpd = hubpd->pd_Hub;
4013 if(!hubpd)
4015 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Internal error obtaining split transaction hub!");
4016 psdFreeVec(pp);
4017 return(NULL);
4019 pp->pp_IOReq.iouh_Flags |= (hubpd->pd_HubThinkTime<<UHFS_THINKTIME);
4020 pp->pp_IOReq.iouh_SplitHubAddr = hubpd->pd_DevAddr;
4022 if(pep)
4024 switch(pep->pep_TransType)
4026 case USEAF_CONTROL:
4027 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4028 break;
4029 case USEAF_ISOCHRONOUS:
4030 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ISOXFER;
4031 break;
4032 case USEAF_BULK:
4033 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_BULKXFER;
4034 break;
4035 case USEAF_INTERRUPT:
4036 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_INTXFER;
4037 break;
4038 default:
4039 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
4040 "AllocPipe(): Illegal transfer type %ld",
4041 pep->pep_TransType);
4042 KPRINTF(20, ("Illegal transfer type for endpoint!"));
4043 psdFreeVec(pp);
4044 return(NULL);
4047 pp->pp_IOReq.iouh_Dir = (pep->pep_Direction ? UHDIR_IN : UHDIR_OUT);
4048 pp->pp_IOReq.iouh_Endpoint = pep->pep_EPNum;
4049 pp->pp_IOReq.iouh_MaxPktSize = pep->pep_MaxPktSize;
4050 pp->pp_IOReq.iouh_Interval = pep->pep_Interval;
4051 } else {
4052 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4053 pp->pp_IOReq.iouh_Dir = UHDIR_SETUP;
4054 pp->pp_IOReq.iouh_Endpoint = 0;
4055 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0;
4057 pd->pd_UseCnt++;
4058 return(pp);
4060 return(NULL);
4061 AROS_LIBFUNC_EXIT
4063 /* \\\ */
4065 /* /// "psdFreePipe()" */
4066 AROS_LH1(void, psdFreePipe,
4067 AROS_LHA(struct PsdPipe *, pp, A1),
4068 LIBBASETYPEPTR, ps, 25, psd)
4070 AROS_LIBFUNC_INIT
4071 struct PsdDevice *pd;
4072 if(!pp)
4074 return;
4076 KPRINTF(2, ("psdFreePipe(%p)\n", pp));
4077 pd = pp->pp_Device;
4079 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4081 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4082 "Tried to free pipe on %s that was still pending!", pd->pd_ProductStr);
4083 psdAbortPipe(pp);
4084 psdWaitPipe(pp);
4087 if(!(--pd->pd_UseCnt) && (pd->pd_Flags & PDFF_DELEXPUNGE))
4089 KPRINTF(20, ("Finally getting rid of device %s\n", pd->pd_ProductStr));
4090 pFreeDevice(ps, pd);
4091 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
4094 psdFreeVec(pp);
4095 AROS_LIBFUNC_EXIT
4097 /* \\\ */
4099 /* /// "psdPipeSetup()" */
4100 AROS_LH5(void, psdPipeSetup,
4101 AROS_LHA(struct PsdPipe *, pp, A1),
4102 AROS_LHA(UWORD, rt, D0),
4103 AROS_LHA(UWORD, rq, D1),
4104 AROS_LHA(UWORD, val, D2),
4105 AROS_LHA(UWORD, idx, D3),
4106 LIBBASETYPEPTR, ps, 26, psd)
4108 AROS_LIBFUNC_INIT
4109 struct UsbSetupData *usd = &pp->pp_IOReq.iouh_SetupData;
4111 KPRINTF(1, ("psdSetupPipe(%p, (%02lx %02lx %04lx %04lx))\n",
4112 pp, rt, rq, val, idx));
4113 usd->bmRequestType = rt;
4114 usd->bRequest = rq;
4115 usd->wValue = AROS_WORD2LE(val);
4116 usd->wIndex = AROS_WORD2LE(idx);
4117 AROS_LIBFUNC_EXIT
4119 /* \\\ */
4121 /* /// "psdDoPipe()" */
4122 AROS_LH3(LONG, psdDoPipe,
4123 AROS_LHA(struct PsdPipe *, pp, A1),
4124 AROS_LHA(APTR, data, A0),
4125 AROS_LHA(ULONG, len, D0),
4126 LIBBASETYPEPTR, ps, 27, psd)
4128 AROS_LIBFUNC_INIT
4129 struct PsdDevice *pd = pp->pp_Device;
4130 KPRINTF(200, ("psdDoPipe(%p, %p, %ld)\n", pp, data, len));
4132 if(pd->pd_Flags & PDFF_CONNECTED)
4134 if(pd->pd_Flags & PDFF_SUSPENDED)
4136 // make sure the device is up and running before trying to send a new pipe
4137 psdResumeDevice(pd);
4140 pp->pp_IOReq.iouh_Data = data;
4141 pp->pp_IOReq.iouh_Length = len;
4142 if(!pp->pp_Endpoint)
4144 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4146 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4147 ++pd->pd_IOBusyCount;
4148 GetSysTime((APTR) &pd->pd_LastActivity);
4149 return(psdWaitPipe(pp));
4150 } else {
4151 psdDelayMS(50);
4152 pp->pp_IOReq.iouh_Actual = 0;
4153 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4154 return(pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT);
4156 AROS_LIBFUNC_EXIT
4158 /* \\\ */
4160 /* /// "psdSendPipe()" */
4161 AROS_LH3(void, psdSendPipe,
4162 AROS_LHA(struct PsdPipe *, pp, A1),
4163 AROS_LHA(APTR, data, A0),
4164 AROS_LHA(ULONG, len, D0),
4165 LIBBASETYPEPTR, ps, 28, psd)
4167 AROS_LIBFUNC_INIT
4168 struct PsdDevice *pd = pp->pp_Device;
4169 KPRINTF(200, ("psdSendPipe(%p, %p, %ld)\n", pp, data, len));
4170 if(pd->pd_Flags & PDFF_CONNECTED)
4172 if(pd->pd_Flags & PDFF_SUSPENDED)
4174 // make sure the device is up and running before trying to send a new pipe
4175 psdResumeDevice(pd);
4178 pp->pp_IOReq.iouh_Data = data;
4179 pp->pp_IOReq.iouh_Length = len;
4180 if(!pp->pp_Endpoint)
4182 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4184 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4185 GetSysTime((APTR) &pd->pd_LastActivity);
4186 ++pd->pd_IOBusyCount;
4187 } else {
4188 psdDelayMS(50);
4189 pp->pp_IOReq.iouh_Actual = 0;
4190 //pp->pp_Msg.mn_Node.ln_Type = NT_REPLYMSG;
4191 pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT;
4192 ReplyMsg(&pp->pp_Msg);
4193 ++pd->pd_IOBusyCount;
4195 AROS_LIBFUNC_EXIT
4197 /* \\\ */
4199 /* /// "psdAbortPipe()" */
4200 AROS_LH1(void, psdAbortPipe,
4201 AROS_LHA(struct PsdPipe *, pp, A1),
4202 LIBBASETYPEPTR, ps, 29, psd)
4204 AROS_LIBFUNC_INIT
4205 struct PsdPipe *npp;
4207 KPRINTF(5, ("psdAbortPipe(%p)\n", pp));
4208 if(pp->pp_Msg.mn_Node.ln_Type != NT_MESSAGE)
4210 KPRINTF(5, ("Nothing to abort %02lx\n", pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type));
4211 return;
4213 if((npp = psdAllocVec(sizeof(struct PsdPipe))))
4215 //npp->pp_Msg.mn_Node.ln_Type = NT_MESSAGE;
4216 npp->pp_Device = pp->pp_Device;
4217 npp->pp_MsgPort = npp->pp_Msg.mn_ReplyPort = pp->pp_MsgPort;
4218 npp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
4220 npp->pp_AbortPipe = pp;
4221 PutMsg(&pp->pp_Device->pd_Hardware->phw_TaskMsgPort, &npp->pp_Msg);
4222 psdWaitPipe(npp);
4223 psdFreeVec(npp);
4225 AROS_LIBFUNC_EXIT
4227 /* \\\ */
4229 /* /// "psdWaitPipe()" */
4230 AROS_LH1(LONG, psdWaitPipe,
4231 AROS_LHA(struct PsdPipe *, pp, A1),
4232 LIBBASETYPEPTR, ps, 30, psd)
4234 AROS_LIBFUNC_INIT
4235 ULONG sigs = 0;
4236 struct PsdDevice *pd = pp->pp_Device;
4237 LONG ioerr;
4238 KPRINTF(5, ("psdWaitPipe(%p)\n", pp));
4239 while(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4241 KPRINTF(5, ("ln_Type = %02lx\n", pp->pp_Msg.mn_Node.ln_Type));
4242 sigs |= Wait(1L<<pp->pp_MsgPort->mp_SigBit);
4243 KPRINTF(5, ("sigs = %p\n", sigs));
4245 #if 1 // broken?
4246 Forbid();
4247 if(pp->pp_Msg.mn_Node.ln_Type == NT_REPLYMSG)
4249 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4250 Remove(&pp->pp_Msg.mn_Node);
4252 //if(pp->pp_MsgPort->mp_MsgList.lh_Head->ln_Succ)
4254 // avoid signals getting lost for other messages arriving.
4255 SetSignal(sigs, sigs);
4257 Permit();
4258 #else
4259 Forbid();
4260 Remove(&pp->pp_Msg.mn_Node);
4261 Permit();
4262 #endif
4263 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4264 switch(ioerr)
4266 case UHIOERR_TIMEOUT:
4267 pd->pd_DeadCount++;
4268 // fall through
4269 case UHIOERR_NAKTIMEOUT:
4270 pd->pd_DeadCount++;
4271 case UHIOERR_CRCERROR:
4272 pd->pd_DeadCount++;
4273 break;
4274 case UHIOERR_RUNTPACKET:
4275 default:
4276 if(pd->pd_DeadCount)
4278 pd->pd_DeadCount >>= 1;
4279 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4280 "Device %s starts recovering with %s (%ld)!",
4281 pd->pd_ProductStr,
4282 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
4285 KPRINTF(200, ("psdWaitPipe(%p)=%ld\n", pp, ioerr));
4286 --pd->pd_IOBusyCount;
4287 GetSysTime((APTR) &pd->pd_LastActivity);
4289 if((pd->pd_DeadCount > 19) || ((pd->pd_DeadCount > 14) && (pd->pd_Flags & (PDFF_HASDEVADDR|PDFF_HASDEVDESC))))
4291 if(!(pd->pd_Flags & PDFF_DEAD))
4293 pd->pd_Flags |= PDFF_DEAD;
4294 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4295 "Device %s probably dropped dead!", pd->pd_ProductStr);
4297 psdSendEvent(EHMB_DEVICEDEAD, pp->pp_Device, NULL);
4299 } else {
4300 if((!pd->pd_DeadCount) && ((pd->pd_Flags & (PDFF_DEAD|PDFF_CONNECTED)) == (PDFF_DEAD|PDFF_CONNECTED)))
4302 pd->pd_Flags &= ~PDFF_DEAD;
4303 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4304 "Uuuhuuuhh, the zombie %s returned from the dead!", pd->pd_ProductStr);
4307 return(ioerr);
4308 AROS_LIBFUNC_EXIT
4310 /* \\\ */
4312 /* /// "psdCheckPipe()" */
4313 AROS_LH1(struct PsdPipe *, psdCheckPipe,
4314 AROS_LHA(struct PsdPipe *, pp, A1),
4315 LIBBASETYPEPTR, ps, 71, psd)
4317 AROS_LIBFUNC_INIT
4318 KPRINTF(5, ("psdCheckPipe(%p)\n", pp));
4319 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4321 return(NULL);
4323 return(pp);
4324 AROS_LIBFUNC_EXIT
4326 /* \\\ */
4328 /* /// "psdGetPipeActual()" */
4329 AROS_LH1(ULONG, psdGetPipeActual,
4330 AROS_LHA(struct PsdPipe *, pp, A1),
4331 LIBBASETYPEPTR, ps, 31, psd)
4333 AROS_LIBFUNC_INIT
4334 KPRINTF(1, ("psdGetPipeActual(%p)\n", pp));
4335 return(pp->pp_IOReq.iouh_Actual);
4336 AROS_LIBFUNC_EXIT
4338 /* \\\ */
4340 /* /// "psdGetPipeError()" */
4341 AROS_LH1(LONG, psdGetPipeError,
4342 AROS_LHA(struct PsdPipe *, pp, A1),
4343 LIBBASETYPEPTR, ps, 32, psd)
4345 AROS_LIBFUNC_INIT
4346 KPRINTF(1, ("psdGetPipeError(%p)\n", pp));
4347 return((LONG) pp->pp_IOReq.iouh_Req.io_Error);
4348 AROS_LIBFUNC_EXIT
4350 /* \\\ */
4352 /* *** Streams *** */
4354 /* /// "psdOpenStreamA()" */
4355 AROS_LH2(struct PsdPipeStream *, psdOpenStreamA,
4356 AROS_LHA(struct PsdEndpoint *, pep, A0),
4357 AROS_LHA(struct TagItem *, tags, A1),
4358 LIBBASETYPEPTR, ps, 72, psd)
4360 AROS_LIBFUNC_INIT
4361 struct PsdPipeStream *pps;
4363 KPRINTF(2, ("psdOpenStream(%p, %p)\n", pep, tags));
4364 if(!pep)
4366 return(NULL);
4368 if((pps = psdAllocVec(sizeof(struct PsdPipeStream))))
4370 pps->pps_Device = pep->pep_Interface->pif_Config->pc_Device;
4371 pps->pps_Endpoint = pep;
4372 NewList(&pps->pps_FreePipes);
4373 NewList(&pps->pps_ReadyPipes);
4374 InitSemaphore(&pps->pps_AccessLock);
4375 pps->pps_NakTimeoutTime = 5000;
4376 if(pep->pep_Direction)
4378 /* Defaults for IN */
4379 pps->pps_NumPipes = 4;
4380 pps->pps_Flags = PSFF_READAHEAD|PSFF_BUFFERREAD|PSFF_ALLOWRUNT;
4381 pps->pps_BufferSize = 32*pps->pps_Endpoint->pep_MaxPktSize;
4382 } else {
4383 /* Defaults for OUT */
4384 pps->pps_NumPipes = 4;
4385 pps->pps_Flags = PSFF_NOSHORTPKT;
4386 pps->pps_BufferSize = 4*pps->pps_Endpoint->pep_MaxPktSize;
4389 psdSetAttrsA(PGA_PIPESTREAM, pps, tags);
4390 if(!pps->pps_Pipes)
4392 psdCloseStream(pps);
4393 pps = NULL;
4395 return(pps);
4397 return(NULL);
4398 AROS_LIBFUNC_EXIT
4400 /* \\\ */
4402 /* /// "psdCloseStream()" */
4403 AROS_LH1(void, psdCloseStream,
4404 AROS_LHA(struct PsdPipeStream *, pps, A1),
4405 LIBBASETYPEPTR, ps, 73, psd)
4407 AROS_LIBFUNC_INIT
4408 struct PsdPipe *pp;
4409 ULONG cnt;
4411 KPRINTF(2, ("psdCloseStream(%p)\n", pps));
4412 if(!pps)
4414 return;
4416 psdStreamFlush(pps);
4417 ObtainSemaphore(&pps->pps_AccessLock);
4418 if(pps->pps_Pipes)
4420 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4422 pp = pps->pps_Pipes[cnt];
4423 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
4425 KPRINTF(1, ("Abort %ld\n", cnt));
4426 psdAbortPipe(pp);
4427 KPRINTF(1, ("Wait %ld\n", cnt));
4428 psdWaitPipe(pp);
4430 KPRINTF(1, ("Free %ld\n", cnt));
4431 psdFreePipe(pp);
4433 psdFreeVec(pps->pps_Pipes);
4434 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
4436 DeleteMsgPort(pps->pps_MsgPort);
4439 psdFreeVec(pps->pps_Buffer);
4440 ReleaseSemaphore(&pps->pps_AccessLock);
4441 psdFreeVec(pps);
4442 AROS_LIBFUNC_EXIT
4444 /* \\\ */
4446 /* /// "psdStreamRead()" */
4447 AROS_LH3(LONG, psdStreamRead,
4448 AROS_LHA(struct PsdPipeStream *, pps, A1),
4449 AROS_LHA(UBYTE *, buffer, A0),
4450 AROS_LHA(LONG, length, D0),
4451 LIBBASETYPEPTR, ps, 74, psd)
4453 AROS_LIBFUNC_INIT
4454 struct PsdPipe *pp;
4455 ULONG cnt;
4456 LONG ioerr;
4457 LONG remlen;
4458 BOOL term = FALSE;
4459 LONG actual = 0;
4460 ULONG sigmask;
4462 UBYTE *bufptr;
4463 UBYTE *srcptr;
4464 UBYTE *tarrptr;
4465 ULONG tcnt;
4466 UBYTE cchar;
4468 KPRINTF(2, ("psdStreamRead(%p, %p, %ld)\n", pps, buffer, length));
4469 if(!pps)
4471 return(-1);
4473 ObtainSemaphore(&pps->pps_AccessLock);
4474 KPRINTF(2, ("Sema\n"));
4475 pps->pps_Error = 0;
4476 if((!pps->pps_Pipes) || (!pps->pps_Endpoint->pep_Direction))
4478 KPRINTF(2, ("Wrong direction!\n"));
4479 pps->pps_Error = UHIOERR_BADPARAMS;
4480 ReleaseSemaphore(&pps->pps_AccessLock);
4481 return(-1);
4483 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4485 if(pps->pps_Flags & PSFF_BUFFERREAD)
4487 /* buffered reading */
4490 /* check for incoming packets */
4491 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4493 KPRINTF(1, ("PktBack(%p, %p, %ld/%ld)=%ld\n",
4494 pp, pp->pp_IOReq.iouh_Data, pp->pp_IOReq.iouh_Actual,
4495 pp->pp_IOReq.iouh_Length, pp->pp_IOReq.iouh_Req.io_Error));
4497 pps->pps_ReqBytes -= pp->pp_IOReq.iouh_Length;
4498 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4499 if((ioerr == UHIOERR_NAKTIMEOUT) && pp->pp_IOReq.iouh_Actual)
4501 ioerr = 0;
4504 if(ioerr)
4506 pps->pps_Error = ioerr;
4507 term = TRUE;
4508 if(ioerr != UHIOERR_TIMEOUT)
4510 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4511 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4512 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4514 /* stop automatic queueing */
4515 pps->pps_Flags &= ~PSFF_READAHEAD;
4516 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4517 } else {
4518 /* successfully received packet */
4519 pps->pps_BytesPending += pp->pp_IOReq.iouh_Actual;
4520 AddTail(&pps->pps_ReadyPipes, &pp->pp_Msg.mn_Node);
4523 if(length == -1) /* get all that's there (STRONGLY DISCOURAGED! Might cause buffer overflows) */
4525 length = pps->pps_BytesPending;
4527 /* check for buffered data */
4528 while(length && pps->pps_BytesPending)
4530 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4531 if(!pp->pp_Msg.mn_Node.ln_Succ) /* debug */
4533 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) "StreamRead", "Readqueue empty!");
4534 ReleaseSemaphore(&pps->pps_AccessLock);
4535 return(-1);
4537 if(pp->pp_IOReq.iouh_Actual < pps->pps_Offset)
4539 psdAddErrorMsg(RETURN_FAIL, (STRPTR) "StreamRead",
4540 "Actual %ld < offset %ld!", pp->pp_IOReq.iouh_Actual, pps->pps_Offset);
4541 ReleaseSemaphore(&pps->pps_AccessLock);
4542 return(-1);
4544 remlen = pp->pp_IOReq.iouh_Actual - pps->pps_Offset;
4545 if(length < remlen)
4547 KPRINTF(1, ("PktBit(%p, %p, %ld)\n", pp, buffer, length));
4548 remlen = length;
4549 } else {
4550 KPRINTF(1, ("PktRem(%p, %p, %ld)\n", pp, buffer, remlen));
4552 /* copy packet */
4553 if(pp->pp_Flags & PFF_INPLACE)
4555 KPRINTF(1, ("PktRemIP(%p, %p, %ld)\n", pp, buffer, remlen));
4556 } else {
4557 if(pps->pps_TermArray)
4559 /* EOF Mode */
4560 KPRINTF(1, ("PktCpyEOF(%p, %p, %ld)\n", pp, buffer, remlen));
4561 bufptr = buffer;
4562 srcptr = &(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]);
4563 tarrptr = pps->pps_TermArray;
4564 cnt = remlen;
4565 remlen = 0;
4566 if(cnt)
4570 cchar = *bufptr++ = *srcptr++;
4571 remlen++;
4572 tcnt = 0;
4575 if(cchar < tarrptr[tcnt])
4577 break;
4579 else if(cchar == tarrptr[tcnt])
4581 cnt = 1;
4582 term = TRUE;
4583 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, remlen));
4584 break;
4586 if(tcnt < 7)
4588 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4590 break;
4593 } while(++tcnt < 8);
4594 } while(--cnt);
4596 } else {
4597 KPRINTF(1, ("PktCpy(%p, %p, %ld)\n", pp, buffer, remlen));
4598 /* quick non-eof mode */
4599 CopyMem(&(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]), buffer, remlen);
4602 actual += remlen;
4603 length -= remlen;
4604 buffer += remlen;
4605 pps->pps_BytesPending -= remlen;
4606 pps->pps_Offset += remlen;
4607 /* end of packet reached? */
4608 if(pps->pps_Offset == pp->pp_IOReq.iouh_Actual)
4610 pps->pps_Offset = 0;
4611 Remove(&pp->pp_Msg.mn_Node);
4612 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4613 /* check for short packet */
4614 if((pps->pps_Flags & PSFF_SHORTTERM) && (pp->pp_IOReq.iouh_Actual % pp->pp_IOReq.iouh_MaxPktSize))
4616 term = TRUE;
4619 if(term)
4621 break;
4624 /* start sending out requests */
4625 remlen = length;
4626 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4627 if(!(pps->pps_BytesPending || pps->pps_ReqBytes || pps->pps_TermArray || (length < pps->pps_BufferSize)))
4629 /* faster non-buffered mode */
4630 if(pp->pp_Msg.mn_Node.ln_Succ)
4632 pp->pp_Flags |= PFF_INPLACE;
4633 Remove(&pp->pp_Msg.mn_Node);
4634 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4635 KPRINTF(1, ("OutFast(%p, %p, %ld/%ld)\n",
4636 pp, buffer, remlen, length));
4637 psdSendPipe(pp, buffer, remlen);
4638 pps->pps_ReqBytes += remlen;
4639 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4642 /* slower buffered mode */
4643 while(pp->pp_Msg.mn_Node.ln_Succ && ((remlen > pps->pps_ReqBytes) || (pps->pps_Flags & PSFF_READAHEAD)))
4645 pp->pp_Flags &= ~PFF_INPLACE;
4646 Remove(&pp->pp_Msg.mn_Node);
4647 if((pps->pps_Flags & PSFF_READAHEAD) || (remlen % pp->pp_IOReq.iouh_MaxPktSize))
4649 KPRINTF(1, ("OutSlow(%p, %p, %ld)\n",
4650 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], pps->pps_BufferSize));
4651 remlen = pps->pps_BufferSize;
4652 } else {
4653 KPRINTF(1, ("OutExact(%p, %p, %ld)\n",
4654 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen));
4656 psdSendPipe(pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen);
4657 pps->pps_ReqBytes += remlen;
4658 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4660 if((!length) || (pps->pps_Flags & PSFF_DONOTWAIT))
4662 term = TRUE;
4664 if(!term)
4666 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4667 KPRINTF(1, ("WaitPort (%p)\n", sigmask));
4668 sigmask = Wait(sigmask);
4669 KPRINTF(1, ("Wait back (%p)\n", sigmask));
4670 if(sigmask & pps->pps_AbortSigMask)
4672 KPRINTF(1, ("Aborted!\n"));
4673 term = TRUE;
4674 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4677 } while(!term);
4678 } else {
4679 /* plain reading (might lose data) */
4680 if(pps->pps_TermArray || (pps->pps_Flags & PSFF_READAHEAD))
4682 psdAddErrorMsg0(RETURN_WARN, (STRPTR) "StreamRead", "This mode combination for the stream is not supported!");
4684 /* start sending out requests */
4685 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4686 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4688 ioerr = psdDoPipe(pp, buffer, length);
4689 if(ioerr)
4691 pps->pps_Error = ioerr;
4692 if(ioerr != UHIOERR_TIMEOUT)
4694 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4695 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4696 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4699 actual = pp->pp_IOReq.iouh_Actual;
4703 ReleaseSemaphore(&pps->pps_AccessLock);
4704 return(actual);
4705 AROS_LIBFUNC_EXIT
4707 /* \\\ */
4709 /* /// "psdStreamWrite()" */
4710 AROS_LH3(LONG, psdStreamWrite,
4711 AROS_LHA(struct PsdPipeStream *, pps, A1),
4712 AROS_LHA(UBYTE *, buffer, A0),
4713 AROS_LHA(LONG, length, D0),
4714 LIBBASETYPEPTR, ps, 75, psd)
4716 AROS_LIBFUNC_INIT
4717 struct PsdPipe *pp;
4718 struct PsdPipe *newpp;
4719 ULONG cnt;
4720 LONG ioerr;
4721 LONG remlen;
4722 LONG actual = 0;
4723 ULONG sigmask;
4725 UBYTE *bufptr;
4726 UBYTE *srcptr;
4727 UBYTE *tarrptr;
4728 ULONG tcnt;
4729 UBYTE cchar;
4731 KPRINTF(2, ("psdStreamWrite(%p, %p, %ld)\n", pps, buffer, length));
4732 if(!pps)
4734 return(-1);
4736 ObtainSemaphore(&pps->pps_AccessLock);
4737 pps->pps_Error = 0;
4738 if((!pps->pps_Pipes) || pps->pps_Endpoint->pep_Direction)
4740 KPRINTF(2, ("Wrong direction!\n"));
4741 pps->pps_Error = UHIOERR_BADPARAMS;
4742 ReleaseSemaphore(&pps->pps_AccessLock);
4743 return(-1);
4745 if(length == -1) /* null terminated string mode */
4747 KPRINTF(2, ("EOL mode!\n"));
4748 length = strlen(buffer);
4750 if((tarrptr = pps->pps_TermArray)) /* EOF Mode */
4752 KPRINTF(1, ("EOFSearch(%p, %ld)\n", buffer, length));
4753 srcptr = buffer;
4754 cnt = length;
4755 length = 0;
4756 if(cnt)
4760 cchar = *srcptr++;
4761 length++;
4762 tcnt = 0;
4765 if(cchar < tarrptr[tcnt])
4767 break;
4769 else if(cchar == tarrptr[tcnt])
4771 cnt = 1;
4772 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, length));
4773 break;
4775 if(tcnt)
4777 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4779 break;
4782 } while(++tcnt < 8);
4783 } while(--cnt);
4786 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4788 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4789 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4791 if(pps->pps_Flags & PSFF_BUFFERWRITE)
4793 /* buffered writing */
4794 if(pps->pps_BytesPending)
4796 remlen = pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize;
4797 /* align to packet boundary */
4798 if(remlen + length >= pp->pp_IOReq.iouh_MaxPktSize)
4800 /* new data crosses at least on packet size */
4801 if(pps->pps_BytesPending + length <= pps->pps_BufferSize)
4803 /* copy everything up to the last (!) boundary */
4804 remlen = pps->pps_BytesPending + length;
4805 remlen = remlen - (remlen % pp->pp_IOReq.iouh_MaxPktSize);
4806 remlen -= pps->pps_BytesPending;
4807 KPRINTF(1, ("PendOptCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4808 } else {
4809 /* just calculate amount to copy to the next boundary */
4810 remlen = pp->pp_IOReq.iouh_MaxPktSize - remlen;
4811 KPRINTF(1, ("PendOneCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4813 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], remlen);
4814 pps->pps_BytesPending += remlen;
4815 actual += remlen;
4816 buffer += remlen;
4817 length -= remlen;
4818 } else {
4819 KPRINTF(1, ("PendAdd(%p, %ld+%ld)\n", buffer, pps->pps_BytesPending, length));
4820 /* only a few bytes, see if we can fit them */
4821 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4822 pps->pps_BytesPending += length;
4823 actual += length;
4824 //buffer += length; /* not needed */
4825 length = 0;
4827 /* flush some buffers */
4828 if((length >= pp->pp_IOReq.iouh_MaxPktSize) ||
4829 ((pps->pps_BytesPending >= (pps->pps_BufferSize>>1)) && (pps->pps_BytesPending >= pp->pp_IOReq.iouh_MaxPktSize)))
4831 remlen = pps->pps_BytesPending - (pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize);
4832 KPRINTF(1, ("PendFlush(%ld/%ld)\n", remlen, pps->pps_BytesPending));
4833 Remove(&pp->pp_Msg.mn_Node);
4834 psdSendPipe(pp, pps->pps_Buffer, remlen);
4835 pps->pps_ActivePipe = pp;
4836 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4838 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4839 sigmask = Wait(sigmask);
4840 if(sigmask & pps->pps_AbortSigMask)
4842 KPRINTF(1, ("Kill signal detected!\n"));
4843 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4844 break;
4847 if(!newpp)
4849 psdAbortPipe(pp);
4851 ioerr = psdWaitPipe(pp);
4852 pps->pps_ActivePipe = NULL;
4853 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4855 /* move end of buffer */
4856 cnt = pps->pps_BytesPending;
4857 tcnt = pp->pp_IOReq.iouh_Actual;
4858 pps->pps_BytesPending -= tcnt;
4859 bufptr = pps->pps_Buffer;
4860 srcptr = bufptr + tcnt;
4861 cnt -= tcnt;
4862 if(cnt)
4866 *bufptr++ = *srcptr++;
4867 } while(--cnt);
4869 if(ioerr)
4871 pps->pps_Error = ioerr;
4872 if(ioerr != UHIOERR_TIMEOUT)
4874 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4875 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4876 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4878 ReleaseSemaphore(&pps->pps_AccessLock);
4879 return(actual);
4883 /* send out large chunk (avoid copying) */
4884 if(length >= pp->pp_IOReq.iouh_MaxPktSize)
4886 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4887 KPRINTF(1, ("BulkFlush(%p, %ld/%ld)\n", buffer, remlen, length));
4888 Remove(&pp->pp_Msg.mn_Node);
4889 psdSendPipe(pp, buffer, remlen);
4890 pps->pps_ActivePipe = pp;
4891 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4893 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4894 sigmask = Wait(sigmask);
4895 if(sigmask & pps->pps_AbortSigMask)
4897 KPRINTF(1, ("Kill signal detected!\n"));
4898 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4899 break;
4902 if(!newpp)
4904 psdAbortPipe(pp);
4906 ioerr = psdWaitPipe(pp);
4907 pps->pps_ActivePipe = NULL;
4908 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4910 actual += pp->pp_IOReq.iouh_Actual;
4911 buffer += pp->pp_IOReq.iouh_Actual;
4912 length -= pp->pp_IOReq.iouh_Actual;
4913 if(ioerr)
4915 pps->pps_Error = ioerr;
4916 if(ioerr != UHIOERR_TIMEOUT)
4918 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4919 "Packet(%s) failed: %s (%ld)", (STRPTR) "c",
4920 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4922 ReleaseSemaphore(&pps->pps_AccessLock);
4923 return(actual);
4926 /* buffer remaining bytes */
4927 if(length)
4929 KPRINTF(1, ("BufAdd(%p, %ld)\n", buffer, length));
4930 /* only a few bytes left, so lets buffer them */
4931 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4932 pps->pps_BytesPending += length;
4933 actual += length;
4935 } else {
4936 /* plain writing */
4937 /* start sending out requests */
4938 KPRINTF(1, ("PlainWrite(%p, %ld)\n", buffer, length));
4939 Remove(&pp->pp_Msg.mn_Node);
4940 psdSendPipe(pp, buffer, length);
4941 pps->pps_ActivePipe = pp;
4942 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4944 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4945 sigmask = Wait(sigmask);
4946 if(sigmask & pps->pps_AbortSigMask)
4948 KPRINTF(1, ("Kill signal detected!\n"));
4949 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4950 break;
4953 if(!newpp)
4955 psdAbortPipe(pp);
4957 ioerr = psdWaitPipe(pp);
4958 pps->pps_ActivePipe = NULL;
4959 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4960 if(ioerr)
4962 pps->pps_Error = ioerr;
4963 if(ioerr != UHIOERR_TIMEOUT)
4965 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4966 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4967 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4970 actual = pp->pp_IOReq.iouh_Actual;
4972 } else {
4973 KPRINTF(2, ("No free pipe!\n"));
4976 ReleaseSemaphore(&pps->pps_AccessLock);
4977 return(actual);
4978 AROS_LIBFUNC_EXIT
4980 /* \\\ */
4982 /* /// "psdStreamFlush()" */
4983 AROS_LH1(LONG, psdStreamFlush,
4984 AROS_LHA(struct PsdPipeStream *, pps, A1),
4985 LIBBASETYPEPTR, ps, 76, psd)
4987 AROS_LIBFUNC_INIT
4988 struct PsdPipe *pp;
4989 ULONG cnt;
4990 LONG ioerr;
4991 LONG ret = FALSE;
4993 KPRINTF(2, ("psdStreamFlush(%p)\n", pps));
4994 if(!pps)
4996 return(-1);
4998 ObtainSemaphore(&pps->pps_AccessLock);
4999 pps->pps_Error = 0;
5000 if(pps->pps_Endpoint->pep_Direction)
5002 /* IN */
5003 KPRINTF(2, ("Flushing in...\n"));
5004 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
5006 psdAbortPipe(pps->pps_Pipes[cnt]);
5008 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
5010 psdWaitPipe(pps->pps_Pipes[cnt]);
5012 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5013 while(pp->pp_Msg.mn_Node.ln_Succ)
5015 Remove(&pp->pp_Msg.mn_Node);
5016 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5017 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5019 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
5021 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5023 pps->pps_ReqBytes = 0;
5024 pps->pps_BytesPending = 0;
5025 pps->pps_Offset = 0;
5026 ret = TRUE;
5027 } else {
5028 /* OUT */
5029 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
5030 if(pp->pp_Msg.mn_Node.ln_Succ)
5032 ret = TRUE;
5033 if(pps->pps_BytesPending)
5035 KPRINTF(2, ("Flushing out %ld...\n", pps->pps_BytesPending));
5036 Remove(&pp->pp_Msg.mn_Node);
5037 ioerr = psdDoPipe(pp, pps->pps_Buffer, pps->pps_BytesPending);
5038 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5039 pps->pps_BytesPending = 0;
5040 if(ioerr)
5042 pps->pps_Error = ioerr;
5043 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamFlush",
5044 "Packet(%s) failed: %s (%ld)", (STRPTR) "f",
5045 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5046 ret = FALSE;
5048 } else {
5049 KPRINTF(2, ("Nothing to flush\n"));
5053 ReleaseSemaphore(&pps->pps_AccessLock);
5054 return(ret);
5055 AROS_LIBFUNC_EXIT
5057 /* \\\ */
5059 /* /// "psdGetStreamError()" */
5060 AROS_LH1(LONG, psdGetStreamError,
5061 AROS_LHA(struct PsdPipeStream *, pps, A1),
5062 LIBBASETYPEPTR, ps, 77, psd)
5064 AROS_LIBFUNC_INIT
5065 KPRINTF(1, ("psdGetStreamError(%p)\n", pps));
5066 if(pps)
5068 return((LONG) pps->pps_Error);
5069 } else {
5070 return(-1);
5072 AROS_LIBFUNC_EXIT
5074 /* \\\ */
5076 /* *** Realtime Iso */
5078 /* /// "psdAllocRTIsoHandler()" */
5079 AROS_LH2(struct PsdRTIsoHandler *, psdAllocRTIsoHandlerA,
5080 AROS_LHA(struct PsdEndpoint *, pep, A0),
5081 AROS_LHA(struct TagItem *, tags, A1),
5082 LIBBASETYPEPTR, ps, 93, psd)
5084 AROS_LIBFUNC_INIT
5085 struct PsdRTIsoHandler *prt;
5086 struct PsdPipe *pp;
5087 LONG ioerr;
5089 KPRINTF(2, ("psdAllocRTIso(%p, %p)\n", pep, tags));
5090 if(!pep)
5092 return(NULL);
5094 if(pep->pep_TransType != USEAF_ISOCHRONOUS)
5096 return(NULL);
5098 if(!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_RT_ISO))
5100 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support realtime iso transfers. Sorry.");
5101 return(NULL);
5103 if((prt = psdAllocVec(sizeof(struct PsdRTIsoHandler))))
5105 prt->prt_Device = pep->pep_Interface->pif_Config->pc_Device;
5106 prt->prt_Endpoint = pep;
5107 prt->prt_RTIso.urti_OutPrefetch = 2048;
5108 if((pp = prt->prt_Pipe = psdAllocPipe(prt->prt_Device, (struct MsgPort *) 0xffffffff, pep)))
5110 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = NULL;
5111 psdSetAttrsA(PGA_RTISO, prt, tags);
5112 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ADDISOHANDLER;
5113 pp->pp_IOReq.iouh_Data = &prt->prt_RTIso;
5114 // hardware must support quick IO for this to work!
5115 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5116 if(!ioerr)
5118 Forbid();
5119 AddTail(&prt->prt_Device->pd_RTIsoHandlers, &prt->prt_Node);
5120 Permit();
5121 return(prt);
5122 } else {
5123 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5124 "Adding RT Iso Handler failed: %s (%ld)",
5125 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5127 psdFreePipe(prt->prt_Pipe);
5129 psdFreeVec(prt);
5131 return(NULL);
5132 AROS_LIBFUNC_EXIT
5134 /* \\\ */
5136 /* /// "psdFreeRTIsoHandler()" */
5137 AROS_LH1(void, psdFreeRTIsoHandler,
5138 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5139 LIBBASETYPEPTR, ps, 94, psd)
5141 AROS_LIBFUNC_INIT
5142 struct PsdPipe *pp;
5144 if(!prt)
5146 return;
5148 Forbid();
5149 Remove(&prt->prt_Node);
5150 Permit();
5151 pp = prt->prt_Pipe;
5152 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_REMISOHANDLER;
5153 DoIO((struct IORequest *) &pp->pp_IOReq);
5154 psdFreePipe(pp);
5155 psdFreeVec(prt);
5156 AROS_LIBFUNC_EXIT
5158 /* \\\ */
5160 /* /// "psdStartRTIso()" */
5161 AROS_LH1(LONG, psdStartRTIso,
5162 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5163 LIBBASETYPEPTR, ps, 95, psd)
5165 AROS_LIBFUNC_INIT
5166 struct PsdPipe *pp;
5167 LONG ioerr;
5169 if(!prt)
5171 return UHIOERR_BADPARAMS;
5173 pp = prt->prt_Pipe;
5174 if(pp->pp_Device->pd_Flags & PDFF_SUSPENDED)
5176 // make sure the device is up and running before trying to send a new pipe
5177 psdResumeDevice(pp->pp_Device);
5179 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STARTRTISO;
5180 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5181 if(!ioerr)
5183 ++pp->pp_Device->pd_IOBusyCount;
5185 return(ioerr);
5186 AROS_LIBFUNC_EXIT
5188 /* \\\ */
5190 /* /// "psdStopRTIso()" */
5191 AROS_LH1(LONG, psdStopRTIso,
5192 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5193 LIBBASETYPEPTR, ps, 96, psd)
5195 AROS_LIBFUNC_INIT
5196 struct PsdPipe *pp;
5197 LONG ioerr;
5199 if(!prt)
5201 return UHIOERR_BADPARAMS;
5203 pp = prt->prt_Pipe;
5204 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STOPRTISO;
5205 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5206 if(!ioerr)
5208 --pp->pp_Device->pd_IOBusyCount;
5210 return(ioerr);
5211 AROS_LIBFUNC_EXIT
5213 /* \\\ */
5215 /* *** Classes *** */
5217 /* /// "psdAddClass()" */
5218 AROS_LH2(struct PsdUsbClass *, psdAddClass,
5219 AROS_LHA(STRPTR, name, A1),
5220 AROS_LHA(ULONG, vers, D0),
5221 LIBBASETYPEPTR, ps, 35, psd)
5223 AROS_LIBFUNC_INIT
5224 struct Library *cls = NULL;
5225 struct PsdUsbClass *puc;
5226 IPTR pri = 0;
5227 STRPTR desc;
5228 UWORD msgoff;
5229 STRPTR origname = name;
5230 STRPTR evilmsg[8] = { "Say hello to %s V%ld.%ld (%s).",
5231 "Whoah! %s V%ld.%ld surprised as %s.",
5232 "The door bell rang for %s V%ld.%ld (%s).",
5233 "Welcome %s V%ld.%ld (%s) to the party.",
5235 "Don't laugh at %s V%ld.%ld for %s.",
5236 "Time has come for %s V%ld.%ld (%s) to join the show.",
5237 "Start blaming %s V%ld.%ld for helping at %s.",
5238 "Ain't %s V%ld.%ld useful for %s?" };
5240 KPRINTF(5, ("psdAddClass(%s, %ld)\n", name, vers));
5242 while(*name)
5244 if((cls = OpenLibrary(name, vers)))
5246 break;
5250 if((*name == '/') || (*name == ':'))
5252 ++name;
5253 break;
5255 } while(*(++name));
5257 if(cls)
5259 Forbid();
5260 if(FindName(&ps->ps_Classes, cls->lib_Node.ln_Name))
5262 Permit();
5263 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5264 "Attempted to add class %s twice. Nothing is good enough for people like you.",
5265 name);
5266 KPRINTF(20, ("attempt to add class twice!\n"));
5267 CloseLibrary(cls);
5268 return(NULL);
5270 Permit();
5271 if((puc = psdAllocVec(sizeof(struct PsdUsbClass))))
5273 puc->puc_Base = ps;
5274 puc->puc_ClassBase = cls;
5275 puc->puc_Node.ln_Name = puc->puc_ClassName = psdCopyStr(cls->lib_Node.ln_Name);
5276 puc->puc_FullPath = psdCopyStr(origname);
5278 usbGetAttrs(UGA_CLASS, NULL,
5279 UCCA_Priority, &pri,
5280 UCCA_Description, &desc,
5281 TAG_END);
5283 puc->puc_Node.ln_Pri = pri;
5284 psdLockWritePBase();
5285 Enqueue(&ps->ps_Classes, &puc->puc_Node);
5286 psdUnlockPBase();
5287 msgoff = ps->ps_FunnyCount++ & 7;
5289 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5290 evilmsg[msgoff],
5291 cls->lib_Node.ln_Name, cls->lib_Version, cls->lib_Revision, desc);
5292 psdSendEvent(EHMB_ADDCLASS, puc, NULL);
5293 return(puc);
5295 CloseLibrary(cls);
5297 return(NULL);
5298 AROS_LIBFUNC_EXIT
5300 /* \\\ */
5302 /* /// "psdRemClass()" */
5303 AROS_LH1(void, psdRemClass,
5304 AROS_LHA(struct PsdUsbClass *, puc, A1),
5305 LIBBASETYPEPTR, ps, 36, psd)
5307 AROS_LIBFUNC_INIT
5308 KPRINTF(5, ("psdRemClass(%p)\n", puc));
5309 psdLockWritePBase();
5310 Remove(&puc->puc_Node);
5311 psdUnlockPBase();
5313 /* Check if there are still bindings remaining */
5314 while(puc->puc_UseCnt)
5316 struct PsdDevice *pd;
5317 struct PsdConfig *pc;
5318 struct PsdInterface *pif;
5320 KPRINTF(20, ("This should never happen: Class %s still in use (%ld), can't close!\n",
5321 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt));
5323 /* Well, try to release the open bindings in a best effort attempt */
5324 psdLockReadPBase();
5325 pd = NULL;
5326 while((pd = psdGetNextDevice(pd)))
5328 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
5330 psdUnlockPBase();
5331 psdReleaseDevBinding(pd);
5332 psdLockReadPBase();
5333 pd = NULL; /* restart */
5334 continue;
5336 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5337 while(pc->pc_Node.ln_Succ)
5339 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5340 while(pif->pif_Node.ln_Succ)
5342 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
5344 psdUnlockPBase();
5345 psdReleaseIfBinding(pif);
5346 psdLockReadPBase();
5347 pd = NULL; /* restart */
5348 continue;
5350 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5352 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5355 psdUnlockPBase();
5356 if(puc->puc_UseCnt)
5358 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
5359 "This should never happen! Class %s still in use (cnt=%ld). Could not get rid of it! Sorry, we're broke.",
5360 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt);
5362 /*psdDelayMS(2000);*/
5365 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5366 "I shot class %s, but I didn't kill the deputy.",
5367 puc->puc_ClassBase->lib_Node.ln_Name);
5368 CloseLibrary(puc->puc_ClassBase);
5369 psdFreeVec(puc->puc_ClassName);
5370 psdFreeVec(puc->puc_FullPath);
5371 psdFreeVec(puc);
5372 psdSendEvent(EHMB_REMCLASS, puc, NULL);
5373 AROS_LIBFUNC_EXIT
5375 /* \\\ */
5377 /* *** Error Msgs *** */
5379 /* /// "psdAddErrorMsgA()" */
5380 AROS_LH4(struct PsdErrorMsg *, psdAddErrorMsgA,
5381 AROS_LHA(UWORD, level, D0),
5382 AROS_LHA(STRPTR, origin, A0),
5383 AROS_LHA(STRPTR, fmtstr, A1),
5384 AROS_LHA(RAWARG, fmtdata, A2),
5385 LIBBASETYPEPTR, ps, 40, psd)
5387 AROS_LIBFUNC_INIT
5388 struct PsdErrorMsg *pem;
5389 if(((!ps->ps_GlobalCfg->pgc_LogInfo) && (level < RETURN_WARN)) ||
5390 ((!ps->ps_GlobalCfg->pgc_LogWarning) && (level >= RETURN_WARN) && (level < RETURN_ERROR)) ||
5391 ((!ps->ps_GlobalCfg->pgc_LogError) && (level >= RETURN_ERROR) && (level < RETURN_FAIL)) ||
5392 ((!ps->ps_GlobalCfg->pgc_LogFailure) && (level >= RETURN_FAIL)))
5394 return(NULL);
5396 if((pem = psdAllocVec(sizeof(struct PsdErrorMsg))))
5398 pem->pem_Base = ps;
5399 pem->pem_Level = level;
5400 if((pem->pem_Origin = psdCopyStr(origin)))
5402 if((pem->pem_Msg = psdCopyStrFmtA(fmtstr, fmtdata)))
5404 if (ps->ps_Flags & PSF_KLOG) {
5405 KPrintF("[%s] %s\n", origin, pem->pem_Msg);
5408 if(pOpenDOS(ps))
5410 DateStamp(&pem->pem_DateStamp);
5411 } else {
5412 struct timerequest tr = ps->ps_TimerIOReq;
5413 tr.tr_node.io_Command = TR_GETSYSTIME;
5414 DoIO((struct IORequest *) &tr);
5415 pem->pem_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60);
5416 pem->pem_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60;
5417 pem->pem_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50;
5419 Forbid();
5420 AddTail(&ps->ps_ErrorMsgs, &pem->pem_Node);
5421 Permit();
5422 psdSendEvent(EHMB_ADDERRORMSG, pem, NULL);
5423 return(pem);
5425 psdFreeVec(pem->pem_Origin);
5427 psdFreeVec(pem);
5429 return(NULL);
5430 AROS_LIBFUNC_EXIT
5432 /* \\\ */
5434 /* /// "psdRemErrorMsg()" */
5435 AROS_LH1(void, psdRemErrorMsg,
5436 AROS_LHA(struct PsdErrorMsg *, pem, A0),
5437 LIBBASETYPEPTR, ps, 41, psd)
5439 AROS_LIBFUNC_INIT
5440 KPRINTF(1, ("psdRemErrorMsg()\n"));
5441 Forbid();
5442 Remove(&pem->pem_Node);
5443 Permit();
5444 psdFreeVec(pem->pem_Origin);
5445 psdFreeVec(pem->pem_Msg);
5446 psdFreeVec(pem);
5447 psdSendEvent(EHMB_REMERRORMSG, pem, NULL);
5448 AROS_LIBFUNC_EXIT
5450 /* \\\ */
5452 /* *** Bindings *** */
5454 /* /// "psdClassScan()" */
5455 AROS_LH0(void, psdClassScan,
5456 LIBBASETYPEPTR, ps, 37, psd)
5458 AROS_LIBFUNC_INIT
5459 struct PsdHardware *phw;
5460 struct PsdDevice *pd;
5461 struct PsdUsbClass *puc;
5463 psdLockReadPBase();
5465 if((FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS) && (!ps->ps_ConfigRead))
5467 // it's the first time we were reading the config and DOS was not available
5468 ps->ps_StartedAsTask = TRUE;
5471 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5472 if(!puc->puc_Node.ln_Succ)
5474 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "ClassScan attempted with no classes installed!");
5475 psdUnlockPBase();
5476 return;
5479 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5480 while(phw->phw_Node.ln_Succ)
5482 if((pd = phw->phw_RootDevice))
5484 // for the root, do it ourselves, the rest is done by each hub task
5485 psdHubClassScan(pd);
5487 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5489 psdUnlockPBase();
5490 //psdSendEvent(EHMB_CLSSCANRDY, NULL, NULL);
5491 KPRINTF(5, ("************ Scanning finished!\n"));
5492 AROS_LIBFUNC_EXIT
5494 /* \\\ */
5496 /* /// "psdDoHubMethodA()" */
5497 AROS_LH3(LONG, psdDoHubMethodA,
5498 AROS_LHA(struct PsdDevice *, pd, A0),
5499 AROS_LHA(ULONG, methodid, D0),
5500 AROS_LHA(APTR, methoddata, A1),
5501 LIBBASETYPEPTR, ps, 92, psd)
5503 AROS_LIBFUNC_INIT
5504 struct PsdUsbClass *puc;
5505 KPRINTF(2, ("psdDoHubMethodA(%p)\n", pd));
5507 if(pd)
5509 if(pd->pd_Hub)
5511 if((pd->pd_Hub->pd_DevBinding) && (puc = pd->pd_Hub->pd_ClsBinding))
5513 return(usbDoMethodA(methodid, methoddata));
5517 return 0;
5518 AROS_LIBFUNC_EXIT
5520 /* \\\ */
5522 /* /// "psdClaimAppBindingA()" */
5523 AROS_LH1(struct PsdAppBinding *, psdClaimAppBindingA,
5524 AROS_LHA(struct TagItem *, tags, A1),
5525 LIBBASETYPEPTR, ps, 45, psd)
5527 AROS_LIBFUNC_INIT
5528 struct PsdDevice *pd;
5529 struct PsdConfig *pc;
5530 struct PsdInterface *pif;
5531 struct PsdDevice *hubpd;
5532 struct PsdAppBinding tmppab;
5533 struct PsdAppBinding *pab = NULL;
5534 struct PsdUsbClass *puc;
5536 APTR binding;
5538 KPRINTF(2, ("psdClaimAppBindingA(%p)\n", tags));
5540 tmppab.pab_Device = NULL;
5541 tmppab.pab_ReleaseHook = NULL;
5542 tmppab.pab_Task = NULL;
5543 tmppab.pab_ForceRelease = FALSE;
5544 psdSetAttrsA(PGA_APPBINDING, &tmppab, tags);
5545 if(tmppab.pab_Device && tmppab.pab_ReleaseHook)
5547 pd = tmppab.pab_Device;
5549 // force release of other bindings first
5550 if(tmppab.pab_ForceRelease)
5552 /* If there are bindings, get rid of them. */
5553 if(pd->pd_DevBinding)
5555 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5556 "%s really wants to bind to %s, so I'm letting the old binding go.",
5557 FindTask(NULL)->tc_Node.ln_Name,
5558 pd->pd_ProductStr);
5560 psdReleaseDevBinding(pd);
5561 } else {
5562 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5563 while(pc->pc_Node.ln_Succ)
5565 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5566 while(pif->pif_Node.ln_Succ)
5568 if(pif->pif_IfBinding)
5570 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5571 "%s really wants to bind to %s, so I'm letting the old binding go.",
5572 FindTask(NULL)->tc_Node.ln_Name,
5573 pd->pd_ProductStr);
5574 psdReleaseIfBinding(pif);
5576 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5578 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5582 hubpd = pd->pd_Hub;
5583 if(!hubpd) // claim app binding at the root hub -- improbable, but possible.
5585 pab = psdHubClaimAppBindingA(tags);
5586 } else {
5587 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5589 pab = (struct PsdAppBinding *) usbDoMethod(UCM_HubClaimAppBinding, binding, tags);
5592 if(pab)
5594 // fill in task names
5595 pab->pab_Task = FindTask(NULL);
5596 pab->pab_Node.ln_Name = pab->pab_Task->tc_Node.ln_Name;
5597 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5598 return(pab);
5601 return(NULL);
5602 AROS_LIBFUNC_EXIT
5604 /* \\\ */
5606 /* /// "psdReleaseAppBinding()" */
5607 AROS_LH1(void, psdReleaseAppBinding,
5608 AROS_LHA(struct PsdAppBinding *, pab, A0),
5609 LIBBASETYPEPTR, ps, 46, psd)
5611 AROS_LIBFUNC_INIT
5612 struct PsdDevice *pd;
5613 struct PsdDevice *hubpd;
5614 struct PsdUsbClass *puc;
5615 APTR binding;
5617 KPRINTF(2, ("psdReleaseAppBinding(%p)\n", pab));
5619 if(pab)
5621 pd = pab->pab_Device;
5622 hubpd = pd->pd_Hub;
5623 if(!hubpd) // release binding of hub (improbable)
5625 psdHubReleaseDevBinding(pd);
5626 return;
5628 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5630 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5633 AROS_LIBFUNC_EXIT
5635 /* \\\ */
5637 /* /// "psdReleaseDevBinding()" */
5638 AROS_LH1(void, psdReleaseDevBinding,
5639 AROS_LHA(struct PsdDevice *, pd, A0),
5640 LIBBASETYPEPTR, ps, 50, psd)
5642 AROS_LIBFUNC_INIT
5643 struct PsdUsbClass *puc;
5644 struct PsdDevice *hubpd;
5645 APTR binding;
5647 KPRINTF(5, ("psdReleaseDevBinding(%p)\n", pd));
5648 if(pd->pd_DevBinding)
5650 hubpd = pd->pd_Hub;
5651 if(!hubpd) // release binding of hub
5653 psdHubReleaseDevBinding(pd);
5654 return;
5656 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5658 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5661 AROS_LIBFUNC_EXIT
5663 /* \\\ */
5665 /* /// "psdReleaseIfBinding()" */
5666 AROS_LH1(void, psdReleaseIfBinding,
5667 AROS_LHA(struct PsdInterface *, pif, A0),
5668 LIBBASETYPEPTR, ps, 51, psd)
5670 AROS_LIBFUNC_INIT
5671 struct PsdUsbClass *puc;
5672 struct PsdDevice *hubpd;
5673 APTR binding;
5675 KPRINTF(5, ("psdReleaseIfBinding(%p)\n", pif));
5676 if(pif->pif_IfBinding && pif->pif_ClsBinding)
5678 hubpd = pif->pif_Config->pc_Device->pd_Hub;
5679 if(!hubpd) // release binding of hub (improbable)
5681 psdHubReleaseIfBinding(pif);
5682 return;
5684 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5686 usbDoMethod(UCM_HubReleaseIfBinding, binding, pif);
5689 AROS_LIBFUNC_EXIT
5691 /* \\\ */
5693 /* /// "psdUnbindAll()" */
5694 AROS_LH0(void, psdUnbindAll,
5695 LIBBASETYPEPTR, ps, 61, psd)
5697 AROS_LIBFUNC_INIT
5698 struct PsdHardware *phw;
5699 struct PsdDevice *pd;
5700 struct PsdConfig *pc;
5701 struct PsdInterface *pif;
5702 BOOL restart;
5704 KPRINTF(10, ("pUnbindAll()\n"));
5705 /* FIXME What happens if devices or hardware gets removed during the process? Need notify semaphore */
5706 psdLockReadPBase();
5709 restart = FALSE;
5710 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5711 while(phw->phw_Node.ln_Succ)
5713 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
5714 while(pd->pd_Node.ln_Succ)
5716 /* If there are bindings, get rid of them. */
5717 if(pd->pd_DevBinding)
5719 psdUnlockPBase();
5720 psdReleaseDevBinding(pd);
5721 psdLockReadPBase();
5722 restart = TRUE;
5723 break;
5725 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5726 while(pc->pc_Node.ln_Succ)
5728 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5729 while(pif->pif_Node.ln_Succ)
5731 if(pif->pif_IfBinding)
5733 psdUnlockPBase();
5734 psdReleaseIfBinding(pif);
5735 psdLockReadPBase();
5736 restart = TRUE;
5737 break;
5739 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5741 if(restart)
5743 break;
5745 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5747 if(restart)
5749 break;
5751 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
5753 if(restart)
5755 break;
5757 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5759 } while(restart);
5760 psdUnlockPBase();
5761 AROS_LIBFUNC_EXIT
5763 /* \\\ */
5765 /* /// "psdHubClassScan()" */
5766 AROS_LH1(void, psdHubClassScan,
5767 AROS_LHA(struct PsdDevice *, pd, A0),
5768 LIBBASETYPEPTR, ps, 82, psd)
5770 AROS_LIBFUNC_INIT
5771 struct PsdUsbClass *puc;
5772 struct PsdConfig *pc;
5773 struct PsdInterface *pif;
5774 struct PsdInterface *firstpif;
5775 struct PsdPipe *pp = NULL;
5776 struct MsgPort *mp;
5777 APTR binding;
5778 UWORD hasifbinding;
5779 BOOL mainif;
5780 STRPTR owner;
5782 KPRINTF(5, ("psdClassScan()\n"));
5784 if(!(mp = CreateMsgPort()))
5786 return;
5788 psdLockReadPBase();
5789 psdLockWriteDevice(pd);
5790 while(!(pd->pd_PoPoCfg.poc_NoClassBind || pd->pd_DevBinding))
5792 if(!(pp = psdAllocPipe(pd, mp, NULL)))
5794 break;
5796 KPRINTF(5, ("Doing ClassScan on Device: %s\n", pd->pd_ProductStr));
5797 hasifbinding = 0;
5798 /* First look if there is any interface binding. We may not change
5799 the current config in this case! */
5800 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5801 while(pc->pc_Node.ln_Succ)
5803 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5805 while(pif->pif_Node.ln_Succ)
5807 if(pif->pif_IfBinding)
5809 hasifbinding = pc->pc_CfgNum;
5810 break;
5812 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5814 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5817 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5818 if((!hasifbinding) && owner)
5820 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5821 while(puc->puc_Node.ln_Succ)
5823 if(!strcmp(owner, puc->puc_ClassName))
5825 if((pd->pd_DevBinding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd)))
5827 pd->pd_ClsBinding = puc;
5828 puc->puc_UseCnt++;
5829 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5830 } else {
5831 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5832 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5834 break;
5836 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5838 /* no more scanning required, abort here */
5839 break;
5842 /* Second attempt */
5843 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5844 while(pc->pc_Node.ln_Succ)
5846 if((!hasifbinding) || (hasifbinding == pc->pc_CfgNum))
5848 /* If the current config is not the one selected, change it */
5849 if(pd->pd_CurrCfg != pc->pc_CfgNum)
5851 psdSetDeviceConfig(pp, pc->pc_CfgNum);
5853 KPRINTF(5, (" Config %ld\n", pc->pc_CfgNum));
5854 /* If something went wrong above, we must exclude this config */
5855 if(pd->pd_CurrCfg == pc->pc_CfgNum)
5857 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5858 while(pif->pif_Node.ln_Succ)
5860 KPRINTF(5, (" Interface %ld\n", pif->pif_IfNum));
5861 firstpif = pif;
5862 mainif = TRUE;
5863 if(!pif->pif_IfBinding)
5865 binding = NULL;
5868 if(!psdSetAltInterface(pp, pif))
5870 pif->pif_IfBinding = NULL;
5871 /* Okay, this alternate setting failed. Try to get next one */
5872 if(!mainif)
5874 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5875 if(pif->pif_Node.ln_Succ)
5877 KPRINTF(5, ("CONT!\n"));
5878 continue;
5879 } else {
5880 KPRINTF(5, ("BREAK!\n"));
5881 pif = firstpif;
5882 break;
5886 owner = psdGetForcedBinding(pd->pd_IDString, pif->pif_IDString);
5887 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5888 while(puc->puc_Node.ln_Succ)
5890 KPRINTF(5, (">>>PING %s!\n", puc->puc_ClassName));
5891 if(owner)
5893 if(!strcmp(owner, puc->puc_ClassName))
5895 binding = (APTR) usbDoMethod(UCM_ForceInterfaceBinding, pif);
5896 if(!binding)
5898 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5899 "Forced interface binding of %s to %s failed.", pd->pd_ProductStr, owner);
5902 if(!binding)
5904 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5905 continue;
5907 } else {
5908 binding = (APTR) usbDoMethod(UCM_AttemptInterfaceBinding, pif);
5910 Forbid();
5911 KPRINTF(5, ("<<<PONG!!\n"));
5912 if(binding)
5914 KPRINTF(5, ("Got binding!\n"));
5915 /* Find root config structure */
5916 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5917 while(pif->pif_Node.ln_Succ)
5919 if(pif->pif_IfNum == firstpif->pif_IfNum)
5921 break;
5923 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5925 if(!pif->pif_Node.ln_Succ)
5927 KPRINTF(5, ("Fucked it up!\n"));
5928 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Something incredibly stupid happend. I've given up.");
5929 Permit();
5930 break;
5932 pif->pif_IfBinding = binding;
5933 pif->pif_ClsBinding = puc;
5934 hasifbinding = pc->pc_CfgNum;
5935 puc->puc_UseCnt++;
5936 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5937 Permit();
5938 break;
5940 Permit();
5941 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5943 if(binding)
5945 break;
5947 //break; /* FIXME: DISABLED ALTSCANNING */
5948 /* Check alternate setting */
5949 if(pif->pif_AlterIfs.lh_Head->ln_Succ)
5951 /* There are some alternative interfaces, start at top */
5952 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
5953 mainif = FALSE;
5955 } while(pif != firstpif);
5956 //pif->pif_IfBinding = binding;
5957 if(!binding)
5959 psdSetAltInterface(pp, pif);
5961 /* Hohum, search current main interface then */
5962 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5963 while(pif->pif_Node.ln_Succ)
5965 if(pif->pif_IfNum == firstpif->pif_IfNum)
5967 break;
5969 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5972 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5976 KPRINTF(5, ("End, next ConfigCheck!\n"));
5977 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5979 /* Could not establish interface binding, try device binding then */
5980 //psdUnlockPBase();
5981 if(!hasifbinding)
5983 //pd->pd_DevBinding = (APTR) ~0UL;
5984 binding = NULL;
5985 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5986 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5987 while(puc->puc_Node.ln_Succ)
5989 binding = NULL;
5990 if(owner)
5992 if(!strcmp(owner, puc->puc_ClassName))
5994 binding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd, TAG_END);
5995 if(!binding)
5997 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5998 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
6001 if(!binding)
6003 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6004 continue;
6006 } else {
6007 binding = (APTR) usbDoMethod(UCM_AttemptDeviceBinding, pd);
6009 if(binding)
6011 pd->pd_DevBinding = binding;
6012 pd->pd_ClsBinding = puc;
6013 puc->puc_UseCnt++;
6014 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
6015 break;
6017 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6019 pd->pd_DevBinding = binding;
6021 break;
6023 if(pp)
6025 psdFreePipe(pp);
6027 // call hub class scan code
6028 if((binding = pd->pd_DevBinding) && (puc = pd->pd_ClsBinding))
6030 usbDoMethod(UCM_HubClassScan, binding);
6032 psdUnlockDevice(pd);
6033 psdUnlockPBase();
6034 DeleteMsgPort(mp);
6035 AROS_LIBFUNC_EXIT
6037 /* \\\ */
6039 /* /// "psdHubClaimAppBindingA()" */
6040 AROS_LH1(struct PsdAppBinding *, psdHubClaimAppBindingA,
6041 AROS_LHA(struct TagItem *, tags, A1),
6042 LIBBASETYPEPTR, ps, 83, psd)
6044 AROS_LIBFUNC_INIT
6045 struct PsdDevice *pd;
6046 struct PsdAppBinding *pab;
6047 struct PsdConfig *pc;
6048 struct PsdInterface *pif;
6050 BOOL hasbinding = FALSE;
6051 KPRINTF(2, ("psdHubClaimAppBindingA(%p)\n", tags));
6053 if((pab = psdAllocVec(sizeof(struct PsdAppBinding))))
6055 psdSetAttrsA(PGA_APPBINDING, pab, tags);
6056 if(pab->pab_Device && pab->pab_ReleaseHook)
6058 pd = pab->pab_Device;
6059 if(pd->pd_DevBinding)
6061 hasbinding = TRUE;
6062 } else {
6063 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6064 while(pc->pc_Node.ln_Succ)
6066 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6068 while(pif->pif_Node.ln_Succ)
6070 if(pif->pif_IfBinding)
6072 hasbinding = TRUE;
6073 break;
6075 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6077 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6080 if(!hasbinding)
6082 pd->pd_Flags |= PDFF_APPBINDING;
6083 pd->pd_DevBinding = pab;
6084 pd->pd_ClsBinding = NULL;
6085 return(pab);
6088 psdFreeVec(pab);
6090 return(NULL);
6091 AROS_LIBFUNC_EXIT
6093 /* \\\ */
6095 /* /// "psdHubReleaseDevBinding()" */
6096 AROS_LH1(void, psdHubReleaseDevBinding,
6097 AROS_LHA(struct PsdDevice *, pd, A0),
6098 LIBBASETYPEPTR, ps, 84, psd)
6100 AROS_LIBFUNC_INIT
6101 struct PsdUsbClass *puc;
6102 APTR binding;
6103 struct PsdAppBinding *pab;
6105 KPRINTF(5, ("psdHubReleaseDevBinding(%p)\n", pd));
6106 if(pd)
6108 psdLockWriteDevice(pd);
6109 if((binding = pd->pd_DevBinding))
6111 pd->pd_DevBinding = NULL;
6112 if(pd->pd_Flags & PDFF_APPBINDING)
6114 pab = (struct PsdAppBinding *) binding;
6115 CallHookPkt(pab->pab_ReleaseHook, pab, (APTR) pab->pab_UserData);
6116 pd->pd_ClsBinding = NULL;
6117 pd->pd_Flags &= ~PDFF_APPBINDING;
6118 psdFreeVec(pab);
6119 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6120 } else {
6121 puc = pd->pd_ClsBinding;
6122 if(puc)
6124 pd->pd_ClsBinding = NULL;
6125 usbDoMethod(UCM_ReleaseDeviceBinding, binding);
6126 puc->puc_UseCnt--;
6127 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6131 psdUnlockDevice(pd);
6133 AROS_LIBFUNC_EXIT
6135 /* \\\ */
6137 /* /// "psdHubReleaseIfBinding()" */
6138 AROS_LH1(void, psdHubReleaseIfBinding,
6139 AROS_LHA(struct PsdInterface *, pif, A0),
6140 LIBBASETYPEPTR, ps, 85, psd)
6142 AROS_LIBFUNC_INIT
6143 struct PsdUsbClass *puc;
6144 struct PsdDevice *pd;
6145 APTR binding;
6147 KPRINTF(5, ("psdHubReleaseIfBinding(%p)\n", pif));
6149 if(pif)
6151 pd = pif->pif_Config->pc_Device;
6152 psdLockWriteDevice(pd);
6153 if((binding = pif->pif_IfBinding))
6155 pif->pif_IfBinding = NULL;
6156 puc = pif->pif_ClsBinding;
6157 if(puc)
6159 pif->pif_ClsBinding = NULL;
6160 usbDoMethod(UCM_ReleaseInterfaceBinding, binding);
6161 puc->puc_UseCnt--;
6163 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6165 psdUnlockDevice(pd);
6167 AROS_LIBFUNC_EXIT
6169 /* \\\ */
6171 /* *** Events *** */
6173 /* /// "psdAddEventHandler()" */
6174 AROS_LH2(struct PsdEventHook *, psdAddEventHandler,
6175 AROS_LHA(struct MsgPort *, mp, A1),
6176 AROS_LHA(ULONG, msgmask, D0),
6177 LIBBASETYPEPTR, ps, 47, psd)
6179 AROS_LIBFUNC_INIT
6180 struct PsdEventHook *peh = NULL;
6182 KPRINTF(5, ("psdAddEventHandler(%p, %p)\n", mp, msgmask));
6184 if(mp)
6186 ObtainSemaphore(&ps->ps_ReentrantLock);
6187 if((peh = psdAllocVec(sizeof(struct PsdEventHook))))
6189 peh->peh_MsgPort = mp;
6190 peh->peh_MsgMask = msgmask;
6191 AddTail(&ps->ps_EventHooks, &peh->peh_Node);
6193 ReleaseSemaphore(&ps->ps_ReentrantLock);
6195 return(peh);
6196 AROS_LIBFUNC_EXIT
6198 /* \\\ */
6200 /* /// "psdRemEventHandler()" */
6201 AROS_LH1(void, psdRemEventHandler,
6202 AROS_LHA(struct PsdEventHook *, peh, A0),
6203 LIBBASETYPEPTR, ps, 48, psd)
6205 AROS_LIBFUNC_INIT
6206 struct Message *msg;
6208 KPRINTF(5, ("psdRemEventHandler(%p)\n", peh));
6209 if(!peh)
6211 return;
6213 ObtainSemaphore(&ps->ps_ReentrantLock);
6214 Remove(&peh->peh_Node);
6215 while((msg = GetMsg(peh->peh_MsgPort)))
6217 ReplyMsg(msg);
6219 ReleaseSemaphore(&ps->ps_ReentrantLock);
6220 pGarbageCollectEvents(ps);
6221 psdFreeVec(peh);
6222 AROS_LIBFUNC_EXIT
6224 /* \\\ */
6226 /* /// "psdSendEvent()" */
6227 AROS_LH3(void, psdSendEvent,
6228 AROS_LHA(ULONG, ehmt, D0),
6229 AROS_LHA(APTR, param1, A0),
6230 AROS_LHA(APTR, param2, A1),
6231 LIBBASETYPEPTR, ps, 49, psd)
6233 AROS_LIBFUNC_INIT
6234 struct PsdEventNote *pen;
6235 struct PsdEventHook *peh;
6236 ULONG msgmask = (1L<<ehmt);
6238 KPRINTF(1, ("psdSendEvent(%p, %p, %p)\n", ehmt, param1, param2));
6240 pGarbageCollectEvents(ps);
6241 ObtainSemaphore(&ps->ps_ReentrantLock);
6242 peh = (struct PsdEventHook *) ps->ps_EventHooks.lh_Head;
6243 while(peh->peh_Node.ln_Succ)
6245 if(peh->peh_MsgMask & msgmask)
6247 if((pen = psdAllocVec(sizeof(struct PsdEventNote))))
6249 pen->pen_Msg.mn_ReplyPort = &ps->ps_EventReplyPort;
6250 pen->pen_Msg.mn_Length = sizeof(struct PsdEventNote);
6251 pen->pen_Event = ehmt;
6252 pen->pen_Param1 = param1;
6253 pen->pen_Param2 = param2;
6254 PutMsg(peh->peh_MsgPort, &pen->pen_Msg);
6257 peh = (struct PsdEventHook *) peh->peh_Node.ln_Succ;
6259 ReleaseSemaphore(&ps->ps_ReentrantLock);
6260 AROS_LIBFUNC_EXIT
6262 /* \\\ */
6264 /* *** Configuration *** */
6266 /* /// "psdReadCfg()" */
6267 AROS_LH2(BOOL, psdReadCfg,
6268 AROS_LHA(struct PsdIFFContext *, pic, A0),
6269 AROS_LHA(APTR, formdata, A1),
6270 LIBBASETYPEPTR, ps, 52, psd)
6272 AROS_LIBFUNC_INIT
6273 struct PsdIFFContext *subpic;
6274 LONG len;
6275 ULONG chlen;
6276 ULONG *buf = formdata;
6277 BOOL res = TRUE;
6278 KPRINTF(10, ("psdReadCfg(%p, %p)\n", pic, formdata));
6280 pLockSemExcl(ps, &ps->ps_ConfigLock);
6281 if(!pic)
6283 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6284 if(!(pic->pic_Node.ln_Succ))
6286 pUnlockSem(ps, &ps->ps_ConfigLock);
6287 return(FALSE);
6290 if((AROS_LONG2BE(*buf) != ID_FORM) || (AROS_LONG2BE(buf[2]) != pic->pic_FormID))
6292 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to replace a cfg form with a chunk or with an alien form!");
6293 pUnlockSem(ps, &ps->ps_ConfigLock);
6294 return(FALSE);
6296 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6297 while(subpic->pic_Node.ln_Succ)
6299 pFreeForm(ps, subpic);
6300 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6302 pic->pic_ChunksLen = 0;
6303 len = (AROS_LONG2BE(buf[1]) - 3) & ~1UL;
6304 buf += 3;
6305 while(len >= 8)
6307 if(!(pAddCfgChunk(ps, pic, buf)))
6309 break;
6311 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
6312 len -= chlen;
6313 buf = (ULONG *) (((UBYTE *) buf) + chlen);
6315 if(len)
6317 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
6318 res = 0;
6321 pUnlockSem(ps, &ps->ps_ConfigLock);
6322 ps->ps_CheckConfigReq = TRUE;
6323 return(res);
6324 AROS_LIBFUNC_EXIT
6326 /* \\\ */
6328 /* /// "psdLoadCfgFromDisk()" */
6329 AROS_LH1(BOOL, psdLoadCfgFromDisk,
6330 AROS_LHA(STRPTR, filename, A1),
6331 LIBBASETYPEPTR, ps, 79, psd)
6333 AROS_LIBFUNC_INIT
6334 ULONG *buf;
6335 BOOL loaded = FALSE;
6336 BPTR filehandle;
6337 ULONG formhead[3];
6338 ULONG formlen;
6340 XPRINTF(10, ("Loading config file: %s\n", filename));
6342 if(!filename)
6344 loaded = psdLoadCfgFromDisk("ENV:Sys/poseidon.prefs");
6345 if(loaded)
6347 return(TRUE);
6350 loaded = psdLoadCfgFromDisk("ENVARC:Sys/poseidon.prefs");
6352 return(loaded);
6355 if(!pOpenDOS(ps))
6357 KPRINTF(1, ("dos.library not available yet\n"));
6358 return(FALSE);
6361 filehandle = Open(filename, MODE_OLDFILE);
6362 KPRINTF(1, ("File handle 0x%p\n", filehandle));
6363 if(filehandle)
6365 if(Read(filehandle, formhead, 12) == 12)
6367 KPRINTF(1, ("Read header\n"));
6368 if((AROS_LONG2BE(formhead[0]) == ID_FORM) && (AROS_LONG2BE(formhead[2]) == IFFFORM_PSDCFG))
6370 formlen = AROS_LONG2BE(formhead[1]);
6371 KPRINTF(1, ("Header OK, %lu bytes\n", formlen));
6373 buf = (ULONG *) psdAllocVec(formlen + 8);
6374 if(buf)
6376 buf[0] = formhead[0];
6377 buf[1] = formhead[1];
6378 buf[2] = formhead[2];
6379 if(Read(filehandle, &buf[3], formlen - 4) == formlen - 4)
6381 KPRINTF(1, ("Data read OK\n"));
6383 psdReadCfg(NULL, buf);
6384 psdParseCfg();
6386 KPRINTF(1, ("All done\n"));
6387 loaded = TRUE;
6389 psdFreeVec(buf);
6393 Close(filehandle);
6394 } else {
6395 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6396 "Failed to load config from '%s'!",
6397 filename);
6399 if(loaded)
6401 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6403 return(loaded);
6404 AROS_LIBFUNC_EXIT
6406 /* \\\ */
6408 /* /// "psdSaveCfgToDisk()" */
6409 AROS_LH2(BOOL, psdSaveCfgToDisk,
6410 AROS_LHA(STRPTR, filename, A1),
6411 AROS_LHA(BOOL, executable, D0),
6412 LIBBASETYPEPTR, ps, 80, psd)
6414 AROS_LIBFUNC_INIT
6415 ULONG *buf;
6416 BOOL saved = FALSE;
6417 BPTR filehandle;
6419 if(!filename)
6421 saved = psdSaveCfgToDisk("ENVARC:Sys/poseidon.prefs", FALSE);
6422 saved &= psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE);
6423 return(saved);
6426 if(!pOpenDOS(ps))
6428 return(FALSE);
6430 pLockSemShared(ps, &ps->ps_ConfigLock);
6432 buf = (ULONG *) psdWriteCfg(NULL);
6433 if(buf)
6435 /* Write file */
6436 filehandle = Open(filename, MODE_NEWFILE);
6437 if(filehandle)
6439 Write(filehandle, buf, (AROS_LONG2BE(buf[1])+9) & ~1UL);
6440 Close(filehandle);
6441 saved = TRUE;
6442 } else {
6443 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6444 "Failed to write config to '%s'!",
6445 filename);
6447 psdFreeVec(buf);
6449 pUnlockSem(ps, &ps->ps_ConfigLock);
6450 if(saved)
6452 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6454 return(saved);
6455 AROS_LIBFUNC_EXIT
6457 /* \\\ */
6459 /* /// "psdWriteCfg()" */
6460 AROS_LH1(APTR, psdWriteCfg,
6461 AROS_LHA(struct PsdIFFContext *, pic, A0),
6462 LIBBASETYPEPTR, ps, 53, psd)
6464 AROS_LIBFUNC_INIT
6465 ULONG len;
6466 APTR buf = NULL;
6468 KPRINTF(10, ("psdWriteCfg(%p)\n", pic));
6470 pLockSemShared(ps, &ps->ps_ConfigLock);
6471 if(!pic)
6473 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6474 if(!(pic->pic_Node.ln_Succ))
6476 pUnlockSem(ps, &ps->ps_ConfigLock);
6477 return(NULL);
6480 pUpdateGlobalCfg(ps, pic);
6481 ps->ps_CheckConfigReq = TRUE;
6482 len = pGetFormLength(pic);
6483 if((buf = psdAllocVec(len)))
6485 pInternalWriteForm(pic, buf);
6487 pUnlockSem(ps, &ps->ps_ConfigLock);
6488 return(buf);
6489 AROS_LIBFUNC_EXIT
6491 /* \\\ */
6493 /* /// "psdFindCfgForm()" */
6494 AROS_LH2(struct PsdIFFContext *, psdFindCfgForm,
6495 AROS_LHA(struct PsdIFFContext *, pic, A0),
6496 AROS_LHA(ULONG, formid, D0),
6497 LIBBASETYPEPTR, ps, 54, psd)
6499 AROS_LIBFUNC_INIT
6500 struct PsdIFFContext *subpic;
6502 KPRINTF(160, ("psdFindCfgForm(0x%p, 0x%08lx)\n", pic, formid));
6503 pLockSemShared(ps, &ps->ps_ConfigLock);
6504 if(!pic)
6506 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6507 if(!(pic->pic_Node.ln_Succ))
6509 pUnlockSem(ps, &ps->ps_ConfigLock);
6510 return(NULL);
6513 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6514 while(subpic->pic_Node.ln_Succ)
6516 if(subpic->pic_FormID == formid)
6518 pUnlockSem(ps, &ps->ps_ConfigLock);
6519 return(subpic);
6521 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
6523 pUnlockSem(ps, &ps->ps_ConfigLock);
6524 return(NULL);
6525 AROS_LIBFUNC_EXIT
6527 /* \\\ */
6529 /* /// "psdNextCfgForm()" */
6530 AROS_LH1(struct PsdIFFContext *, psdNextCfgForm,
6531 AROS_LHA(struct PsdIFFContext *, pic, A0),
6532 LIBBASETYPEPTR, ps, 55, psd)
6534 AROS_LIBFUNC_INIT
6535 ULONG formid;
6536 KPRINTF(160, ("psdNextCfgForm(%p)\n", pic));
6538 if(!pic)
6540 return(NULL);
6542 pLockSemShared(ps, &ps->ps_ConfigLock);
6543 formid = pic->pic_FormID;
6544 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6545 while(pic->pic_Node.ln_Succ)
6547 if(pic->pic_FormID == formid)
6549 pUnlockSem(ps, &ps->ps_ConfigLock);
6551 KPRINTF(1, ("Found context 0x%p\n", pic));
6552 return(pic);
6554 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6556 pUnlockSem(ps, &ps->ps_ConfigLock);
6557 return(NULL);
6558 AROS_LIBFUNC_EXIT
6560 /* \\\ */
6562 /* /// "psdAllocCfgForm()" */
6563 AROS_LH1(struct PsdIFFContext *, psdAllocCfgForm,
6564 AROS_LHA(ULONG, formid, D0),
6565 LIBBASETYPEPTR, ps, 86, psd)
6567 AROS_LIBFUNC_INIT
6568 struct PsdIFFContext *pic;
6569 KPRINTF(10, ("psdAllocCfgForm(%p)\n", formid));
6570 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
6572 NewList(&pic->pic_SubForms);
6573 //pic->pic_Parent = parent;
6574 pic->pic_FormID = formid;
6575 pic->pic_FormLength = 4;
6576 pic->pic_Chunks = NULL;
6577 pic->pic_ChunksLen = 0;
6578 pic->pic_BufferLen = 0;
6579 Forbid();
6580 AddTail(&ps->ps_AlienConfigs, &pic->pic_Node);
6581 Permit();
6583 return(pic);
6584 AROS_LIBFUNC_EXIT
6586 /* \\\ */
6588 /* /// "psdRemCfgForm()" */
6589 AROS_LH1(void, psdRemCfgForm,
6590 AROS_LHA(struct PsdIFFContext *, pic, A0),
6591 LIBBASETYPEPTR, ps, 56, psd)
6593 AROS_LIBFUNC_INIT
6594 KPRINTF(10, ("psdRemCfgForm(%p)\n", pic));
6596 pLockSemExcl(ps, &ps->ps_ConfigLock);
6597 if(!pic)
6599 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6600 if(!(pic->pic_Node.ln_Succ))
6602 pUnlockSem(ps, &ps->ps_ConfigLock);
6603 return;
6606 pFreeForm(ps, pic);
6607 pUnlockSem(ps, &ps->ps_ConfigLock);
6608 ps->ps_CheckConfigReq = TRUE;
6609 AROS_LIBFUNC_EXIT
6611 /* \\\ */
6613 /* /// "psdAddCfgEntry()" */
6614 AROS_LH2(struct PsdIFFContext *, psdAddCfgEntry,
6615 AROS_LHA(struct PsdIFFContext *, pic, A0),
6616 AROS_LHA(APTR, formdata, A1),
6617 LIBBASETYPEPTR, ps, 57, psd)
6619 AROS_LIBFUNC_INIT
6620 struct PsdIFFContext *res;
6622 KPRINTF(10, ("psdAddCfgEntry(%p, %p)\n", pic, formdata));
6623 pLockSemExcl(ps, &ps->ps_ConfigLock);
6624 if(!pic)
6626 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6627 if(!(pic->pic_Node.ln_Succ))
6629 pUnlockSem(ps, &ps->ps_ConfigLock);
6630 return(NULL);
6633 res = pAddCfgChunk(ps, pic, formdata);
6634 pUnlockSem(ps, &ps->ps_ConfigLock);
6635 ps->ps_CheckConfigReq = TRUE;
6636 return(res);
6637 AROS_LIBFUNC_EXIT
6639 /* \\\ */
6641 /* /// "psdRemCfgChunk()" */
6642 AROS_LH2(BOOL, psdRemCfgChunk,
6643 AROS_LHA(struct PsdIFFContext *, pic, A0),
6644 AROS_LHA(ULONG, chnkid, D0),
6645 LIBBASETYPEPTR, ps, 58, psd)
6647 AROS_LIBFUNC_INIT
6648 BOOL res = FALSE;
6650 KPRINTF(10, ("psdRemCfgChunk(%p, %p)\n", pic, chnkid));
6651 pLockSemExcl(ps, &ps->ps_ConfigLock);
6652 if(!pic)
6654 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6655 if(!(pic->pic_Node.ln_Succ))
6657 pUnlockSem(ps, &ps->ps_ConfigLock);
6658 return(FALSE);
6661 if(chnkid)
6663 res = pRemCfgChunk(ps, pic, chnkid);
6664 } else {
6665 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6666 while(subpic->pic_Node.ln_Succ)
6668 pFreeForm(ps, subpic);
6669 res = TRUE;
6670 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6672 if(pic->pic_ChunksLen)
6674 res = TRUE;
6676 pic->pic_ChunksLen = 0;
6677 pic->pic_FormLength = 4;
6680 pUnlockSem(ps, &ps->ps_ConfigLock);
6681 ps->ps_CheckConfigReq = TRUE;
6682 return(res);
6683 AROS_LIBFUNC_EXIT
6685 /* \\\ */
6687 /* /// "psdGetCfgChunk()" */
6688 AROS_LH2(APTR, psdGetCfgChunk,
6689 AROS_LHA(struct PsdIFFContext *, pic, A0),
6690 AROS_LHA(ULONG, chnkid, D0),
6691 LIBBASETYPEPTR, ps, 59, psd)
6693 AROS_LIBFUNC_INIT
6694 ULONG *chnk;
6695 ULONG *res = NULL;
6697 KPRINTF(10, ("psdGetCfgChunk(%p, 0x%08lx)\n", pic, chnkid));
6699 pLockSemShared(ps, &ps->ps_ConfigLock);
6700 if(!pic)
6702 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6703 if(!(pic->pic_Node.ln_Succ))
6705 pUnlockSem(ps, &ps->ps_ConfigLock);
6706 return(NULL);
6709 pUpdateGlobalCfg(ps, pic);
6710 chnk = pFindCfgChunk(ps, pic, chnkid);
6711 if(chnk)
6713 res = psdAllocVec(AROS_LONG2BE(chnk[1])+8);
6714 if(res)
6716 memcpy(res, chnk, AROS_LONG2BE(chnk[1])+8);
6719 pUnlockSem(ps, &ps->ps_ConfigLock);
6720 return(res);
6721 AROS_LIBFUNC_EXIT
6723 /* \\\ */
6725 /* /// "psdParseCfg()" */
6726 AROS_LH0(void, psdParseCfg,
6727 LIBBASETYPEPTR, ps, 60, psd)
6729 AROS_LIBFUNC_INIT
6730 struct PsdIFFContext *pic;
6731 struct PsdIFFContext *subpic;
6732 ULONG *chnk;
6733 STRPTR name;
6734 ULONG unit;
6735 struct PsdHardware *phw;
6736 struct PsdUsbClass *puc;
6737 BOOL removeall = TRUE;
6738 BOOL nodos = (FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS);
6739 IPTR restartme;
6741 XPRINTF(10, ("psdParseCfg()\n"));
6743 pLockSemShared(ps, &ps->ps_ConfigLock);
6744 pCheckCfgChanged(ps);
6745 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6746 if(!pic)
6748 pUnlockSem(ps, &ps->ps_ConfigLock);
6749 return;
6752 // if no config for hardware is found, we don't remove the devices,
6753 // because this could render the system useless (no USB mice or
6754 // keyboards to configure the hardware!)
6755 if(!psdFindCfgForm(pic, IFFFORM_UHWDEVICE))
6757 XPRINTF(10, ("No hardware data present\n"));
6758 removeall = FALSE;
6761 psdLockReadPBase();
6763 /* select all hardware devices for removal */
6764 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6765 while(phw->phw_Node.ln_Succ)
6767 phw->phw_RemoveMe = removeall;
6768 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6771 /* select all classes for removal */
6772 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6773 while(puc->puc_Node.ln_Succ)
6776 * For kickstart-resident classes we check usage count, and
6777 * remove them only if it's zero.
6778 * These classes can be responsible for devices which we can use
6779 * at boot time. If we happen to remove them, we can end up with
6780 * no input or storage devices at all.
6782 if (FindResident(puc->puc_ClassName))
6783 puc->puc_RemoveMe = (puc->puc_UseCnt == 0);
6784 else
6785 puc->puc_RemoveMe = TRUE;
6787 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6790 psdUnlockPBase();
6792 /* Get Hardware config */
6793 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6794 while(subpic)
6796 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6797 if(chnk)
6799 name = (STRPTR) &chnk[2];
6800 unit = 0;
6801 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6802 if(chnk)
6804 unit = chnk[2];
6806 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6808 phw = pFindHardware(ps, name, unit);
6809 XPRINTF(5, ("Have configuration for device 0x%p (%s unit %u)\n", phw, name, unit));
6810 if(phw)
6812 phw->phw_RemoveMe = FALSE;
6816 subpic = psdNextCfgForm(subpic);
6819 /* Get Class config */
6820 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6821 while(subpic)
6823 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6824 if(chnk)
6826 name = (STRPTR) &chnk[2];
6827 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6828 XPRINTF(5, ("Have configuration for class 0x%p (%s)\n", puc, name));
6829 if(puc)
6831 puc->puc_RemoveMe = FALSE;
6834 subpic = psdNextCfgForm(subpic);
6837 // unlock config while removing to avoid deadlocks.
6838 pUnlockSem(ps, &ps->ps_ConfigLock);
6840 /* now remove remaining classes not found in the config */
6841 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6842 while(puc->puc_Node.ln_Succ)
6844 if(puc->puc_RemoveMe)
6846 XPRINTF(5, ("Removing class %s\n", puc->puc_ClassName));
6847 psdRemClass(puc);
6848 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6849 } else {
6850 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6854 /* now remove all remaining hardware not found in the config */
6855 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6856 while(phw->phw_Node.ln_Succ)
6858 if(phw->phw_RemoveMe)
6860 XPRINTF(5, ("Removing device %s unit %u\n", phw->phw_DevName, phw->phw_Unit));
6861 psdRemHardware(phw);
6862 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6863 } else {
6864 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6868 pLockSemShared(ps, &ps->ps_ConfigLock);
6869 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6870 if(!pic)
6872 pUnlockSem(ps, &ps->ps_ConfigLock);
6873 // oops!
6874 return;
6877 /* Add missing Classes */
6878 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6879 while(subpic)
6881 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6882 if(chnk)
6884 /* *** FIXME *** POSSIBLE DEADLOCK WHEN CLASS TRIES TO DO CONFIG STUFF IN
6885 AN EXTERNAL TASK INSIDE LIBOPEN CODE */
6886 name = (STRPTR) &chnk[2];
6887 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6888 if(!puc)
6890 psdAddClass(name, 0);
6893 subpic = psdNextCfgForm(subpic);
6896 /* Now really mount Hardware found in config */
6897 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6898 while(subpic)
6900 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6901 if(chnk)
6903 name = (STRPTR) &chnk[2];
6904 unit = 0;
6905 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6906 if(chnk)
6908 unit = chnk[2];
6910 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6912 phw = pFindHardware(ps, name, unit);
6913 if(!phw)
6915 phw = psdAddHardware(name, unit);
6916 if(phw)
6918 #ifdef AROS_USB30_CODE
6919 if(psdEnumerateHardware(phw) == NULL) {
6920 psdRemHardware(phw);
6922 #else
6923 psdEnumerateHardware(phw);
6924 #endif
6929 subpic = psdNextCfgForm(subpic);
6931 pUnlockSem(ps, &ps->ps_ConfigLock);
6933 if(!nodos && ps->ps_StartedAsTask)
6935 // last time we were reading the config before DOS, so maybe we need to
6936 // unbind some classes that need to be overruled by newly available classes,
6937 // such as hid.class overruling bootmouse & bootkeyboard.
6938 // so unbind those classes that promote themselves as AfterDOS
6940 psdLockReadPBase();
6941 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Checking AfterDOS...");
6942 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6943 while(puc->puc_Node.ln_Succ)
6945 restartme = FALSE;
6946 usbGetAttrs(UGA_CLASS, NULL,
6947 UCCA_AfterDOSRestart, &restartme,
6948 TAG_END);
6950 if(restartme && puc->puc_UseCnt)
6952 struct PsdDevice *pd;
6953 struct PsdConfig *pc;
6954 struct PsdInterface *pif;
6956 /* Well, try to release the open bindings in a best effort attempt */
6957 pd = NULL;
6958 while((pd = psdGetNextDevice(pd)))
6960 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
6962 psdUnlockPBase();
6963 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6964 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6965 puc->puc_ClassName, "device", pd->pd_ProductStr);
6966 psdReleaseDevBinding(pd);
6967 psdLockReadPBase();
6968 pd = NULL; /* restart */
6969 continue;
6971 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6972 while(pc->pc_Node.ln_Succ)
6974 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6975 while(pif->pif_Node.ln_Succ)
6977 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
6979 psdUnlockPBase();
6980 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6981 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6982 puc->puc_ClassName, "interface", pd->pd_ProductStr);
6983 psdReleaseIfBinding(pif);
6984 psdLockReadPBase();
6985 pd = NULL; /* restart */
6986 continue;
6988 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6990 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6994 usbDoMethodA(UCM_DOSAvailableEvent, NULL);
6995 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6997 ps->ps_StartedAsTask = FALSE;
6998 psdUnlockPBase();
7001 if(nodos && (!ps->ps_ConfigRead))
7003 // it's the first time we were reading the config and DOS was not available
7004 ps->ps_StartedAsTask = TRUE;
7006 ps->ps_ConfigRead = TRUE;
7007 ps->ps_SavedConfigHash = ps->ps_ConfigHash; // update saved hash
7009 /* do a class scan */
7010 psdClassScan();
7012 if(nodos && ps->ps_GlobalCfg->pgc_BootDelay)
7014 // wait for hubs to settle
7015 psdDelayMS(1000);
7016 puc = (struct PsdUsbClass *) FindName(&ps->ps_Classes, "massstorage.class");
7017 if(puc && puc->puc_UseCnt)
7019 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
7020 "Delaying further execution by %ld second(s) (boot delay).",
7021 ps->ps_GlobalCfg->pgc_BootDelay);
7022 if(ps->ps_GlobalCfg->pgc_BootDelay >= 1)
7024 psdDelayMS((ps->ps_GlobalCfg->pgc_BootDelay-1)*1000);
7026 } else {
7027 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Boot delay skipped, no mass storage devices found.");
7030 AROS_LIBFUNC_EXIT
7032 /* \\\ */
7034 /* /// "psdSetClsCfg()" */
7035 AROS_LH2(BOOL, psdSetClsCfg,
7036 AROS_LHA(STRPTR, owner, A0),
7037 AROS_LHA(APTR, form, A1),
7038 LIBBASETYPEPTR, ps, 62, psd)
7040 AROS_LIBFUNC_INIT
7041 struct PsdIFFContext *pic;
7042 BOOL result = FALSE;
7044 KPRINTF(10, ("psdSetClsCfg(%s, %p)\n", owner, form));
7045 pLockSemExcl(ps, &ps->ps_ConfigLock);
7046 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7047 while(pic)
7049 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7051 pic = psdFindCfgForm(pic, IFFFORM_CLASSDATA);
7052 if(pic)
7054 if(form)
7056 result = psdReadCfg(pic, form);
7057 } else {
7058 psdRemCfgChunk(pic, 0);
7059 result = TRUE;
7061 break;
7062 } else {
7063 break;
7066 pic = psdNextCfgForm(pic);
7068 if(result)
7070 pUnlockSem(ps, &ps->ps_ConfigLock);
7071 pCheckCfgChanged(ps);
7072 return(result);
7074 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7075 if(pic->pic_Node.ln_Succ)
7077 pic = pAllocForm(ps, pic, IFFFORM_CLASSCFG);
7078 if(pic)
7080 if(pAddStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7082 if(form)
7084 if(pAddCfgChunk(ps, pic, form))
7086 pUnlockSem(ps, &ps->ps_ConfigLock);
7087 pCheckCfgChanged(ps);
7088 return(TRUE);
7090 } else {
7091 ULONG buf[3];
7092 buf[0] = AROS_LONG2BE(ID_FORM);
7093 buf[1] = AROS_LONG2BE(4);
7094 buf[2] = AROS_LONG2BE(IFFFORM_CLASSDATA);
7095 if(pAddCfgChunk(ps, pic, buf))
7097 pUnlockSem(ps, &ps->ps_ConfigLock);
7098 pCheckCfgChanged(ps);
7099 return(TRUE);
7105 pUnlockSem(ps, &ps->ps_ConfigLock);
7106 pCheckCfgChanged(ps);
7107 return(FALSE);
7108 AROS_LIBFUNC_EXIT
7110 /* \\\ */
7112 /* /// "psdGetClsCfg()" */
7113 AROS_LH1(struct PsdIFFContext *, psdGetClsCfg,
7114 AROS_LHA(STRPTR, owner, A0),
7115 LIBBASETYPEPTR, ps, 63, psd)
7117 AROS_LIBFUNC_INIT
7118 struct PsdIFFContext *pic;
7120 KPRINTF(10, ("psdGetClsCfg(%s)\n", owner));
7121 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7122 while(pic)
7124 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7126 return(psdFindCfgForm(pic, IFFFORM_CLASSDATA));
7128 pic = psdNextCfgForm(pic);
7130 return(NULL);
7131 AROS_LIBFUNC_EXIT
7133 /* \\\ */
7135 /* /// "psdSetUsbDevCfg()" */
7136 AROS_LH4(BOOL, psdSetUsbDevCfg,
7137 AROS_LHA(STRPTR, owner, A0),
7138 AROS_LHA(STRPTR, devid, A2),
7139 AROS_LHA(STRPTR, ifid, A3),
7140 AROS_LHA(APTR, form, A1),
7141 LIBBASETYPEPTR, ps, 64, psd)
7143 AROS_LIBFUNC_INIT
7144 struct PsdIFFContext *pic;
7145 struct PsdIFFContext *cpic = NULL;
7146 struct PsdIFFContext *mpic = NULL;
7147 BOOL result = FALSE;
7149 KPRINTF(10, ("psdSetUsbDevCfg(%s, %s, %s, %p)\n", owner, devid, ifid, form));
7150 pLockSemExcl(ps, &ps->ps_ConfigLock);
7151 /* Find device config form. It contains all device config data */
7152 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7153 while(pic)
7155 /* Find DEVID-Chunk. Check if it matches our device id */
7156 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7158 cpic = NULL;
7159 /* We found the correct device. Now if we need to store interface data, find the interface first */
7160 if(ifid)
7162 /* Search interface config form */
7163 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7164 while(mpic)
7166 /* Found the form. Find the the ID String for the interface */
7167 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7169 /* ID did match, now check for owner */
7170 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7172 /* found it! So there is already a config saved in there. Search for dev config data form */
7173 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7174 if(!cpic)
7176 /* not found, generate it */
7177 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7179 break;
7182 mpic = psdNextCfgForm(mpic);
7184 if(!cpic)
7186 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7188 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7190 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7192 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7197 } else {
7198 /* Search for device config */
7199 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7200 while(mpic)
7202 /* search for the right owner */
7203 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7205 /* found it! So there is already a config saved in there. Search for dev config data form */
7206 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7207 if(!cpic)
7209 /* not found, generate it */
7210 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7212 break;
7214 mpic = psdNextCfgForm(mpic);
7216 if(!cpic) /* no device config form */
7218 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7220 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7222 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7227 if(cpic)
7229 if(form)
7231 result = psdReadCfg(cpic, form);
7232 } else {
7233 psdRemCfgChunk(cpic, 0);
7234 result = TRUE;
7236 break;
7239 pic = psdNextCfgForm(pic);
7241 if(result)
7243 pUnlockSem(ps, &ps->ps_ConfigLock);
7244 pCheckCfgChanged(ps);
7245 return(result);
7247 cpic = NULL;
7248 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7249 if(pic->pic_Node.ln_Succ)
7251 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7252 if(pic)
7254 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7256 if(ifid)
7258 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7260 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7262 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7264 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7268 } else {
7269 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7271 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7273 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7277 if(cpic)
7279 if(form)
7281 result = psdReadCfg(cpic, form);
7282 } else {
7283 psdRemCfgChunk(cpic, 0);
7284 result = TRUE;
7290 pUnlockSem(ps, &ps->ps_ConfigLock);
7291 pCheckCfgChanged(ps);
7292 return(result);
7293 AROS_LIBFUNC_EXIT
7295 /* \\\ */
7297 /* /// "psdGetUsbDevCfg()" */
7298 AROS_LH3(struct PsdIFFContext *, psdGetUsbDevCfg,
7299 AROS_LHA(STRPTR, owner, A0),
7300 AROS_LHA(STRPTR, devid, A2),
7301 AROS_LHA(STRPTR, ifid, A3),
7302 LIBBASETYPEPTR, ps, 65, psd)
7304 AROS_LIBFUNC_INIT
7305 struct PsdIFFContext *pic;
7306 struct PsdIFFContext *cpic = NULL;
7307 struct PsdIFFContext *mpic = NULL;
7309 KPRINTF(10, ("psdGetUsbDevCfg(%s, %s, %s)\n", owner, devid, ifid));
7310 pLockSemShared(ps, &ps->ps_ConfigLock);
7311 /* Find device config form. It contains all device config data */
7312 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7313 while(pic)
7315 /* Find DEVID-Chunk. Check if it matches our device id */
7316 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7318 cpic = NULL;
7319 /* We found the correct device. Now if we need to store interface data, find the interface first */
7320 if(ifid)
7322 /* Search interface config form */
7323 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7324 while(mpic)
7326 /* Found the form. Find the the ID String for the interface */
7327 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7329 /* ID did match, now check for owner */
7330 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7332 /* found it! So there is already a config saved in there. Search for dev config data form */
7333 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7334 break;
7337 mpic = psdNextCfgForm(mpic);
7339 } else {
7340 /* Search for device config */
7341 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7342 while(mpic)
7344 /* search for the right owner */
7345 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7347 /* found it! So there is already a config saved in there. Search for dev config data form */
7348 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7349 break;
7351 mpic = psdNextCfgForm(mpic);
7354 break;
7356 pic = psdNextCfgForm(pic);
7358 pUnlockSem(ps, &ps->ps_ConfigLock);
7359 KPRINTF(1, ("Result %p\n", cpic));
7360 return(cpic);
7361 AROS_LIBFUNC_EXIT
7363 /* \\\ */
7365 /* /// "psdSetForcedBinding()" */
7366 AROS_LH3(BOOL, psdSetForcedBinding,
7367 AROS_LHA(STRPTR, owner, A2),
7368 AROS_LHA(STRPTR, devid, A0),
7369 AROS_LHA(STRPTR, ifid, A1),
7370 LIBBASETYPEPTR, ps, 69, psd)
7372 AROS_LIBFUNC_INIT
7373 struct PsdIFFContext *pic;
7374 struct PsdIFFContext *mpic = NULL;
7375 ULONG olen = 0;
7376 BOOL result = FALSE;
7378 if(owner)
7380 olen = strlen(owner);
7382 pLockSemExcl(ps, &ps->ps_ConfigLock);
7383 /* Find device config form. It contains all device config data */
7384 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7385 while(pic)
7387 /* Find DEVID-Chunk. Check if it matches our device id */
7388 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7390 /* We found the correct device. Now if we need to store interface data, find the interface first */
7391 if(ifid)
7393 /* Search interface config form */
7394 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7395 while(mpic)
7397 /* Found the form. Find the the ID String for the interface */
7398 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7400 /* ID did match, insert/replace forced binding */
7401 if(olen)
7403 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7405 result = TRUE;
7407 } else {
7408 pRemCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7409 result = TRUE;
7412 mpic = psdNextCfgForm(mpic);
7414 if(!olen)
7416 result = TRUE;
7418 if((!result) && olen)
7420 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7422 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7424 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7426 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7428 result = TRUE;
7434 } else {
7435 /* Add FBND chunk */
7436 if(olen)
7438 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7440 result = TRUE;
7442 } else {
7443 pRemCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7444 result = TRUE;
7447 break;
7449 pic = psdNextCfgForm(pic);
7451 if(!olen)
7453 result = TRUE;
7455 if(result)
7457 pUnlockSem(ps, &ps->ps_ConfigLock);
7458 pCheckCfgChanged(ps);
7459 return(result);
7461 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7462 if(pic->pic_Node.ln_Succ)
7464 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7465 if(pic)
7467 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7469 if(ifid)
7471 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7473 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7475 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7477 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7479 result = TRUE;
7484 } else {
7485 /* Add FBND chunk */
7486 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7488 result = TRUE;
7494 pUnlockSem(ps, &ps->ps_ConfigLock);
7495 pCheckCfgChanged(ps);
7496 return(result);
7497 AROS_LIBFUNC_EXIT
7499 /* \\\ */
7501 /* /// "psdGetForcedBinding()" */
7502 AROS_LH2(STRPTR, psdGetForcedBinding,
7503 AROS_LHA(STRPTR, devid, A0),
7504 AROS_LHA(STRPTR, ifid, A1),
7505 LIBBASETYPEPTR, ps, 70, psd)
7507 AROS_LIBFUNC_INIT
7508 struct PsdIFFContext *pic;
7509 struct PsdIFFContext *mpic = NULL;
7510 ULONG *chunk;
7511 STRPTR owner = NULL;
7513 pLockSemShared(ps, &ps->ps_ConfigLock);
7514 /* Find device config form. It contains all device config data */
7515 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7516 while(pic)
7518 /* Find DEVID-Chunk. Check if it matches our device id */
7519 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7521 /* We found the correct device. Now if we need to store interface data, find the interface first */
7522 if(ifid)
7524 /* Search interface config form */
7525 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7526 while(mpic)
7528 /* Found the form. Find the the ID String for the interface */
7529 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7531 /* ID did match, now check for forced binding */
7532 chunk = pFindCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7533 if(chunk)
7535 owner = (STRPTR) &chunk[2];
7536 break;
7539 mpic = psdNextCfgForm(mpic);
7541 } else {
7542 /* Search for device forced binding */
7543 chunk = pFindCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7544 if(chunk)
7546 owner = (STRPTR) &chunk[2];
7547 break;
7550 break;
7552 pic = psdNextCfgForm(pic);
7554 pUnlockSem(ps, &ps->ps_ConfigLock);
7555 return(owner);
7556 AROS_LIBFUNC_EXIT
7558 /* \\\ */
7560 /* /// "psdAddStringChunk()" */
7561 AROS_LH3(BOOL, psdAddStringChunk,
7562 AROS_LHA(struct PsdIFFContext *, pic, A0),
7563 AROS_LHA(ULONG, chunkid, D0),
7564 AROS_LHA(CONST_STRPTR, str, A1),
7565 LIBBASETYPEPTR, ps, 87, psd)
7567 AROS_LIBFUNC_INIT
7568 BOOL res;
7569 KPRINTF(10, ("psdAddStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7570 pLockSemExcl(ps, &ps->ps_ConfigLock);
7571 res = pAddStringChunk(ps, pic, chunkid, str);
7572 pUnlockSem(ps, &ps->ps_ConfigLock);
7573 return(res);
7574 AROS_LIBFUNC_EXIT
7576 /* \\\ */
7578 /* /// "psdMatchStringChunk()" */
7579 AROS_LH3(BOOL, psdMatchStringChunk,
7580 AROS_LHA(struct PsdIFFContext *, pic, A0),
7581 AROS_LHA(ULONG, chunkid, D0),
7582 AROS_LHA(CONST_STRPTR, str, A1),
7583 LIBBASETYPEPTR, ps, 88, psd)
7585 AROS_LIBFUNC_INIT
7586 BOOL res;
7587 KPRINTF(10, ("psdMatchStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7588 pLockSemShared(ps, &ps->ps_ConfigLock);
7589 res = pMatchStringChunk(ps, pic, chunkid, str);
7590 pUnlockSem(ps, &ps->ps_ConfigLock);
7591 return(res);
7592 AROS_LIBFUNC_EXIT
7594 /* \\\ */
7596 /* /// "psdGetStringChunk()" */
7597 AROS_LH2(STRPTR, psdGetStringChunk,
7598 AROS_LHA(struct PsdIFFContext *, pic, A0),
7599 AROS_LHA(ULONG, chunkid, D0),
7600 LIBBASETYPEPTR, ps, 89, psd)
7602 AROS_LIBFUNC_INIT
7603 STRPTR str;
7604 KPRINTF(10, ("psdGetStringChunk(%p, %p)\n", pic, chunkid));
7605 pLockSemShared(ps, &ps->ps_ConfigLock);
7606 str = pGetStringChunk(ps, pic, chunkid);
7607 pUnlockSem(ps, &ps->ps_ConfigLock);
7608 return(str);
7609 AROS_LIBFUNC_EXIT
7611 /* \\\ */
7613 /* *** Configuration (non-library subroutines) *** */
7615 /* /// "pAllocForm()" */
7616 struct PsdIFFContext * pAllocForm(LIBBASETYPEPTR ps, struct PsdIFFContext *parent, ULONG formid)
7618 struct PsdIFFContext *pic;
7619 KPRINTF(10, ("pAllocForm(%p, %p)\n", parent, formid));
7620 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
7622 NewList(&pic->pic_SubForms);
7623 //pic->pic_Parent = parent;
7624 pic->pic_FormID = formid;
7625 pic->pic_FormLength = 4;
7626 pic->pic_Chunks = NULL;
7627 pic->pic_ChunksLen = 0;
7628 pic->pic_BufferLen = 0;
7629 Forbid();
7630 if(parent)
7632 AddTail(&parent->pic_SubForms, &pic->pic_Node);
7633 } else {
7634 AddTail(&ps->ps_ConfigRoot, &pic->pic_Node);
7636 Permit();
7638 return(pic);
7640 /* \\\ */
7642 /* /// "pFreeForm()" */
7643 void pFreeForm(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7645 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7646 KPRINTF(10, ("pFreeForm(%p)\n", pic));
7647 Remove(&pic->pic_Node);
7648 while(subpic->pic_Node.ln_Succ)
7650 pFreeForm(ps, subpic);
7651 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7653 psdFreeVec(pic->pic_Chunks);
7654 psdFreeVec(pic);
7656 /* \\\ */
7658 /* /// "pGetFormLength()" */
7659 ULONG pGetFormLength(struct PsdIFFContext *pic)
7661 ULONG len = (5 + pic->pic_ChunksLen) & ~1UL;
7662 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7663 //KPRINTF(10, ("pGetFormLength(%p)\n", pic));
7664 while(subpic->pic_Node.ln_Succ)
7666 len += pGetFormLength(subpic);
7667 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7669 pic->pic_FormLength = len;
7670 //KPRINTF(10, ("FormLen=%ld\n", len+8));
7671 return(len + 8);
7673 /* \\\ */
7675 /* /// "pFindCfgChunk()" */
7676 APTR pFindCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7678 ULONG *buf = pic->pic_Chunks;
7679 ULONG len = pic->pic_ChunksLen;
7680 ULONG chlen;
7681 KPRINTF(10, ("pFindCfgChunk(%p, %p)\n", pic, chnkid));
7683 while(len)
7685 if(AROS_LONG2BE(*buf) == chnkid)
7687 KPRINTF(10, ("Found at %p\n", buf));
7688 return(buf);
7690 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7691 len -= chlen;
7692 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7694 KPRINTF(10, ("Not found!\n"));
7695 return(NULL);
7697 /* \\\ */
7699 /* /// "pRemCfgChunk()" */
7700 BOOL pRemCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7702 ULONG *buf = pic->pic_Chunks;
7703 ULONG len = pic->pic_ChunksLen;
7704 ULONG chlen;
7705 KPRINTF(10, ("pRemCfgChunk(%p, %p)\n", pic, chnkid));
7707 while(len)
7709 chlen = ((AROS_LONG2BE(buf[1])) + 9) & ~1UL;
7710 if(AROS_LONG2BE(*buf) == chnkid)
7712 len -= chlen;
7713 if(len)
7715 memcpy(buf, &((UBYTE *) buf)[chlen], (size_t) len);
7717 pic->pic_ChunksLen -= chlen;
7718 KPRINTF(10, ("Deleted %ld bytes to %ld chunk len\n", chlen, pic->pic_ChunksLen));
7719 return(TRUE);
7721 len -= chlen;
7722 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7724 KPRINTF(10, ("Not found!\n"));
7725 return(FALSE);
7727 /* \\\ */
7729 /* /// "pAddCfgChunk()" */
7730 struct PsdIFFContext * pAddCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, APTR chunk)
7732 LONG len;
7733 LONG chlen;
7734 ULONG *buf = chunk;
7735 ULONG *newbuf;
7736 struct PsdIFFContext *subpic;
7737 KPRINTF(10, ("pAddCfgChunk(%p, %p)\n", pic, chunk));
7738 if(AROS_LONG2BE(*buf) == ID_FORM)
7740 buf++;
7741 len = ((AROS_LONG2BE(*buf)) - 3) & ~1UL;
7742 buf++;
7743 if((subpic = pAllocForm(ps, pic, AROS_LONG2BE(*buf))))
7745 buf++;
7746 while(len >= 8)
7748 if(!(pAddCfgChunk(ps, subpic, buf)))
7750 break;
7752 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7753 len -= chlen;
7754 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7756 if(len)
7758 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
7759 return(NULL);
7761 } else {
7762 return(NULL);
7764 return(subpic);
7765 } else {
7766 pRemCfgChunk(ps, pic, AROS_LONG2BE(*buf));
7767 len = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7768 if(pic->pic_ChunksLen+len > pic->pic_BufferLen)
7770 KPRINTF(10, ("expanding buffer from %ld to %ld to fit %ld bytes\n", pic->pic_BufferLen, (pic->pic_ChunksLen+len)<<1, pic->pic_ChunksLen+len));
7772 /* Expand buffer */
7773 if((newbuf = psdAllocVec((pic->pic_ChunksLen+len)<<1)))
7775 if(pic->pic_ChunksLen)
7777 memcpy(newbuf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7778 psdFreeVec(pic->pic_Chunks);
7780 pic->pic_Chunks = newbuf;
7781 pic->pic_BufferLen = (pic->pic_ChunksLen+len)<<1;
7782 } else {
7783 return(NULL);
7786 memcpy(&(((UBYTE *) pic->pic_Chunks)[pic->pic_ChunksLen]), chunk, (size_t) len);
7787 pic->pic_ChunksLen += len;
7788 return(pic);
7791 /* \\\ */
7793 /* /// "pInternalWriteForm()" */
7794 ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf)
7796 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7797 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7798 *buf++ = AROS_LONG2BE(ID_FORM);
7799 *buf++ = AROS_LONG2BE(pic->pic_FormLength);
7800 *buf++ = AROS_LONG2BE(pic->pic_FormID);
7801 if(pic->pic_ChunksLen)
7803 memcpy(buf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7804 buf = (ULONG *) (((UBYTE *) buf) + pic->pic_ChunksLen);
7806 while(subpic->pic_Node.ln_Succ)
7808 buf = pInternalWriteForm(subpic, buf);
7809 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7811 return(buf);
7813 /* \\\ */
7815 /* /// "pCalcCfgCRC()" */
7816 ULONG pCalcCfgCRC(struct PsdIFFContext *pic)
7818 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7819 ULONG len;
7820 ULONG crc = pic->pic_FormID;
7821 UWORD *ptr;
7823 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7824 if(pic->pic_ChunksLen)
7826 len = pic->pic_ChunksLen>>1;
7827 if(len)
7829 ptr = (UWORD *) pic->pic_Chunks;
7832 crc = ((crc<<1)|(crc>>31))^(*ptr++);
7833 } while(--len);
7836 while(subpic->pic_Node.ln_Succ)
7838 crc ^= pCalcCfgCRC(subpic);
7839 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7841 return(crc);
7843 /* \\\ */
7845 /* /// "pCheckCfgChanged()" */
7846 BOOL pCheckCfgChanged(LIBBASETYPEPTR ps)
7848 ULONG crc;
7849 struct PsdIFFContext *pic;
7850 struct PsdIFFContext *subpic;
7851 STRPTR tmpstr;
7853 pLockSemShared(ps, &ps->ps_ConfigLock);
7854 ps->ps_CheckConfigReq = FALSE;
7855 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7856 if(!(pic->pic_Node.ln_Succ))
7858 pUnlockSem(ps, &ps->ps_ConfigLock);
7859 return(FALSE);
7861 crc = pCalcCfgCRC(pic);
7862 if(crc != ps->ps_ConfigHash)
7864 ULONG *chnk;
7865 ps->ps_ConfigHash = crc;
7866 /* Get Global config */
7867 if((subpic = psdFindCfgForm(pic, IFFFORM_STACKCFG)))
7869 if((chnk = pFindCfgChunk(ps, subpic, IFFCHNK_GLOBALCFG)))
7871 CopyMem(&chnk[2], ((UBYTE *) ps->ps_GlobalCfg) + 8, min(AROS_LONG2BE(chnk[1]), AROS_LONG2BE(ps->ps_GlobalCfg->pgc_Length)));
7873 if(!pMatchStringChunk(ps, subpic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile))
7875 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_INSERTSND)))
7877 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
7878 ps->ps_PoPo.po_InsertSndFile = tmpstr;
7881 if(!pMatchStringChunk(ps, subpic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile))
7883 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_REMOVESND)))
7885 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
7886 ps->ps_PoPo.po_RemoveSndFile = tmpstr;
7890 pUnlockSem(ps, &ps->ps_ConfigLock);
7891 psdSendEvent(EHMB_CONFIGCHG, NULL, NULL);
7892 return(TRUE);
7894 pUnlockSem(ps, &ps->ps_ConfigLock);
7895 return(FALSE);
7897 /* \\\ */
7899 /* /// "pAddStringChunk()" */
7900 BOOL pAddStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7902 BOOL res = FALSE;
7903 ULONG len = strlen(str);
7904 ULONG *chnk = (ULONG *) psdAllocVec((ULONG) len+8+2);
7905 if(chnk)
7907 chnk[0] = AROS_LONG2BE(chunkid);
7908 chnk[1] = AROS_LONG2BE(len+1);
7909 strcpy((STRPTR) &chnk[2], str);
7910 if(pAddCfgChunk(ps, pic, chnk))
7912 res = TRUE;
7914 psdFreeVec(chnk);
7916 return(res);
7918 /* \\\ */
7920 /* /// "pMatchStringChunk()" */
7921 BOOL pMatchStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7923 ULONG *chunk;
7924 ULONG len;
7925 STRPTR srcptr;
7926 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7928 srcptr = (STRPTR) &chunk[2];
7929 len = AROS_LONG2BE(chunk[1]);
7930 while(len-- && *srcptr)
7932 if(*str++ != *srcptr++)
7934 return(FALSE);
7937 if(!*str)
7939 return(TRUE);
7942 return(FALSE);
7944 /* \\\ */
7946 /* /// "pGetStringChunk()" */
7947 STRPTR pGetStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid)
7949 ULONG *chunk;
7950 STRPTR str;
7951 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7953 if((str = (STRPTR) psdAllocVec(AROS_LONG2BE(chunk[1]) + 1)))
7955 memcpy(str, &chunk[2], (size_t) AROS_LONG2BE(chunk[1]));
7956 return(str);
7959 return(NULL);
7961 /* \\\ */
7963 /* /// "pUpdateGlobalCfg()" */
7964 void pUpdateGlobalCfg(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7966 struct PsdIFFContext *tmppic;
7967 /* Set Global config */
7968 if(pic == (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head)
7970 if((tmppic = psdFindCfgForm(NULL, IFFFORM_STACKCFG)))
7972 pAddCfgChunk(ps, tmppic, ps->ps_GlobalCfg);
7973 pAddStringChunk(ps, tmppic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile);
7974 pAddStringChunk(ps, tmppic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile);
7978 /* \\\ */
7980 /* *** Misc (non library functions) ***/
7982 /* /// "pGetDevConfig()" */
7983 BOOL pGetDevConfig(struct PsdPipe *pp)
7985 struct PsdDevice *pd = pp->pp_Device;
7986 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
7987 UBYTE *tempbuf;
7988 struct UsbStdCfgDesc uscd;
7989 ULONG len;
7990 LONG ioerr;
7991 STRPTR classname;
7992 UWORD curcfg = 0;
7994 KPRINTF(1, ("Getting configuration descriptor...\n"));
7995 psdLockWriteDevice(pd);
7996 while(curcfg < pd->pd_NumCfgs)
7998 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
7999 USR_GET_DESCRIPTOR, (UDT_CONFIGURATION<<8)|curcfg, 0);
8001 /*tempbuf = psdAllocVec(256);
8002 ioerr = psdDoPipe(pp, tempbuf, 34);
8003 if(ioerr == UHIOERR_RUNTPACKET)
8005 ioerr = 0;
8007 memcpy(&uscd, tempbuf, 9);*/
8008 ioerr = psdDoPipe(pp, &uscd, 9);//sizeof(struct UsbStdCfgDesc));
8009 if(!ioerr)
8011 KPRINTF(1, ("Config type: %ld\n", (ULONG) uscd.bDescriptorType));
8012 len = (ULONG) AROS_WORD2LE(uscd.wTotalLength);
8013 KPRINTF(1, ("Configsize %ld, total size %ld\n", (ULONG) uscd.bLength, len));
8014 if((tempbuf = psdAllocVec(len)))
8015 //if(1)
8017 KPRINTF(1, ("Getting whole configuration descriptor...\n"));
8018 ioerr = psdDoPipe(pp, tempbuf, len);
8019 if(!ioerr)
8021 struct PsdConfig *pc = NULL;
8022 struct PsdInterface *pif = NULL;
8023 struct PsdInterface *altif = NULL;
8024 struct PsdEndpoint *pep = NULL;
8025 struct PsdDescriptor *pdd = NULL;
8026 UBYTE *dbuf = tempbuf;
8027 UBYTE *bufend;
8028 ULONG dlen;
8029 bufend = &dbuf[len];
8030 while(dbuf < bufend)
8032 dlen = dbuf[0]; /* bLength */
8033 if(dlen < 2)
8035 break;
8037 if(&dbuf[dlen] > bufend)
8039 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "End of descriptor past buffer!");
8041 switch(dbuf[1]) /* bDescriptorType */
8043 case UDT_CONFIGURATION:
8045 struct UsbStdCfgDesc *usc = (struct UsbStdCfgDesc *) dbuf;
8046 pif = NULL;
8047 altif = NULL;
8048 pep = NULL;
8049 if((pc = pAllocConfig(pd)))
8051 pd->pd_Flags |= PDFF_CONFIGURED;
8052 pc->pc_NumIfs = usc->bNumInterfaces;
8053 pc->pc_CfgNum = usc->bConfigurationValue;
8054 pc->pc_Attr = usc->bmAttributes;
8055 pc->pc_MaxPower = usc->bMaxPower<<1;
8056 pc->pc_CfgStr = 0;
8057 KPRINTF(1, (" Config %ld\n", pc->pc_CfgNum));
8058 if(usc->iConfiguration)
8060 pc->pc_CfgStr = psdGetStringDescriptor(pp, usc->iConfiguration);
8062 if(!pc->pc_CfgStr)
8064 pc->pc_CfgStr = psdCopyStrFmt("Configuration %ld", pc->pc_CfgNum);
8066 } else {
8067 KPRINTF(20, (" Config allocation failed\n"));
8069 break;
8072 case UDT_INTERFACE:
8074 struct UsbStdIfDesc *usif = (struct UsbStdIfDesc *) dbuf;
8075 pep = NULL;
8076 if(pc)
8078 if((altif = pAllocInterface(pc)))
8080 altif->pif_IfNum = usif->bInterfaceNumber;
8081 altif->pif_Alternate = usif->bAlternateSetting;
8082 altif->pif_NumEPs = usif->bNumEndpoints;
8083 altif->pif_IfClass = usif->bInterfaceClass;
8084 altif->pif_IfSubClass = usif->bInterfaceSubClass;
8085 altif->pif_IfProto = usif->bInterfaceProtocol;
8086 KPRINTF(2, (" Interface %ld\n", altif->pif_IfNum));
8087 if(usif->iInterface)
8089 altif->pif_IfStr = psdGetStringDescriptor(pp, usif->iInterface);
8091 if(!altif->pif_IfStr)
8093 classname = psdNumToStr(NTS_CLASSCODE, (LONG) altif->pif_IfClass, NULL);
8094 if(classname)
8096 altif->pif_IfStr = psdCopyStrFmt("%s interface (%ld)", classname, altif->pif_IfNum);
8097 } else {
8098 altif->pif_IfStr = psdCopyStrFmt("Interface %ld", altif->pif_IfNum);
8101 KPRINTF(2, (" IfName : %s\n"
8102 " Alternate : %ld\n"
8103 " NumEPs : %ld\n"
8104 " IfClass : %ld\n"
8105 " IfSubClass: %ld\n"
8106 " IfProto : %ld\n",
8107 altif->pif_IfStr, altif->pif_Alternate,
8108 altif->pif_NumEPs,
8109 altif->pif_IfClass,
8110 altif->pif_IfSubClass, altif->pif_IfProto));
8111 if(pc->pc_CfgNum == 1)
8113 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx",
8114 altif->pif_IfNum, altif->pif_Alternate,
8115 altif->pif_IfClass, altif->pif_IfSubClass,
8116 altif->pif_IfProto);
8117 } else {
8118 // for more than one config, add config number (retain backwards compatibility with most devices)
8119 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx-%02lx",
8120 pc->pc_CfgNum,
8121 altif->pif_IfNum, altif->pif_Alternate,
8122 altif->pif_IfClass, altif->pif_IfSubClass,
8123 altif->pif_IfProto);
8126 /* Move the interface to the alternatives if possible */
8127 if(altif->pif_Alternate)
8129 if(!pif)
8131 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Alternate interface without prior main interface!");
8132 KPRINTF(20, (" Alternate interface without prior main interface\n"));
8133 pif = altif;
8134 } else {
8135 Remove(&altif->pif_Node);
8136 AddTail(&pif->pif_AlterIfs, &altif->pif_Node);
8137 altif->pif_ParentIf = pif;
8139 } else {
8140 altif->pif_ParentIf = NULL;
8141 pif = altif;
8143 } else {
8144 KPRINTF(20, (" Interface allocation failed\n"));
8146 } else {
8147 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Interface without prior config descriptor!");
8148 KPRINTF(20, (" Interface descriptor without Config\n"));
8150 break;
8153 case UDT_ENDPOINT:
8155 struct UsbStdEPDesc *usep = (struct UsbStdEPDesc *) dbuf;
8156 if(altif)
8158 if((pep = pAllocEndpoint(altif)))
8160 STRPTR eptype;
8161 pep->pep_EPNum = usep->bEndpointAddress & 0x0f;
8162 pep->pep_Direction = usep->bEndpointAddress>>7;
8163 pep->pep_TransType = usep->bmAttributes & 0x03;
8164 pep->pep_SyncType = (usep->bmAttributes>>2) & 0x03;
8165 pep->pep_UsageType = (usep->bmAttributes>>4) & 0x03;
8166 eptype = (pep->pep_TransType == USEAF_INTERRUPT) ? "int" : "iso";
8168 pep->pep_MaxPktSize = AROS_WORD2LE(usep->wMaxPacketSize) & 0x07ff;
8169 pep->pep_NumTransMuFr = ((AROS_WORD2LE(usep->wMaxPacketSize)>>11) & 3) + 1;
8170 if(pep->pep_NumTransMuFr == 4)
8172 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains illegal Num Trans µFrame value!");
8173 pep->pep_NumTransMuFr = 1;
8176 pep->pep_Interval = usep->bInterval;
8177 if(pd->pd_Flags & PDFF_HIGHSPEED)
8179 switch(pep->pep_TransType)
8181 case USEAF_CONTROL:
8182 case USEAF_BULK:
8183 //pep->pep_Interval = 0; // no use here, NAK rate not of interest
8184 break;
8186 case USEAF_ISOCHRONOUS:
8187 if(pep->pep_MaxPktSize > 1024)
8189 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8190 "Endpoint contains %s (%ld) MaxPktSize value!",
8191 (STRPTR) "too high", pep->pep_MaxPktSize);
8192 pep->pep_MaxPktSize = 1024;
8195 case USEAF_INTERRUPT:
8196 if(!pep->pep_Interval)
8198 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8199 "%sspeed %s endpoint contains %s interval value! Fixing.",
8200 (STRPTR) "High", eptype, (STRPTR) "zero");
8201 pep->pep_Interval = 1;
8203 else if(pep->pep_Interval > 16)
8205 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8206 "%sspeed %s endpoint contains %s interval value! Fixing.",
8207 (STRPTR) "High", eptype, (STRPTR) "too high");
8208 pep->pep_Interval = 16;
8210 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8211 break;
8214 else if(pd->pd_Flags & PDFF_LOWSPEED)
8216 switch(pep->pep_TransType)
8218 case USEAF_INTERRUPT:
8219 if(pep->pep_Interval < 8)
8221 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8222 (STRPTR) "Low", eptype, (STRPTR) "too low");
8223 pep->pep_Interval = 8;
8225 break;
8227 case USEAF_CONTROL:
8228 case USEAF_BULK:
8229 pep->pep_Interval = 0; // no use here
8230 break;
8232 case USEAF_ISOCHRONOUS:
8233 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Lowspeed devices cannot have isochronous endpoints!");
8234 break;
8236 } else {
8237 switch(pep->pep_TransType)
8239 case USEAF_INTERRUPT:
8240 if(!pep->pep_Interval)
8242 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8243 (STRPTR) "Full", eptype, (STRPTR) "zero");
8244 pep->pep_Interval = 1;
8246 break;
8248 case USEAF_CONTROL:
8249 case USEAF_BULK:
8250 pep->pep_Interval = 0; // no use here
8251 break;
8253 case USEAF_ISOCHRONOUS:
8254 if(pep->pep_MaxPktSize > 1023)
8256 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains too high (%ld) MaxPktSize value! Fixing.", pep->pep_MaxPktSize);
8257 pep->pep_MaxPktSize = 1023;
8259 if(!pep->pep_Interval)
8261 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8262 (STRPTR) "Full", eptype, (STRPTR) "zero");
8263 pep->pep_Interval = 1;
8265 else if(pep->pep_Interval > 16)
8267 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8268 (STRPTR) "Full", eptype, (STRPTR) "too high");
8269 pep->pep_Interval = 16;
8271 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8272 break;
8276 KPRINTF(2, (" Endpoint %ld\n", pep->pep_EPNum));
8277 KPRINTF(2, (" Direction : %s\n"
8278 " TransType : %ld\n"
8279 " MaxPktSize: %ld\n"
8280 " Interval : %ld\n",
8281 (pep->pep_Direction ? "IN" : "OUT"),
8282 pep->pep_TransType, pep->pep_MaxPktSize,
8283 pep->pep_Interval));
8285 } else {
8286 KPRINTF(20, (" Endpoint allocation failed\n"));
8288 } else {
8289 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint without prior interface descriptor!");
8290 KPRINTF(20, (" Endpoint descriptor without Interface\n"));
8292 break;
8295 case UDT_DEVICE:
8296 case UDT_HUB:
8297 case UDT_HID:
8298 case UDT_REPORT:
8299 case UDT_PHYSICAL:
8300 case UDT_CS_INTERFACE:
8301 case UDT_CS_ENDPOINT:
8302 case UDT_DEVICE_QUALIFIER:
8303 case UDT_OTHERSPEED_QUALIFIER:
8304 case UDT_INTERFACE_POWER:
8305 case UDT_OTG:
8306 //psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping descriptor %02lx (pc=%p, pif=%p altpif=%p).", dbuf[1], pc, pif, altif);
8307 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8308 break;
8310 default:
8311 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping unknown descriptor %02lx.", dbuf[1]);
8312 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8313 break;
8315 // add descriptor to device
8316 pdd = pAllocDescriptor(pd, dbuf);
8317 if(pdd)
8319 STRPTR descname = NULL;
8321 pdd->pdd_Config = pc;
8322 pdd->pdd_Interface = altif;
8323 pdd->pdd_Endpoint = pep;
8324 if(pdd->pdd_Interface)
8326 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
8328 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8329 if(!descname)
8331 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8334 if(!descname)
8336 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8338 if(!descname)
8340 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8343 if(descname)
8345 pdd->pdd_Name = descname;
8348 dbuf += dlen;
8350 KPRINTF(1, ("Configuration acquired!\n"));
8351 psdFreeVec(tempbuf);
8352 curcfg++;
8353 continue;
8354 //psdUnlockDevice(pd);
8355 //return(TRUE);
8356 } else {
8357 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8358 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8359 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8360 KPRINTF(15, ("GET_DESCRIPTOR failed %ld!\n", ioerr));
8362 psdFreeVec(tempbuf);
8363 } else {
8364 KPRINTF(20, ("No memory for %ld bytes config temp buffer!\n", len));
8366 } else {
8367 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8368 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8369 9, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8370 KPRINTF(15, ("GET_DESCRIPTOR (9) failed %ld!\n", ioerr));
8372 psdUnlockDevice(pd);
8373 return(FALSE);
8375 psdUnlockDevice(pd);
8376 return(TRUE);
8378 /* \\\ */
8380 /* /// "pPowerRecurseDrain()" */
8381 ULONG pPowerRecurseDrain(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8383 struct PsdDevice *nextpd;
8384 struct PsdConfig *pc;
8385 UWORD maxdrain = 666;
8386 UWORD childdrain;
8387 BOOL selfpwd = TRUE;
8388 pd->pd_PowerDrain = 0;
8390 /* look at config */
8391 if((pc = pd->pd_CurrentConfig))
8394 /* if suspended, no more than 500µA are drained */
8395 if(pd->pd_Flags & PDFF_SUSPENDED)
8397 pd->pd_PowerDrain = (pc->pc_MaxPower >= 100) ? 3 : 1;
8398 return(pd->pd_PowerDrain);
8400 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8401 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8402 maxdrain = selfpwd ? 500 : 100;
8405 /* examine children */
8406 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8407 while(nextpd->pd_Node.ln_Succ)
8409 if(nextpd->pd_Hub == pd)
8411 childdrain = pPowerRecurseDrain(ps, nextpd);
8412 // limit the drain to the maximum power suckage
8413 pd->pd_PowerDrain += (childdrain > maxdrain) ? maxdrain : childdrain;
8415 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8418 /* look at config */
8419 if(selfpwd)
8421 pd->pd_PowerDrain = 0;
8422 } else {
8423 pd->pd_PowerDrain += pc->pc_MaxPower;
8425 return(pd->pd_PowerDrain);
8427 /* \\\ */
8429 /* /// "pPowerRecurseSupply()" */
8430 void pPowerRecurseSupply(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8432 struct PsdDevice *nextpd;
8433 struct PsdConfig *pc;
8434 UWORD ports = 0;
8435 UWORD supply = 666;
8436 BOOL selfpwd = TRUE;
8438 /* look at config */
8439 if((pc = pd->pd_CurrentConfig))
8441 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8442 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8445 /* count children */
8446 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8447 while(nextpd->pd_Node.ln_Succ)
8449 if(nextpd->pd_Hub == pd) // this device is a child of us (we're a hub!)
8451 ports++;
8453 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8456 /* look at config */
8457 if(selfpwd)
8459 if(pc)
8461 pd->pd_PowerSupply = ports ? 500*ports + pc->pc_MaxPower : pc->pc_MaxPower;
8463 supply = 500; // each downstream port gets the full monty
8464 } else {
8465 // the parent hub has already set the amount of supply for this port
8466 if(pd->pd_PowerSupply >= pc->pc_MaxPower)
8468 // the downstream ports get the remaining divided attention
8469 if(ports)
8471 // avoid division by zero
8472 supply = (pd->pd_PowerSupply - pc->pc_MaxPower) / ports;
8473 if(supply > 100)
8475 // limit to 100 mA per port
8476 supply = 100;
8479 } else {
8480 supply = 1; // bad luck, out of power
8484 /* set supply */
8485 if(ports) /* needs to be a hub */
8487 // propagate supply down to the children
8488 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8489 while(nextpd->pd_Node.ln_Succ)
8491 if(nextpd->pd_Hub == pd)
8493 nextpd->pd_PowerSupply = supply;
8494 pPowerRecurseSupply(ps, nextpd);
8496 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8499 if(pd->pd_PowerDrain > pd->pd_PowerSupply)
8501 if(!(pd->pd_Flags & PDFF_LOWPOWER))
8503 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8504 "Detected low power condition for '%s'.", pd->pd_ProductStr);
8505 pd->pd_Flags |= PDFF_LOWPOWER;
8506 psdSendEvent(EHMB_DEVICELOWPW, pd, NULL);
8508 } else {
8509 if(pd->pd_Flags & PDFF_LOWPOWER)
8511 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
8512 "Low power condition resolved for '%s'.", pd->pd_ProductStr);
8513 pd->pd_Flags &= ~PDFF_LOWPOWER;
8517 /* \\\ */
8519 /* /// "pGarbageCollectEvents()" */
8520 void pGarbageCollectEvents(LIBBASETYPEPTR ps)
8522 struct PsdEventNote *pen;
8523 while((pen = (struct PsdEventNote *) GetMsg(&ps->ps_EventReplyPort)))
8525 psdFreeVec(pen);
8528 /* \\\ */
8530 /* /// "pFindName()" */
8531 struct Node * pFindName(LIBBASETYPEPTR ps, struct List *list, STRPTR name)
8533 struct Node *res = NULL;
8535 Forbid();
8536 while(*name)
8538 res = FindName(list, name);
8539 if(res)
8541 break;
8545 if((*name == '/') || (*name == ':'))
8547 ++name;
8548 break;
8550 } while(*(++name));
8552 Permit();
8553 return(res);
8555 /* \\\ */
8557 /* /// "pStripString()" */
8558 void pStripString(LIBBASETYPEPTR ps, STRPTR str)
8560 STRPTR srcptr = str;
8561 STRPTR tarptr = str;
8562 STRPTR lastgoodchar = str;
8563 BOOL leadingspaces = TRUE;
8564 UBYTE ch;
8565 ULONG len = 0;
8567 while((ch = *srcptr++))
8569 len++;
8570 if(ch == ' ')
8572 if(!leadingspaces)
8574 *tarptr++ = ch;
8576 } else {
8577 *tarptr++ = ch;
8578 lastgoodchar = tarptr;
8579 leadingspaces = FALSE;
8582 *lastgoodchar = 0;
8583 // empty string?
8584 if((str == lastgoodchar) && (len > 6))
8586 strcpy(str, "<empty>");
8589 /* \\\ */
8591 /* /// "pFixBrokenConfig()" */
8592 BOOL pFixBrokenConfig(struct PsdPipe *pp)
8594 struct PsdDevice *pd = pp->pp_Device;
8595 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
8596 struct PsdConfig *pc;
8597 struct PsdInterface *pif;
8598 BOOL fixed = FALSE;
8600 switch(pd->pd_VendorID)
8602 case 0x03eb: /* Atmel */
8603 if(pd->pd_ProductID == 0x3312)
8605 psdFreeVec(pd->pd_ProductStr);
8606 pd->pd_ProductStr = psdCopyStr("Highway/Subway Root Hub");
8608 break;
8610 case 0x04e6: /* E-Shuttle */
8611 if(pd->pd_ProductID == 0x0001) /* LS120 */
8613 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8614 /* Get msd interface and fix it */
8615 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8616 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8618 fixed = TRUE;
8619 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "E-Shuttle LS120");
8620 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8621 pif->pif_IfSubClass = MS_ATAPI_SUBCLASS;
8622 pif->pif_IfProto = MS_PROTO_CB;
8625 break;
8627 case 0x054C: /* Sony */
8628 if((pd->pd_ProductID == 0x002E) || (pd->pd_ProductID == 0x0010)) /* Handycam */
8630 fixed = TRUE;
8631 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Sony MSD");
8632 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8633 /* Get msd interface and fix it */
8634 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8635 pif->pif_IfSubClass = MS_RBC_SUBCLASS;
8637 break;
8639 case 0x057b: /* Y-E Data */
8640 if(pd->pd_ProductID == 0x0000) /* Flashbuster U */
8642 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8643 /* Get msd interface and fix it */
8644 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8645 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8647 fixed = TRUE;
8648 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Y-E Data USB Floppy");
8649 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8650 pif->pif_IfSubClass = MS_UFI_SUBCLASS;
8651 pif->pif_IfProto = (pd->pd_DevVers < 0x0300) ? MS_PROTO_CB : MS_PROTO_CBI;
8654 break;
8656 case 0x04ce: /* ScanLogic */
8657 if(pd->pd_ProductID == 0x0002)
8659 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "ScanLogic");
8660 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8661 /* Get msd interface and fix it */
8662 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8663 fixed = TRUE;
8664 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8666 break;
8668 case 0x0584: /* Ratoc cardreader */
8669 if(pd->pd_ProductID == 0x0008)
8671 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "RATOC");
8672 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8673 /* Get msd interface and fix it */
8674 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8675 fixed = TRUE;
8676 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8677 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8678 pif->pif_IfProto = MS_PROTO_BULK;
8680 break;
8682 case 0x04b8: /* Epson */
8683 if(pd->pd_ProductID == 0x0602) /* EPX Storage device (Card slot in Printer) */
8685 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Epson storage");
8686 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8687 /* Get msd interface and fix it */
8688 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8689 fixed = TRUE;
8690 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8691 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8692 pif->pif_IfProto = MS_PROTO_BULK;
8694 break;
8696 default:
8697 break;
8699 return(fixed);
8701 /* \\\ */
8703 /* /// "pOpenDOS()" */
8704 BOOL pOpenDOS(LIBBASETYPEPTR ps)
8706 if(DOSBase)
8708 return TRUE;
8710 if((DOSBase = OpenLibrary("dos.library", 39)))
8712 return TRUE;
8714 return FALSE;
8716 /* \\\ */
8718 /* *** Class Scan Task *** */
8720 /* /// "pStartEventHandler()" */
8721 BOOL pStartEventHandler(LIBBASETYPEPTR ps)
8723 struct PsdHandlerTask *ph = &ps->ps_EventHandler;
8725 ObtainSemaphore(&ps->ps_PoPoLock);
8726 if(ph->ph_Task)
8728 ReleaseSemaphore(&ps->ps_PoPoLock);
8729 return(TRUE);
8731 ph->ph_ReadySignal = SIGB_SINGLE;
8732 ph->ph_ReadySigTask = FindTask(NULL);
8733 SetSignal(0, SIGF_SINGLE); // clear single bit
8734 if(psdSpawnSubTask("Poseidon Event Broadcast", pEventHandlerTask, ps))
8736 Wait(1UL<<ph->ph_ReadySignal);
8738 ph->ph_ReadySigTask = NULL;
8739 //FreeSignal(ph->ph_ReadySignal);
8740 if(ph->ph_Task)
8742 ReleaseSemaphore(&ps->ps_PoPoLock);
8743 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Event broadcaster started.");
8744 return(TRUE);
8746 ReleaseSemaphore(&ps->ps_PoPoLock);
8747 return(FALSE);
8749 /* \\\ */
8751 /* *** Hardware Driver Task *** */
8753 /* /// "pQuickForwardRequest()" */
8754 AROS_UFH1(void, pQuickForwardRequest,
8755 AROS_UFHA(struct MsgPort *, msgport, A1))
8757 AROS_USERFUNC_INIT
8758 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8759 struct PsdPipe *pp;
8761 while((pp = (struct PsdPipe *) RemHead(&msgport->mp_MsgList)))
8763 if(pp->pp_AbortPipe)
8765 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8766 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8767 ReplyMsg(&pp->pp_Msg);
8768 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8769 } else {
8770 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8771 pp->pp_IOReq.iouh_UserData = pp;
8772 SendIO((struct IORequest *) &pp->pp_IOReq);
8773 ++phw->phw_MsgCount;
8776 AROS_USERFUNC_EXIT
8778 /* \\\ */
8780 /* /// "pQuickReplyRequest()" */
8781 AROS_UFH1(void, pQuickReplyRequest,
8782 AROS_UFHA(struct MsgPort *, msgport, A1))
8784 AROS_USERFUNC_INIT
8785 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8786 struct IOUsbHWReq *ioreq;
8788 while((ioreq = (struct IOUsbHWReq *) RemHead(&msgport->mp_MsgList)))
8790 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8791 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8792 --phw->phw_MsgCount;
8794 AROS_USERFUNC_EXIT
8796 /* \\\ */
8798 /* /// "pDeviceTask()" */
8799 AROS_UFH0(void, pDeviceTask)
8801 AROS_USERFUNC_INIT
8802 LIBBASETYPEPTR ps;
8803 struct PsdHardware *phw;
8804 struct Task *thistask;
8805 ULONG sigs;
8806 ULONG sigmask;
8807 LONG ioerr;
8808 struct TagItem taglist[11];
8809 struct TagItem *tag;
8810 struct PsdPipe *pp;
8811 struct IOUsbHWReq *ioreq;
8813 STRPTR prodname = NULL;
8814 STRPTR manufacturer = NULL;
8815 STRPTR description = NULL;
8816 STRPTR copyright = NULL;
8817 ULONG version = 0;
8818 ULONG revision = 0;
8819 ULONG driververs = 0x0100;
8820 ULONG caps = UHCF_ISO;
8821 STRPTR devname;
8822 ULONG cnt;
8824 if(!(ps = (LIBBASETYPEPTR) OpenLibrary("poseidon.library", 4)))
8826 Alert(AG_OpenLib);
8827 return;
8829 thistask = FindTask(NULL);
8830 SetTaskPri(thistask, 21);
8831 phw = thistask->tc_UserData;
8833 #ifndef PA_CALLBACK // undocumented exec feature
8834 #define PA_CALLBACK 3
8835 #endif
8837 phw->phw_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8838 phw->phw_TaskMsgPort.mp_Node.ln_Name = (APTR) phw;
8839 phw->phw_TaskMsgPort.mp_Flags = PA_SIGNAL;
8840 phw->phw_TaskMsgPort.mp_SigTask = thistask;
8841 phw->phw_TaskMsgPort.mp_SigBit = AllocSignal(-1L);
8842 NewList(&phw->phw_TaskMsgPort.mp_MsgList);
8844 phw->phw_DevMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8845 phw->phw_DevMsgPort.mp_Node.ln_Name = (APTR) phw;
8846 phw->phw_DevMsgPort.mp_Flags = PA_SIGNAL;
8847 phw->phw_DevMsgPort.mp_SigTask = thistask;
8848 phw->phw_DevMsgPort.mp_SigBit = AllocSignal(-1L);
8849 NewList(&phw->phw_DevMsgPort.mp_MsgList);
8851 if((phw->phw_RootIOReq = (struct IOUsbHWReq *) CreateIORequest(&phw->phw_DevMsgPort, sizeof(struct IOUsbHWReq))))
8853 devname = phw->phw_DevName;
8854 ioerr = -1;
8855 while(*devname)
8857 if(!(ioerr = OpenDevice(devname, phw->phw_Unit, (struct IORequest *) phw->phw_RootIOReq, 0)))
8859 break;
8863 if((*devname == '/') || (*devname == ':'))
8865 ++devname;
8866 break;
8868 } while(*(++devname));
8871 if(!ioerr)
8873 phw->phw_Node.ln_Name = phw->phw_RootIOReq->iouh_Req.io_Device->dd_Library.lib_Node.ln_Name;
8874 tag = taglist;
8875 tag->ti_Tag = UHA_ProductName;
8876 tag->ti_Data = (IPTR) &prodname;
8877 ++tag;
8878 tag->ti_Tag = UHA_Manufacturer;
8879 tag->ti_Data = (IPTR) &manufacturer;
8880 ++tag;
8881 tag->ti_Tag = UHA_Description;
8882 tag->ti_Data = (IPTR) &description;
8883 ++tag;
8884 tag->ti_Tag = UHA_Version;
8885 tag->ti_Data = (IPTR) &version;
8886 ++tag;
8887 tag->ti_Tag = UHA_Revision;
8888 tag->ti_Data = (IPTR) &revision;
8889 ++tag;
8890 tag->ti_Tag = UHA_Copyright;
8891 tag->ti_Data = (IPTR) &copyright;
8892 ++tag;
8893 tag->ti_Tag = UHA_DriverVersion;
8894 tag->ti_Data = (IPTR) &driververs;
8895 ++tag;
8896 tag->ti_Tag = UHA_Capabilities;
8897 tag->ti_Data = (IPTR) &caps;
8898 ++tag;
8899 tag->ti_Tag = TAG_END;
8900 phw->phw_RootIOReq->iouh_Data = taglist;
8901 phw->phw_RootIOReq->iouh_Req.io_Command = UHCMD_QUERYDEVICE;
8902 DoIO((struct IORequest *) phw->phw_RootIOReq);
8904 phw->phw_ProductName = psdCopyStr(prodname ? prodname : (STRPTR) "n/a");
8905 phw->phw_Manufacturer = psdCopyStr(manufacturer ? manufacturer : (STRPTR) "n/a");
8906 phw->phw_Description = psdCopyStr(description ? description : (STRPTR) "n/a");
8907 phw->phw_Copyright = psdCopyStr(copyright ? copyright : (STRPTR) "n/a");
8908 phw->phw_Version = version;
8909 phw->phw_Revision = revision;
8910 phw->phw_DriverVers = driververs;
8911 phw->phw_Capabilities = caps;
8913 sigmask = SIGBREAKF_CTRL_C;
8914 if(caps & UHCF_QUICKIO)
8916 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Enabling QuickIO for %s.", prodname);
8917 phw->phw_TaskMsgPort.mp_Flags = PA_CALLBACK;
8918 phw->phw_TaskMsgPort.mp_SigTask = (APTR) pQuickForwardRequest;
8920 phw->phw_DevMsgPort.mp_Flags = PA_CALLBACK;
8921 phw->phw_DevMsgPort.mp_SigTask = (APTR) pQuickReplyRequest;
8922 } else {
8923 sigmask |= (1UL<<phw->phw_DevMsgPort.mp_SigBit)|(1UL<<phw->phw_TaskMsgPort.mp_SigBit);
8926 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
8927 phw->phw_Task = thistask;
8929 psdLockWritePBase();
8930 AddTail(&ps->ps_Hardware, &phw->phw_Node);
8931 psdUnlockPBase();
8933 Forbid();
8934 if(phw->phw_ReadySigTask)
8936 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
8938 Permit();
8941 KPRINTF(1, ("Main loop wait.\n"));
8942 while((pp = (struct PsdPipe *) GetMsg(&phw->phw_TaskMsgPort)))
8944 if(pp->pp_AbortPipe)
8946 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8947 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8948 ReplyMsg(&pp->pp_Msg);
8949 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8950 } else {
8951 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8952 pp->pp_IOReq.iouh_UserData = pp;
8953 SendIO((struct IORequest *) &pp->pp_IOReq);
8954 ++phw->phw_MsgCount;
8957 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8959 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8960 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8961 --phw->phw_MsgCount;
8963 sigs = Wait(sigmask);
8964 } while(!(sigs & SIGBREAKF_CTRL_C));
8965 /* Flush all pending IO Requests */
8966 phw->phw_RootIOReq->iouh_Req.io_Command = CMD_FLUSH;
8967 DoIO((struct IORequest *) phw->phw_RootIOReq);
8968 cnt = 0;
8969 while(phw->phw_MsgCount)
8971 KPRINTF(20, ("Still %ld iorequests pending!\n", phw->phw_MsgCount));
8972 psdDelayMS(100);
8973 if(++cnt == 50)
8975 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8976 "There are still %ld IORequests pending, before unit can go down. Driver buggy?",
8977 phw->phw_MsgCount);
8979 if(cnt == 300)
8981 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8982 "Okay, I've waited long enough, sod these %ld IORequests.",
8983 phw->phw_MsgCount);
8984 phw->phw_MsgCount = 0;
8985 break;
8987 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8989 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8990 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8991 --phw->phw_MsgCount;
8994 psdLockWritePBase();
8995 Remove(&phw->phw_Node);
8996 psdUnlockPBase();
8997 CloseDevice((struct IORequest *) phw->phw_RootIOReq);
8998 } else {
8999 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
9000 "Opening %s unit %ld failed %s (%ld).",
9001 phw->phw_DevName, phw->phw_Unit, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
9003 DeleteIORequest((struct IORequest *) phw->phw_RootIOReq);
9004 phw->phw_RootIOReq = NULL;
9006 FreeSignal((LONG) phw->phw_TaskMsgPort.mp_SigBit);
9007 FreeSignal((LONG) phw->phw_DevMsgPort.mp_SigBit);
9009 CloseLibrary((struct Library *) ps);
9010 phw->phw_Task = NULL;
9012 Forbid();
9013 if(phw->phw_ReadySigTask)
9015 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
9017 AROS_USERFUNC_EXIT
9019 /* \\\ */
9021 /* /// "pEventHandlerTask()" */
9022 AROS_UFH0(void, pEventHandlerTask)
9024 AROS_USERFUNC_INIT
9025 LIBBASETYPEPTR ps;
9026 struct Task *thistask;
9027 struct timeval currtime;
9028 ULONG sigs;
9029 ULONG sigmask;
9030 struct PsdUsbClass *puc;
9031 struct PsdHandlerTask *ph;
9032 struct PsdEventNote *pen;
9033 ULONG counter;
9034 ULONG cfgchanged;
9036 thistask = FindTask(NULL);
9037 ps = thistask->tc_UserData;
9038 ph = &ps->ps_EventHandler;
9039 SetTaskPri(thistask, 0);
9041 if((ph->ph_MsgPort = CreateMsgPort()))
9043 if((ph->ph_TimerMsgPort = CreateMsgPort()))
9045 if((ph->ph_TimerIOReq = (struct timerequest *) CreateIORequest(ph->ph_TimerMsgPort, sizeof(struct timerequest))))
9047 if(!(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) ph->ph_TimerIOReq, 0)))
9049 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
9050 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "EventHandler";
9051 ph->ph_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
9053 ph->ph_EventHandler = psdAddEventHandler(ph->ph_MsgPort, EHMF_CONFIGCHG);
9054 if(ph->ph_EventHandler)
9056 ph->ph_Task = thistask;
9057 Forbid();
9058 if(ph->ph_ReadySigTask)
9060 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9062 Permit();
9064 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9065 SendIO(&ph->ph_TimerIOReq->tr_node);
9066 sigmask = (1UL<<ph->ph_MsgPort->mp_SigBit)|(1UL<<ph->ph_TimerMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
9067 counter = 0;
9068 cfgchanged = 0;
9071 if(ps->ps_CheckConfigReq)
9073 pCheckCfgChanged(ps);
9075 while((pen = (struct PsdEventNote *) GetMsg(ph->ph_MsgPort)))
9077 switch(pen->pen_Event)
9079 case EHMB_CONFIGCHG:
9080 if(!cfgchanged)
9082 cfgchanged = counter;
9084 break;
9087 ReplyMsg(&pen->pen_Msg);
9089 if(CheckIO(&ph->ph_TimerIOReq->tr_node))
9091 BOOL startpopo;
9092 WaitIO(&ph->ph_TimerIOReq->tr_node);
9093 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9094 SendIO(&ph->ph_TimerIOReq->tr_node);
9095 counter++;
9096 startpopo = !((counter & 3) || ps->ps_PoPo.po_Task);
9097 if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) &&
9098 (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) &&
9099 (!ps->ps_GlobalCfg->pgc_PopupDeviceGone))
9101 startpopo = FALSE; // no need to start popo, no windows wanted
9103 if(startpopo)
9105 struct PsdPoPo *po = &ps->ps_PoPo;
9107 po->po_ReadySignal = SIGB_SINGLE;
9108 po->po_ReadySigTask = FindTask(NULL);
9109 SetSignal(0, SIGF_SINGLE); // clear single bit
9110 if(psdSpawnSubTask("PoPo (Poseidon Popups)", pPoPoGUITask, ps))
9112 Wait(1UL<<po->po_ReadySignal);
9114 po->po_ReadySigTask = NULL;
9115 //FreeSignal(po->po_ReadySignal);
9116 if(po->po_Task)
9118 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "PoPo kicks ass.");
9121 if((cfgchanged + 2) == counter)
9123 KPRINTF(10, ("Sending information about config changed to all classes.\n"));
9124 /* Inform all classes */
9125 psdLockReadPBase();
9126 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
9127 while(puc->puc_Node.ln_Succ)
9129 usbDoMethod(UCM_ConfigChangedEvent);
9130 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
9132 psdUnlockPBase();
9133 cfgchanged = 0;
9135 // power saving stuff, check every second
9136 if((counter & 1) && ps->ps_GlobalCfg->pgc_PowerSaving)
9138 struct PsdDevice *pd = NULL;
9139 struct PsdInterface *pif;
9140 GetSysTime((APTR) &currtime);
9141 while((pd = psdGetNextDevice(pd)))
9143 if((pd->pd_DevClass != HUB_CLASSCODE) &&
9144 ((pd->pd_Flags & (PDFF_CONFIGURED|PDFF_DEAD|PDFF_SUSPENDED|PDFF_APPBINDING|PDFF_DELEXPUNGE)) == PDFF_CONFIGURED))
9146 if(pd->pd_LastActivity.tv_secs && ((currtime.tv_secs - pd->pd_LastActivity.tv_secs) > ps->ps_GlobalCfg->pgc_SuspendTimeout))
9148 BOOL doit = TRUE;
9149 IPTR suspendable;
9150 if(!((pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP) && ps->ps_GlobalCfg->pgc_ForceSuspend))
9152 if(pd->pd_DevBinding && ((puc = pd->pd_ClsBinding)))
9154 suspendable = 0;
9155 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9156 if(!suspendable)
9158 doit = FALSE;
9161 pif = (struct PsdInterface *) pd->pd_CurrentConfig->pc_Interfaces.lh_Head;
9162 while(pif->pif_Node.ln_Succ)
9164 if(pif->pif_IfBinding && ((puc = pif->pif_ClsBinding)))
9166 suspendable = 0;
9167 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9168 if(!suspendable)
9170 doit = FALSE;
9171 break;
9174 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
9177 if(doit)
9179 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Suspending '%s'.", pd->pd_ProductStr);
9180 psdSuspendDevice(pd);
9182 pd->pd_LastActivity.tv_secs = 0;
9188 sigs = Wait(sigmask);
9189 } while(!(sigs & SIGBREAKF_CTRL_C));
9190 psdRemEventHandler(ph->ph_EventHandler);
9191 ph->ph_EventHandler = NULL;
9192 AbortIO(&ph->ph_TimerIOReq->tr_node);
9193 WaitIO(&ph->ph_TimerIOReq->tr_node);
9195 CloseDevice((struct IORequest *) ph->ph_TimerIOReq);
9197 DeleteIORequest((struct IORequest *) ph->ph_TimerIOReq);
9199 DeleteMsgPort(ph->ph_TimerMsgPort);
9201 DeleteMsgPort(ph->ph_MsgPort);
9202 ph->ph_MsgPort = NULL;
9204 Forbid();
9205 ph->ph_Task = NULL;
9206 if(ph->ph_ReadySigTask)
9208 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9210 AROS_USERFUNC_EXIT
9212 /* \\\ */
9214 /*****************************************************************/
9216 /* /// "Packtables for psdGetAttrs() and psdSetAttrs() " */
9217 /* Pack table for PsdBase */
9218 static const ULONG PsdBasePT[] =
9220 PACK_STARTTABLE(PA_Dummy),
9221 PACK_ENTRY(PA_Dummy, PA_ConfigRead, PsdBase, ps_ConfigRead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9222 PACK_ENTRY(PA_Dummy, PA_GlobalConfig, PsdBase, ps_GlobalCfg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9223 PACK_ENTRY(PA_Dummy, PA_MemPoolUsage, PsdBase, ps_MemAllocated, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9224 PACK_ENTRY(PA_Dummy, PA_CurrConfigHash, PsdBase, ps_ConfigHash, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9225 PACK_ENTRY(PA_Dummy, PA_SavedConfigHash, PsdBase, ps_SavedConfigHash, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9226 PACK_ENTRY(PA_Dummy, PA_ReleaseVersion, PsdBase, ps_ReleaseVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9227 PACK_ENTRY(PA_Dummy, PA_OSVersion, PsdBase, ps_OSVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9228 PACK_ENDTABLE
9231 /* Pack table for PsdErrorMsg */
9232 static const ULONG PsdErrorMsgPT[] =
9234 PACK_STARTTABLE(EMA_Dummy),
9235 PACK_ENTRY(EMA_Dummy, EMA_Level, PsdErrorMsg, pem_Level, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9236 PACK_ENTRY(EMA_Dummy, EMA_Origin, PsdErrorMsg, pem_Origin, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9237 PACK_ENTRY(EMA_Dummy, EMA_Msg, PsdErrorMsg, pem_Msg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9238 PACK_ENDTABLE
9241 /* Pack table for PsdUsbClass */
9242 static const ULONG PsdUsbClassPT[] =
9244 PACK_STARTTABLE(UCA_Dummy),
9245 PACK_ENTRY(UCA_Dummy, UCA_ClassBase, PsdUsbClass, puc_ClassBase, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9246 PACK_ENTRY(UCA_Dummy, UCA_ClassName, PsdUsbClass, puc_ClassName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9247 PACK_ENTRY(UCA_Dummy, UCA_FullPath, PsdUsbClass, puc_FullPath, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9248 PACK_ENTRY(UCA_Dummy, UCA_UseCount, PsdUsbClass, puc_UseCnt, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9249 PACK_ENDTABLE
9252 /* Pack table for PsdHardware */
9253 static const ULONG PsdHardwarePT[] =
9255 PACK_STARTTABLE(HA_Dummy),
9256 PACK_ENTRY(HA_Dummy, HA_DeviceName, PsdHardware, phw_DevName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9257 PACK_ENTRY(HA_Dummy, HA_DeviceUnit, PsdHardware, phw_Unit, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9258 PACK_ENTRY(HA_Dummy, HA_ProductName, PsdHardware, phw_ProductName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9259 PACK_ENTRY(HA_Dummy, HA_Manufacturer, PsdHardware, phw_Manufacturer, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9260 PACK_ENTRY(HA_Dummy, HA_Description, PsdHardware, phw_Description, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9261 PACK_ENTRY(HA_Dummy, HA_Copyright, PsdHardware, phw_Copyright, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9262 PACK_ENTRY(HA_Dummy, HA_Version, PsdHardware, phw_Version, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9263 PACK_ENTRY(HA_Dummy, HA_Revision, PsdHardware, phw_Revision, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9264 PACK_ENTRY(HA_Dummy, HA_DriverVersion, PsdHardware, phw_DriverVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9265 PACK_ENDTABLE
9268 /* Pack table for PsdDevice */
9269 static const ULONG PsdDevicePT[] =
9271 PACK_STARTTABLE(DA_Dummy),
9272 PACK_ENTRY(DA_Dummy, DA_Address, PsdDevice, pd_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9273 PACK_ENTRY(DA_Dummy, DA_NumConfigs, PsdDevice, pd_NumCfgs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9274 PACK_ENTRY(DA_Dummy, DA_CurrConfig, PsdDevice, pd_CurrCfg, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9275 PACK_ENTRY(DA_Dummy, DA_Config, PsdDevice, pd_CurrentConfig, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9276 PACK_ENTRY(DA_Dummy, DA_HubDevice, PsdDevice, pd_Hub, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9277 PACK_ENTRY(DA_Dummy, DA_UsbVersion, PsdDevice, pd_USBVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9278 PACK_ENTRY(DA_Dummy, DA_Class, PsdDevice, pd_DevClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9279 PACK_ENTRY(DA_Dummy, DA_SubClass, PsdDevice, pd_DevSubClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9280 PACK_ENTRY(DA_Dummy, DA_Protocol, PsdDevice, pd_DevProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9281 PACK_ENTRY(DA_Dummy, DA_VendorID, PsdDevice, pd_VendorID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9282 PACK_ENTRY(DA_Dummy, DA_MaxPktSize0, PsdDevice, pd_MaxPktSize0, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9283 PACK_ENTRY(DA_Dummy, DA_ProductID, PsdDevice, pd_ProductID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9284 PACK_ENTRY(DA_Dummy, DA_Version, PsdDevice, pd_DevVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9285 PACK_ENTRY(DA_Dummy, DA_Manufacturer, PsdDevice, pd_MnfctrStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9286 PACK_ENTRY(DA_Dummy, DA_ProductName, PsdDevice, pd_ProductStr, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9287 PACK_ENTRY(DA_Dummy, DA_OrigProductName, PsdDevice, pd_OldProductStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9288 PACK_ENTRY(DA_Dummy, DA_SerialNumber, PsdDevice, pd_SerNumStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9289 PACK_ENTRY(DA_Dummy, DA_Hardware, PsdDevice, pd_Hardware, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9290 PACK_ENTRY(DA_Dummy, DA_Binding, PsdDevice, pd_DevBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9291 PACK_ENTRY(DA_Dummy, DA_BindingClass, PsdDevice, pd_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9292 PACK_ENTRY(DA_Dummy, DA_LangIDArray, PsdDevice, pd_LangIDArray, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9293 PACK_ENTRY(DA_Dummy, DA_CurrLangID, PsdDevice, pd_CurrLangID, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9294 PACK_ENTRY(DA_Dummy, DA_IDString, PsdDevice, pd_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9295 PACK_ENTRY(DA_Dummy, DA_CloneCount, PsdDevice, pd_CloneCount, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9296 PACK_ENTRY(DA_Dummy, DA_AtHubPortNumber, PsdDevice, pd_HubPort, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9297 PACK_ENTRY(DA_Dummy, DA_PowerDrained, PsdDevice, pd_PowerDrain, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9298 PACK_ENTRY(DA_Dummy, DA_PowerSupply, PsdDevice, pd_PowerSupply, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9299 PACK_ENTRY(DA_Dummy, DA_IsNewToMe, PsdDevice, pd_IsNewToMe, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9300 PACK_ENTRY(DA_Dummy, DA_InhibitPopup, PsdDevice, pd_PoPoCfg.poc_InhibitPopup, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9301 PACK_ENTRY(DA_Dummy, DA_InhibitClassBind, PsdDevice, pd_PoPoCfg.poc_NoClassBind, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9302 PACK_ENTRY(DA_Dummy, DA_OverridePowerInfo, PsdDevice, pd_PoPoCfg.poc_OverridePowerInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9303 PACK_ENTRY(DA_Dummy, DA_HubThinkTime, PsdDevice, pd_HubThinkTime, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9304 PACK_WORDBIT(DA_Dummy, DA_IsLowspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_LOWSPEED),
9305 PACK_WORDBIT(DA_Dummy, DA_IsHighspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HIGHSPEED),
9306 PACK_WORDBIT(DA_Dummy, DA_IsConnected, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONNECTED),
9307 PACK_WORDBIT(DA_Dummy, DA_HasAddress, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVADDR),
9308 PACK_WORDBIT(DA_Dummy, DA_HasDevDesc, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVDESC),
9309 PACK_WORDBIT(DA_Dummy, DA_IsConfigured, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONFIGURED),
9310 PACK_WORDBIT(DA_Dummy, DA_IsDead, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_DEAD),
9311 PACK_WORDBIT(DA_Dummy, DA_IsSuspended, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUSPENDED),
9312 PACK_WORDBIT(DA_Dummy, DA_HasAppBinding, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_APPBINDING),
9313 PACK_WORDBIT(DA_Dummy, DA_NeedsSplitTrans, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_NEEDSSPLIT),
9314 PACK_WORDBIT(DA_Dummy, DA_LowPower, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_LOWPOWER),
9315 #ifdef AROS_USB30_CODE
9316 PACK_WORDBIT(DA_Dummy, DA_IsSuperspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUPERSPEED),
9317 #endif
9318 PACK_ENDTABLE
9321 /* Pack table for PsdConfig */
9322 static const ULONG PsdConfigPT[] =
9324 PACK_STARTTABLE(CA_Dummy),
9325 PACK_ENTRY(CA_Dummy, CA_ConfigNum, PsdConfig, pc_CfgNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9326 PACK_ENTRY(CA_Dummy, CA_MaxPower, PsdConfig, pc_MaxPower, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9327 PACK_ENTRY(CA_Dummy, CA_ConfigName, PsdConfig, pc_CfgStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9328 PACK_ENTRY(CA_Dummy, CA_NumInterfaces, PsdConfig, pc_NumIfs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9329 PACK_ENTRY(CA_Dummy, CA_Attrs, PsdConfig, pc_Attr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9330 PACK_ENTRY(CA_Dummy, CA_Device, PsdConfig, pc_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9331 PACK_WORDBIT(CA_Dummy, CA_SelfPowered, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_PACKUNPACK, USCAF_SELF_POWERED),
9332 PACK_WORDBIT(CA_Dummy, CA_RemoteWakeup, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_UNPACKONLY, USCAF_REMOTE_WAKEUP),
9333 PACK_ENDTABLE
9336 /* Pack table for PsdDescriptor */
9337 static const ULONG PsdDescriptorPT[] =
9339 PACK_STARTTABLE(DDA_Dummy),
9340 PACK_ENTRY(DDA_Dummy, DDA_Device, PsdDescriptor, pdd_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9341 PACK_ENTRY(DDA_Dummy, DDA_Config, PsdDescriptor, pdd_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9342 PACK_ENTRY(DDA_Dummy, DDA_Interface, PsdDescriptor, pdd_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9343 PACK_ENTRY(DDA_Dummy, DDA_Endpoint, PsdDescriptor, pdd_Endpoint, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9344 PACK_ENTRY(DDA_Dummy, DDA_Name, PsdDescriptor, pdd_Name, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9345 PACK_ENTRY(DDA_Dummy, DDA_DescriptorType, PsdDescriptor, pdd_Type, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9346 PACK_ENTRY(DDA_Dummy, DDA_CS_SubType, PsdDescriptor, pdd_CSSubType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9347 PACK_ENTRY(DDA_Dummy, DDA_DescriptorData, PsdDescriptor, pdd_Data, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9348 PACK_ENTRY(DDA_Dummy, DDA_DescriptorLength, PsdDescriptor, pdd_Length, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9349 PACK_ENDTABLE
9352 /* Pack table for PsdInterface */
9353 static const ULONG PsdInterfacePT[] =
9355 PACK_STARTTABLE(IFA_Dummy),
9356 PACK_ENTRY(IFA_Dummy, IFA_InterfaceNum, PsdInterface, pif_IfNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9357 PACK_ENTRY(IFA_Dummy, IFA_AlternateNum, PsdInterface, pif_Alternate, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9358 PACK_ENTRY(IFA_Dummy, IFA_NumEndpoints, PsdInterface, pif_NumEPs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9359 PACK_ENTRY(IFA_Dummy, IFA_Class, PsdInterface, pif_IfClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9360 PACK_ENTRY(IFA_Dummy, IFA_SubClass, PsdInterface, pif_IfSubClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9361 PACK_ENTRY(IFA_Dummy, IFA_Protocol, PsdInterface, pif_IfProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9362 PACK_ENTRY(IFA_Dummy, IFA_InterfaceName, PsdInterface, pif_IfStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9363 PACK_ENTRY(IFA_Dummy, IFA_Config, PsdInterface, pif_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9364 PACK_ENTRY(IFA_Dummy, IFA_Binding, PsdInterface, pif_IfBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9365 PACK_ENTRY(IFA_Dummy, IFA_BindingClass, PsdInterface, pif_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9366 PACK_ENTRY(IFA_Dummy, IFA_IDString, PsdInterface, pif_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9367 PACK_ENDTABLE
9370 /* Pack table for PsdEndpoint */
9371 static const ULONG PsdEndpointPT[] =
9373 PACK_STARTTABLE(EA_Dummy),
9374 PACK_ENTRY(EA_Dummy, EA_EndpointNum, PsdEndpoint, pep_EPNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9375 PACK_ENTRY(EA_Dummy, EA_TransferType, PsdEndpoint, pep_TransType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9376 PACK_ENTRY(EA_Dummy, EA_MaxPktSize, PsdEndpoint, pep_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9377 PACK_ENTRY(EA_Dummy, EA_Interval, PsdEndpoint, pep_Interval, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9378 PACK_ENTRY(EA_Dummy, EA_NumTransMuFrame, PsdEndpoint, pep_NumTransMuFr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9379 PACK_ENTRY(EA_Dummy, EA_SyncType, PsdEndpoint, pep_SyncType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9380 PACK_ENTRY(EA_Dummy, EA_UsageType, PsdEndpoint, pep_UsageType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9381 PACK_ENTRY(EA_Dummy, EA_Interface, PsdEndpoint, pep_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9382 PACK_WORDBIT(EA_Dummy, EA_IsIn, PsdEndpoint, pep_Direction, PKCTRL_BIT|PKCTRL_UNPACKONLY, 1),
9383 PACK_ENDTABLE
9386 /* Pack table for PsdPipe */
9387 static const ULONG PsdPipePT[] =
9389 PACK_STARTTABLE(PPA_Dummy),
9390 PACK_ENTRY(PPA_Dummy, PPA_Endpoint, PsdPipe, pp_Endpoint, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9391 PACK_ENTRY(PPA_Dummy, PPA_Error, PsdPipe, pp_IOReq.iouh_Req.io_Error, PKCTRL_BYTE|PKCTRL_UNPACKONLY),
9392 PACK_ENTRY(PPA_Dummy, PPA_Actual, PsdPipe, pp_IOReq.iouh_Actual, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9393 PACK_ENTRY(PPA_Dummy, PPA_EndpointNum, PsdPipe, pp_IOReq.iouh_Endpoint, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9394 PACK_ENTRY(PPA_Dummy, PPA_DeviceAddress, PsdPipe, pp_IOReq.iouh_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9395 PACK_ENTRY(PPA_Dummy, PPA_MaxPktSize, PsdPipe, pp_IOReq.iouh_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9396 PACK_ENTRY(PPA_Dummy, PPA_NakTimeoutTime, PsdPipe, pp_IOReq.iouh_NakTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9397 PACK_ENTRY(PPA_Dummy, PPA_Interval, PsdPipe, pp_IOReq.iouh_Interval, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9398 PACK_WORDBIT(PPA_Dummy, PPA_NoShortPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NOSHORTPKT),
9399 PACK_WORDBIT(PPA_Dummy, PPA_NakTimeout, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NAKTIMEOUT),
9400 PACK_WORDBIT(PPA_Dummy, PPA_AllowRuntPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_ALLOWRUNTPKTS),
9401 PACK_ENDTABLE
9404 /* Pack table for PsdAppBinding */
9405 static const ULONG PsdAppBindingPT[] =
9407 PACK_STARTTABLE(ABA_Dummy),
9408 PACK_ENTRY(ABA_Dummy, ABA_ReleaseHook, PsdAppBinding, pab_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9409 PACK_ENTRY(ABA_Dummy, ABA_Device, PsdAppBinding, pab_Device, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9410 PACK_ENTRY(ABA_Dummy, ABA_UserData, PsdAppBinding, pab_UserData, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9411 PACK_ENTRY(ABA_Dummy, ABA_Task, PsdAppBinding, pab_Task, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9412 PACK_ENTRY(ABA_Dummy, ABA_ForceRelease, PsdAppBinding, pab_ForceRelease, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9413 PACK_ENDTABLE
9416 /* Pack table for PsdAppBinding */
9417 static const ULONG PsdEventNotePT[] =
9419 PACK_STARTTABLE(ENA_Dummy),
9420 PACK_ENTRY(ENA_Dummy, ENA_EventID, PsdEventNote, pen_Event, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9421 PACK_ENTRY(ENA_Dummy, ENA_Param1, PsdEventNote, pen_Param1, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9422 PACK_ENTRY(ENA_Dummy, ENA_Param2, PsdEventNote, pen_Param2, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9423 PACK_ENDTABLE
9426 /* Pack table for PsdGlobalCfg */
9427 static const ULONG PsdGlobalCfgPT[] =
9429 PACK_STARTTABLE(GCA_Dummy),
9430 PACK_ENTRY(GCA_Dummy, GCA_LogInfo, PsdGlobalCfg, pgc_LogInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9431 PACK_ENTRY(GCA_Dummy, GCA_LogWarning, PsdGlobalCfg, pgc_LogWarning, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9432 PACK_ENTRY(GCA_Dummy, GCA_LogError, PsdGlobalCfg, pgc_LogError, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9433 PACK_ENTRY(GCA_Dummy, GCA_LogFailure, PsdGlobalCfg, pgc_LogFailure, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9434 PACK_ENTRY(GCA_Dummy, GCA_BootDelay, PsdGlobalCfg, pgc_BootDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9435 PACK_ENTRY(GCA_Dummy, GCA_SubTaskPri, PsdGlobalCfg, pgc_SubTaskPri, PKCTRL_WORD|PKCTRL_PACKUNPACK),
9436 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceNew, PsdGlobalCfg, pgc_PopupDeviceNew, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9437 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceGone, PsdGlobalCfg, pgc_PopupDeviceGone, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9438 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceDeath, PsdGlobalCfg, pgc_PopupDeviceDeath, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9439 PACK_ENTRY(GCA_Dummy, GCA_PopupCloseDelay, PsdGlobalCfg, pgc_PopupCloseDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9440 PACK_ENTRY(GCA_Dummy, GCA_PopupActivateWin, PsdGlobalCfg, pgc_PopupActivateWin, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9441 PACK_ENTRY(GCA_Dummy, GCA_PopupWinToFront, PsdGlobalCfg, pgc_PopupWinToFront, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9442 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableLP, PsdGlobalCfg, pgc_AutoDisableLP, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9443 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableDead, PsdGlobalCfg, pgc_AutoDisableDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9444 PACK_ENTRY(GCA_Dummy, GCA_AutoRestartDead, PsdGlobalCfg, pgc_AutoRestartDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9445 PACK_ENTRY(GCA_Dummy, GCA_PowerSaving, PsdGlobalCfg, pgc_PowerSaving, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9446 PACK_ENTRY(GCA_Dummy, GCA_ForceSuspend, PsdGlobalCfg, pgc_ForceSuspend, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9447 PACK_ENTRY(GCA_Dummy, GCA_SuspendTimeout, PsdGlobalCfg, pgc_SuspendTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9448 PACK_ENTRY(GCA_Dummy, GCA_PrefsVersion, PsdGlobalCfg, pgc_PrefsVersion, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9449 PACK_ENDTABLE
9452 /* Pack table for PsdPipeStream */
9453 static const ULONG PsdPipeStreamPT[] =
9455 PACK_STARTTABLE(PSA_Dummy),
9456 PACK_ENTRY(PSA_Dummy, PSA_MessagePort, PsdPipeStream, pps_MsgPort, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9457 PACK_ENTRY(PSA_Dummy, PSA_NumPipes, PsdPipeStream, pps_NumPipes, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9458 PACK_ENTRY(PSA_Dummy, PSA_BufferSize, PsdPipeStream, pps_BufferSize, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9459 PACK_ENTRY(PSA_Dummy, PSA_NakTimeoutTime, PsdPipeStream, pps_NakTimeoutTime, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9460 PACK_ENTRY(PSA_Dummy, PSA_BytesPending, PsdPipeStream, pps_BytesPending, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9461 PACK_ENTRY(PSA_Dummy, PSA_Error, PsdPipeStream, pps_Error, PKCTRL_LONG|PKCTRL_PACKUNPACK),
9462 PACK_ENTRY(PSA_Dummy, PSA_TermArray, PsdPipeStream, pps_TermArray, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9463 PACK_ENTRY(PSA_Dummy, PSA_AbortSigMask, PsdPipeStream, pps_AbortSigMask, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9464 PACK_ENTRY(PSA_Dummy, PSA_ActivePipe, PsdPipeStream, pps_ActivePipe, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9465 PACK_WORDBIT(PSA_Dummy, PSA_AsyncIO, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ASYNCIO),
9466 PACK_WORDBIT(PSA_Dummy, PSA_ShortPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_SHORTTERM),
9467 PACK_WORDBIT(PSA_Dummy, PSA_ReadAhead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_READAHEAD),
9468 PACK_WORDBIT(PSA_Dummy, PSA_BufferedRead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERREAD),
9469 PACK_WORDBIT(PSA_Dummy, PSA_BufferedWrite, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERWRITE),
9470 PACK_WORDBIT(PSA_Dummy, PSA_NoZeroPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NOSHORTPKT),
9471 PACK_WORDBIT(PSA_Dummy, PSA_NakTimeout, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NAKTIMEOUT),
9472 PACK_WORDBIT(PSA_Dummy, PSA_AllowRuntPackets, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ALLOWRUNT),
9473 PACK_WORDBIT(PSA_Dummy, PSA_DoNotWait, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_DONOTWAIT),
9474 PACK_ENDTABLE
9477 /* Pack table for PsdRTIsoHandler */
9478 static const ULONG PsdRTIsoHandlerPT[] =
9480 PACK_STARTTABLE(RTA_Dummy),
9481 PACK_ENTRY(RTA_Dummy, RTA_InRequestHook, PsdRTIsoHandler, prt_RTIso.urti_InReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9482 PACK_ENTRY(RTA_Dummy, RTA_OutRequestHook, PsdRTIsoHandler, prt_RTIso.urti_OutReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9483 PACK_ENTRY(RTA_Dummy, RTA_InDoneHook, PsdRTIsoHandler, prt_RTIso.urti_InDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9484 PACK_ENTRY(RTA_Dummy, RTA_OutDoneHook, PsdRTIsoHandler, prt_RTIso.urti_OutDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9485 PACK_ENTRY(RTA_Dummy, RTA_ReleaseHook, PsdRTIsoHandler, prt_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9486 PACK_ENTRY(RTA_Dummy, RTA_OutPrefetchSize, PsdRTIsoHandler, prt_RTIso.urti_OutPrefetch, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9487 PACK_ENDTABLE
9490 /* PGA assignment table */
9491 static const ULONG *PsdPTArray[] =
9493 NULL,
9494 PsdBasePT,
9495 PsdUsbClassPT,
9496 PsdHardwarePT,
9497 PsdDevicePT,
9498 PsdConfigPT,
9499 PsdInterfacePT,
9500 PsdEndpointPT,
9501 PsdErrorMsgPT,
9502 PsdPipePT,
9503 PsdAppBindingPT,
9504 PsdEventNotePT,
9505 PsdGlobalCfgPT,
9506 PsdPipeStreamPT,
9507 PsdDescriptorPT,
9508 PsdRTIsoHandlerPT
9510 /* \\\ */