revert between 56095 -> 55830 in arch
[AROS.git] / rom / usb / poseidon / poseidon.library.c
blob22c7c63dbaea54a2690c770e10a231f5bb71bd99
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 #include <string.h>
45 #ifdef __AROS__
46 #include <aros/bootloader.h>
47 #include <proto/bootloader.h>
48 #endif
50 #define NewList(list) NEWLIST(list)
52 #define min(x,y) (((x) < (y)) ? (x) : (y))
53 #define max(x,y) (((x) > (y)) ? (x) : (y))
55 extern const struct PsdWStringMap usbclasscodestr[];
56 extern const struct PsdULStringMap usbcomboclasscodestr[];
57 extern const struct PsdULStringMap usbdesctypestr[];
58 extern const struct PsdWStringMap usbhwioerrstr[];
59 extern const struct PsdUWStringMap usblangids[];
60 extern const struct PsdUWStringMap usbvendorids[];
62 #if !defined(__AROS__)
63 extern struct ExecBase *SysBase;
64 #endif
66 /* Static data */
67 const char GM_UNIQUENAME(libname)[] = MOD_NAME_STRING;
69 #define UsbClsBase puc->puc_ClassBase
70 #define DOSBase ps->ps_DosBase
71 #define TimerBase ps->ps_TimerIOReq.tr_node.io_Device
73 /* LibInit */
74 static int GM_UNIQUENAME(libInit)(LIBBASETYPEPTR ps)
76 KPRINTF(10, ("libInit ps: 0x%p SysBase: 0x%p\n",
77 ps, SysBase));
79 ps->ps_StackInit = FALSE;
80 ps->ps_UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 39);
82 #define UtilityBase ps->ps_UtilityBase
84 if (UtilityBase)
86 #ifdef __AROS__
87 APTR BootLoaderBase = OpenResource("bootloader.resource");
89 if (BootLoaderBase)
91 struct List *args = GetBootInfo(BL_Args);
93 if (args)
95 struct Node *node;
97 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
99 if (stricmp(node->ln_Name, "usbdebug") == 0)
101 ps->ps_Flags = PSF_KLOG;
102 break;
107 #endif
109 NewList(&ps->ps_Hardware);
110 NewList(&ps->ps_Classes);
111 NewList(&ps->ps_ErrorMsgs);
112 NewList(&ps->ps_EventHooks);
113 memset(&ps->ps_EventReplyPort, 0, sizeof(ps->ps_EventReplyPort));
114 ps->ps_EventReplyPort.mp_Flags = PA_IGNORE;
115 NewList(&ps->ps_EventReplyPort.mp_MsgList);
116 NewList(&ps->ps_ConfigRoot);
117 NewList(&ps->ps_AlienConfigs);
119 NewList(&ps->ps_DeadlockDebug);
121 InitSemaphore(&ps->ps_ReentrantLock);
122 InitSemaphore(&ps->ps_PoPoLock);
124 if((ps->ps_MemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC|MEMF_SEM_PROTECTED, 16384, 1024)))
126 if((ps->ps_SemaMemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC, 16*sizeof(struct PsdReadLock), sizeof(struct PsdBorrowLock))))
128 pInitSem(ps, &ps->ps_Lock, "PBase");
129 pInitSem(ps, &ps->ps_ConfigLock, "ConfigLock");
130 KPRINTF(20, ("libInit: Done!\n"));
131 return TRUE;
133 DeletePool(ps->ps_MemPool);
134 } else {
135 KPRINTF(20, ("libInit: CreatePool() failed!\n"));
137 CloseLibrary((struct Library *) UtilityBase);
138 } else {
139 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
141 return FALSE;
144 /* LibOpen */
145 static int GM_UNIQUENAME(libOpen)(LIBBASETYPEPTR ps)
147 struct PsdIFFContext *pic;
149 KPRINTF(10, ("libOpen ps: 0x%p\n", ps));
150 ObtainSemaphore(&ps->ps_ReentrantLock);
151 if(!ps->ps_StackInit)
153 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
154 ps->ps_TimerIOReq.tr_node.io_Message.mn_ReplyPort = NULL;
155 ps->ps_TimerIOReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest);
156 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) &ps->ps_TimerIOReq, 0))
158 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Name = "Poseidon";
159 ps->ps_TimerIOReq.tr_node.io_Command = TR_ADDREQUEST;
161 ps->ps_ReleaseVersion = RELEASEVERSION;
162 ps->ps_OSVersion = MAKE_ID('A','R','O','S');
164 pic = pAllocForm(ps, NULL, IFFFORM_PSDCFG);
165 if((ps->ps_GlobalCfg = psdAllocVec(sizeof(struct PsdGlobalCfg))))
167 ps->ps_GlobalCfg->pgc_ChunkID = AROS_LONG2BE(IFFCHNK_GLOBALCFG);
168 ps->ps_GlobalCfg->pgc_Length = AROS_LONG2BE(sizeof(struct PsdGlobalCfg)-8);
169 ps->ps_GlobalCfg->pgc_LogInfo = TRUE;
170 ps->ps_GlobalCfg->pgc_LogWarning = TRUE;
171 ps->ps_GlobalCfg->pgc_LogError = TRUE;
172 ps->ps_GlobalCfg->pgc_LogFailure = TRUE;
173 ps->ps_GlobalCfg->pgc_BootDelay = 2;
174 ps->ps_GlobalCfg->pgc_SubTaskPri = 5;
175 ps->ps_GlobalCfg->pgc_PopupDeviceNew = PGCP_ISNEW;
176 ps->ps_GlobalCfg->pgc_PopupDeviceGone = TRUE;
177 ps->ps_GlobalCfg->pgc_PopupDeviceDeath = TRUE;
178 ps->ps_GlobalCfg->pgc_PopupCloseDelay = 5;
179 ps->ps_GlobalCfg->pgc_PopupActivateWin = FALSE;
180 ps->ps_GlobalCfg->pgc_PopupWinToFront = TRUE;
181 ps->ps_GlobalCfg->pgc_AutoDisableLP = FALSE;
182 ps->ps_GlobalCfg->pgc_AutoDisableDead = FALSE;
183 ps->ps_GlobalCfg->pgc_AutoRestartDead = TRUE;
184 ps->ps_GlobalCfg->pgc_PowerSaving = FALSE;
185 ps->ps_GlobalCfg->pgc_ForceSuspend = FALSE;
186 ps->ps_GlobalCfg->pgc_SuspendTimeout = 30;
188 ps->ps_GlobalCfg->pgc_PrefsVersion = 0; // is updated on writing
189 ps->ps_ConfigRead = FALSE;
190 if(pic)
192 pic = pAllocForm(ps, pic, IFFFORM_STACKCFG);
193 if(pic)
195 pAddCfgChunk(ps, pic, ps->ps_GlobalCfg);
198 ps->ps_PoPo.po_InsertSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Connect.iff");
199 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Disconnect.iff");
202 STRPTR tmpstr;
203 tmpstr = psdCopyStr((STRPTR) VERSION_STRING);
204 if(tmpstr)
206 tmpstr[strlen(tmpstr)-2] = 0;
207 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s (%p)!", tmpstr, ps->ps_ReleaseVersion);
208 psdFreeVec(tmpstr);
209 } else {
210 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s", VERSION_STRING);
214 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "This is the AROS port.");
216 KPRINTF(10, ("libOpen: Ok\n"));
217 ps->ps_StackInit = TRUE;
218 ReleaseSemaphore(&ps->ps_ReentrantLock);
219 pStartEventHandler(ps);
221 return TRUE;
222 } else {
223 KPRINTF(20, ("libOpen: No memory for cfg!\n"));
225 } else {
226 KPRINTF(20, ("libOpen: OpenDevice(timer.device) failed!\n"));
228 ReleaseSemaphore(&ps->ps_ReentrantLock);
229 return FALSE;
231 ReleaseSemaphore(&ps->ps_ReentrantLock);
232 KPRINTF(5, ("libOpen: openCnt = %ld\n", ps->ps_Library.lib_OpenCnt));
233 return TRUE;
236 int GM_UNIQUENAME(libExpunge)(LIBBASETYPEPTR ps)
238 struct PsdHardware *phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
239 struct PsdUsbClass *puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
240 struct PsdErrorMsg *pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
241 struct PsdIFFContext *pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
242 KPRINTF(10, ("libExpunge ps: 0x%p\n", ps));
243 while(phw->phw_Node.ln_Succ)
245 psdRemHardware(phw);
246 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
248 while(puc->puc_Node.ln_Succ)
250 psdRemClass(puc);
251 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
253 while(pem->pem_Node.ln_Succ)
255 psdRemErrorMsg(pem);
256 pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
259 while(pic->pic_Node.ln_Succ)
261 pFreeForm(ps, pic);
262 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
265 if(ps->ps_PoPo.po_Task)
267 ps->ps_PoPo.po_ReadySignal = SIGB_SINGLE;
268 ps->ps_PoPo.po_ReadySigTask = FindTask(NULL);
269 Signal(ps->ps_PoPo.po_Task, SIGBREAKF_CTRL_C);
270 while(ps->ps_PoPo.po_Task)
272 Wait(1L<<ps->ps_PoPo.po_ReadySignal);
274 ps->ps_PoPo.po_ReadySigTask = NULL;
275 //FreeSignal(ps->ps_PoPo.po_ReadySignal);
277 if(ps->ps_EventHandler.ph_Task)
279 ps->ps_EventHandler.ph_ReadySignal = SIGB_SINGLE;
280 ps->ps_EventHandler.ph_ReadySigTask = FindTask(NULL);
281 Signal(ps->ps_EventHandler.ph_Task, SIGBREAKF_CTRL_C);
282 while(ps->ps_EventHandler.ph_Task)
284 Wait(1L<<ps->ps_EventHandler.ph_ReadySignal);
286 ps->ps_EventHandler.ph_ReadySigTask = NULL;
287 //FreeSignal(ps->ps_EventHandler.ph_ReadySignal);
289 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
290 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
291 pGarbageCollectEvents(ps);
293 CloseDevice((struct IORequest *) &ps->ps_TimerIOReq);
294 DeletePool(ps->ps_SemaMemPool);
295 DeletePool(ps->ps_MemPool);
297 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%p\n",
298 UtilityBase));
299 CloseLibrary((struct Library *) UtilityBase);
301 CloseLibrary(DOSBase);
303 KPRINTF(1, ("libExpunge: removing library node 0x%p\n",
304 &ps->ps_Library.lib_Node));
305 Remove(&ps->ps_Library.lib_Node);
307 return TRUE;
309 /* \\\ */
311 ADD2INITLIB(GM_UNIQUENAME(libInit), 0)
312 ADD2OPENLIB(GM_UNIQUENAME(libOpen), 0)
313 ADD2EXPUNGELIB(GM_UNIQUENAME(libExpunge), 0);
316 * ***********************************************************************
317 * * Library functions *
318 * ***********************************************************************
321 static const ULONG *PsdPTArray[PGA_LAST+1];
323 /* *** Memory *** */
325 /* /// "psdAllocVec()" */
326 AROS_LH1(APTR, psdAllocVec,
327 AROS_LHA(ULONG, size, D0),
328 LIBBASETYPEPTR, ps, 5, psd)
330 AROS_LIBFUNC_INIT
331 ULONG *pmem;
332 KPRINTF(1, ("psdAllocVec(%ld)\n", size));
333 #ifndef MEMDEBUG
334 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)))))
336 #else
337 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)) + 1024)))
339 ULONG upos = size + (1*sizeof(ULONG));
340 UWORD unum = 1024;
341 UBYTE *dbptr = (UBYTE *) pmem;
342 while(unum--)
344 dbptr[upos] = upos;
345 upos++;
347 #endif
348 *pmem++ = size;
349 ps->ps_MemAllocated += size;
350 return((APTR) pmem);
352 return(NULL);
353 AROS_LIBFUNC_EXIT
355 /* \\\ */
357 /* /// "psdFreeVec()" */
358 AROS_LH1(void, psdFreeVec,
359 AROS_LHA(APTR, pmem, A1),
360 LIBBASETYPEPTR, ps, 6, psd)
362 AROS_LIBFUNC_INIT
363 ULONG size;
365 KPRINTF(1, ("psdFreeVec(%p)\n", pmem));
366 if(pmem)
368 size = ((ULONG *) pmem)[-1];
369 ps->ps_MemAllocated -= size;
371 #ifdef MEMDEBUG
372 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)) + 1024);
373 #else
374 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)));
375 #endif
377 AROS_LIBFUNC_EXIT
379 /* \\\ */
381 /* *** PBase *** */
383 /* /// "pDebugSemaInfo()" */
384 void pDebugSemaInfo(LIBBASETYPEPTR ps, struct PsdSemaInfo *psi)
386 struct PsdReadLock *prl;
387 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
388 "Semaphore %p %s (Excl/SharedLockCount %ld/%ld) (Owner: %s):",
389 psi->psi_LockSem,
390 psi->psi_LockSem->pls_Node.ln_Name,
391 psi->psi_LockSem->pls_ExclLockCount,
392 psi->psi_LockSem->pls_SharedLockCount,
393 psi->psi_LockSem->pls_Owner ? (const char *)psi->psi_LockSem->pls_Owner->tc_Node.ln_Name : "None");
395 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_WaitQueue.lh_Head;
396 while(prl->prl_Node.ln_Succ)
398 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
399 " Waiting Task: %p (%s) %s",
400 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
401 prl->prl_IsExcl ? "Excl" : "Shared");
402 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
404 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_ReadLocks.lh_Head;
405 while(prl->prl_Node.ln_Succ)
407 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
408 " Readlock Task: %p (%s), Count %ld",
409 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
410 prl->prl_Count);
411 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
414 /* \\\ */
416 /* /// "pInitSem()" */
417 void pInitSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls, STRPTR name)
419 struct PsdSemaInfo *psi = NULL;
420 NewList(&pls->pls_WaitQueue);
421 NewList(&pls->pls_ReadLocks);
422 pls->pls_Node.ln_Name = name;
423 // struct should be nulled anyway
424 pls->pls_Owner = NULL;
425 pls->pls_ExclLockCount = 0;
426 pls->pls_SharedLockCount = 0;
427 pls->pls_Dead = FALSE;
429 Forbid();
430 psi = (struct PsdSemaInfo *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdSemaInfo));
431 if(!psi)
433 Permit();
434 return;
436 psi->psi_LockSem = pls;
437 AddTail(&ps->ps_DeadlockDebug, &psi->psi_Node);
438 Permit();
440 /* \\\ */
442 /* /// "pDeleteSem()" */
443 void pDeleteSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
445 struct PsdSemaInfo *psi;
446 Forbid();
447 pls->pls_Dead = TRUE;
448 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
449 while(psi->psi_Node.ln_Succ)
451 if(psi->psi_LockSem == pls)
453 if(pls->pls_SharedLockCount + pls->pls_ExclLockCount)
455 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Semaphore still locked when attempting to delete it!\n");
456 pDebugSemaInfo(ps, psi);
457 } else {
458 Remove(&psi->psi_Node);
459 FreePooled(ps->ps_SemaMemPool, psi, sizeof(struct PsdSemaInfo));
461 break;
463 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
465 Permit();
467 /* \\\ */
469 /* /// "pLockSemExcl()" */
470 void pLockSemExcl(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
472 struct PsdReadLock waitprl;
473 struct Task *thistask = FindTask(NULL);
475 waitprl.prl_Task = thistask;
476 waitprl.prl_IsExcl = TRUE;
478 Forbid();
481 // it's already mine!!
482 if(thistask == pls->pls_Owner)
484 break;
486 if(!pls->pls_ExclLockCount)
488 // easy case: no shared locks, no exclusive locker
489 if(!pls->pls_SharedLockCount)
491 break;
493 // sole readlock promotion case
494 if((pls->pls_SharedLockCount == 1) && ((struct PsdReadLock *) pls->pls_ReadLocks.lh_Head)->prl_Task == thistask)
496 KPRINTF(1, ("Promoting read lock (%p) to write lock!\n", thistask));
497 break;
501 // okay, bad luck, we've got to wait somehow
502 AddHead(&pls->pls_WaitQueue, &waitprl.prl_Node);
503 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
505 Wait(SIGF_SINGLE);
507 Remove(&waitprl.prl_Node);
508 } while(TRUE);
509 pls->pls_Owner = thistask;
510 pls->pls_ExclLockCount++;
511 Permit();
513 /* \\\ */
515 /* /// "pLockSemShared()" */
516 void pLockSemShared(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
518 struct PsdReadLock *prl;
519 struct Task *thistask = FindTask(NULL);
521 Forbid();
522 // is this already locked exclusively by me?
523 if(thistask == pls->pls_Owner)
525 // yes? then just increase exclusive lock count
526 pls->pls_ExclLockCount++;
527 Permit();
528 return;
531 // find existing readlock
532 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
533 while(prl->prl_Node.ln_Succ)
535 if(prl->prl_Task == thistask)
537 KPRINTF(1, ("Increasing ReadLock (%p) count to %ld\n", thistask, prl->prl_Count));
538 prl->prl_Count++;
539 Permit();
540 return;
542 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
545 // this is a new readlock, generate context
546 if(!(prl = (struct PsdReadLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdReadLock))))
548 KPRINTF(20, ("No mem for shared lock! context (%p) on %p\n", thistask, pls));
549 // try exclusive lock as fallback (needs no memory)
550 Permit();
551 pLockSemExcl(ps, pls);
552 return;
555 KPRINTF(1, ("New ReadLockShared context (%p) on %p\n", thistask, pls));
556 prl->prl_Task = thistask;
557 prl->prl_Count = 0;
558 prl->prl_IsExcl = FALSE;
560 // if it's exclusively locked, wait for this lock to vanish
561 while(pls->pls_Owner)
563 AddTail(&pls->pls_WaitQueue, &prl->prl_Node);
564 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
566 Wait(SIGF_SINGLE);
568 Remove(&prl->prl_Node);
571 if(prl->prl_IsExcl)
573 // we got promoted by BorrowLocks during the process! So we don't need the shared stuff anymore
574 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
575 pls->pls_Owner = thistask;
576 pls->pls_ExclLockCount++;
577 } else {
578 // got the lock!
579 AddHead(&pls->pls_ReadLocks, &prl->prl_Node);
580 prl->prl_Count++;
581 pls->pls_SharedLockCount++;
583 Permit();
584 return;
586 /* \\\ */
588 /* /// "pUnlockSem()" */
589 void pUnlockSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
591 struct PsdReadLock *prl;
592 struct Task *thistask = FindTask(NULL);
593 BOOL gotit = FALSE;
595 Forbid();
596 if(pls->pls_Owner)
598 // exclusively locked, this means unlocking task must be owner
599 if(pls->pls_Owner != thistask)
601 Permit();
602 psdDebugSemaphores();
603 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
604 "Attempt to unlock exclusive semaphore %p not owned by task %s!",
605 pls, thistask->tc_Node.ln_Name);
606 return;
609 if(--pls->pls_ExclLockCount)
611 // still locked
612 Permit();
613 return;
615 pls->pls_Owner = NULL;
616 // otherwise drop through and notify
617 } else {
618 if(!pls->pls_SharedLockCount)
620 Permit();
621 psdDebugSemaphores();
622 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
623 "Attempt to unlock (free) semaphore %p once too often by task %s!",
624 pls, thistask->tc_Node.ln_Name);
625 return;
627 // find readlock
628 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
629 while(prl->prl_Node.ln_Succ)
631 if(prl->prl_Task == thistask)
633 if(--prl->prl_Count)
635 // can't be the last lock, so just reduce count and return
636 Permit();
637 return;
639 // remove read lock, it's no longer needed
640 KPRINTF(1, ("Removing read lock context (%p) on %p!\n", thistask, pls));
641 Remove(&prl->prl_Node);
642 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
643 gotit = TRUE;
644 // losing a designated lock
645 pls->pls_SharedLockCount--;
646 break;
648 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
650 if(!gotit)
652 Permit();
653 psdDebugSemaphores();
654 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
655 "Attempt to unlock (shared) semaphore %p once too often by task %s!",
656 pls, thistask->tc_Node.ln_Name);
657 return;
660 // we need to notify anyway, because the waiter could already have a shared lock
661 // on the same semaphore, and if we only notified on LockCount reaching zero,
662 // the locker would wait forever.
665 // notify waiting tasks
666 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
667 while(prl->prl_Node.ln_Succ)
669 Signal(prl->prl_Task, SIGF_SINGLE);
670 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
672 Permit();
674 /* \\\ */
676 /* /// "psdDebugSemaphores()" */
677 AROS_LH0(void, psdDebugSemaphores,
678 LIBBASETYPEPTR, ps, 81, psd)
680 AROS_LIBFUNC_INIT
681 struct Task *thistask = FindTask(NULL);
682 struct PsdSemaInfo *psi;
684 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
685 "Debug Semaphores (%p)", thistask);
687 Forbid();
688 // search for context
689 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
690 while(psi->psi_Node.ln_Succ)
692 pDebugSemaInfo(ps, psi);
693 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
695 Permit();
696 AROS_LIBFUNC_EXIT
698 /* \\\ */
700 /* /// "psdLockReadPBase()" */
701 AROS_LH0(void, psdLockReadPBase,
702 LIBBASETYPEPTR, ps, 8, psd)
704 AROS_LIBFUNC_INIT
705 KPRINTF(2, ("psdLockReadPBase(%p)\n", FindTask(NULL)));
706 pLockSemShared(ps, &ps->ps_Lock);
707 AROS_LIBFUNC_EXIT
709 /* \\\ */
711 /* /// "psdLockWritePBase()" */
712 AROS_LH0(void, psdLockWritePBase,
713 LIBBASETYPEPTR, ps, 7, psd)
715 AROS_LIBFUNC_INIT
716 KPRINTF(2, ("psdLockWritePBase(%p)\n", FindTask(NULL)));
717 pLockSemExcl(ps, &ps->ps_Lock);
718 AROS_LIBFUNC_EXIT
720 /* \\\ */
722 /* /// "psdUnlockPBase()" */
723 AROS_LH0(void, psdUnlockPBase,
724 LIBBASETYPEPTR, ps, 9, psd)
726 AROS_LIBFUNC_INIT
727 KPRINTF(2, ("psdUnlockPBase(%p)\n", FindTask(NULL)));
728 pUnlockSem(ps, &ps->ps_Lock);
729 AROS_LIBFUNC_EXIT
731 /* \\\ */
733 /* /// "psdBorrowLocksWait()" */
734 AROS_LH2(ULONG, psdBorrowLocksWait,
735 AROS_LHA(struct Task *, task, A1),
736 AROS_LHA(ULONG, signals, D0),
737 LIBBASETYPEPTR, ps, 97, psd)
739 AROS_LIBFUNC_INIT
740 struct Task *thistask = FindTask(NULL);
741 ULONG cnt = 0;
742 ULONG sigmask;
743 struct PsdSemaInfo *psi;
744 struct PsdLockSem *pls;
745 struct PsdReadLock *prl;
746 struct PsdBorrowLock *pbl;
747 struct List borrows;
748 struct List reclaims;
749 BOOL moveowner;
751 XPRINTF(10, ("Borrowing locks from %p (%s) to %p (%s)!\n",
752 thistask, thistask->tc_Node.ln_Name, task, task->tc_Node.ln_Name));
754 Forbid();
755 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
756 while(psi->psi_Node.ln_Succ)
758 pls = psi->psi_LockSem;
759 if(pls->pls_Owner == thistask)
761 cnt++;
763 if(pls->pls_SharedLockCount)
765 struct PsdReadLock *prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
768 if(prl->prl_Task == thistask)
770 cnt++;
771 break;
773 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
775 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
777 if(!cnt)
779 Permit();
780 XPRINTF(10, ("Nothing to borrow!\n"));
781 return(Wait(signals));
784 NewList(&borrows);
785 NewList(&reclaims);
786 XPRINTF(10, ("Borrowing %ld locks\n", cnt));
788 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
789 while(psi->psi_Node.ln_Succ)
791 moveowner = TRUE;
792 pls = psi->psi_LockSem;
793 if(pls->pls_Owner == thistask)
795 // check if the target task is already waiting for that lock
796 // in this case, we simply remove our exclusive lock and let
797 // the other task catch it
798 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
799 while(prl->prl_Node.ln_Succ)
801 if(prl->prl_Task == task)
803 if(!prl->prl_IsExcl)
805 // if we hand over the excl lock, we have to make sure that the exclusiveness is kept
806 // and no other thread may catch it while it is shared.
807 // hence we will need set this lock exclusive aswell
808 // this no optimal solution, but it guarantees the same
809 // behaviour with pending lock and no pending lock
810 prl->prl_IsExcl = TRUE;
811 XPRINTF(10, ("Promo waiting lock to excl\n"));
813 // move shared lock to top of the list
814 Remove(&prl->prl_Node);
815 AddHead(&pls->pls_WaitQueue, &prl->prl_Node);
816 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
818 pbl->pbl_LockSem = pls;
819 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
820 AddTail(&reclaims, &pbl->pbl_Node);
822 // unlock exclusive lock
823 pls->pls_ExclLockCount = 0;
824 pls->pls_Owner = NULL;
825 Signal(task, SIGF_SINGLE);
826 XPRINTF(10, ("Waiting lock %p transfer\n", pls));
828 moveowner = FALSE;
829 break;
831 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
833 if(moveowner)
835 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
837 pbl->pbl_LockSem = pls;
838 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
839 AddTail(&borrows, &pbl->pbl_Node);
840 pls->pls_Owner = task;
841 XPRINTF(10, ("Lock %p transfer\n", pls));
845 if(pls->pls_SharedLockCount)
847 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
850 if(prl->prl_Task == thistask)
852 // check if target task is waiting for this task
853 struct PsdReadLock *prl2 = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
854 while(prl2->prl_Node.ln_Succ)
856 if(prl2->prl_Task == task)
858 // move lock to top of the list
859 Remove(&prl2->prl_Node);
860 AddHead(&pls->pls_WaitQueue, &prl2->prl_Node);
861 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
863 pbl->pbl_LockSem = pls;
864 pbl->pbl_ReadLock = prl;
865 pbl->pbl_Count = prl->prl_Count;
866 AddHead(&reclaims, &pbl->pbl_Node);
868 // unlock shared lock
869 Remove(&prl->prl_Node);
870 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
871 pls->pls_SharedLockCount--;
872 Signal(task, SIGF_SINGLE);
874 moveowner = FALSE;
875 XPRINTF(10, ("Waiting shared lock %p transfer\n", pls));
876 break;
878 prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ;
880 if(moveowner)
882 // check if target task already has a shared lock on this
883 prl2 = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
886 if(prl2->prl_Task == task)
888 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
890 // we redirect to this other lock
891 pbl->pbl_LockSem = pls;
892 pbl->pbl_ReadLock = prl2;
893 pbl->pbl_Count = prl->prl_Count; // save the old lock count
894 AddTail(&borrows, &pbl->pbl_Node);
896 // unlock shared lock
897 Remove(&prl->prl_Node);
898 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
899 pls->pls_SharedLockCount--;
900 // just increase lockcount, so a split occurs automatically
901 prl2->prl_Count += pbl->pbl_Count;
903 XPRINTF(10, ("Already locked %p transfer\n", pls));
904 moveowner = FALSE;
905 break;
907 } while((prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ)->prl_Node.ln_Succ);
909 if(moveowner)
911 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
913 pbl->pbl_LockSem = pls;
914 pbl->pbl_ReadLock = prl;
915 pbl->pbl_Count = prl->prl_Count;
916 AddTail(&borrows, &pbl->pbl_Node);
917 prl->prl_Task = task;
918 XPRINTF(10, ("Std lock %p transfer\n", pls));
921 break;
923 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
925 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
928 sigmask = Wait(signals);
930 // try to get moved locks back first
931 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
932 while(pbl->pbl_Node.ln_Succ)
934 Remove(&pbl->pbl_Node);
935 pls = pbl->pbl_LockSem;
936 if(pbl->pbl_ExclLockCount)
938 if(pbl->pbl_ExclLockCount == pls->pls_ExclLockCount)
940 // all fine, other task didn't use the locks or returned them already
941 pls->pls_Owner = thistask;
942 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
943 } else {
944 // okay, bad thing, release lock and try to obtain it again -- eventually the other task should free the lock again
945 pls->pls_ExclLockCount -= pbl->pbl_ExclLockCount;
946 AddTail(&reclaims, &pbl->pbl_Node);
948 } else {
949 if(pls->pls_Owner == task)
951 // oh, damn. The other task converted our shared lock into an exclusive lock --
952 // we cannot claim this back right now. This gets tricky now.
953 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
955 // luckily, the count didn't change, so we just release the shared lock and requeue us into the reclaim list
956 Remove(&pbl->pbl_ReadLock->prl_Node);
957 FreePooled(ps->ps_SemaMemPool, pbl->pbl_ReadLock, sizeof(struct PsdReadLock));
958 pbl->pbl_ReadLock = NULL;
959 pls->pls_SharedLockCount--; // should turn to 0
960 } else {
961 // can it get worse? obviously, the alien task also has added some read locks
962 // this means we need to split up!
963 // therefore we leave a few lock counts and requeue
964 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
965 pbl->pbl_ReadLock = NULL;
967 AddHead(&reclaims, &pbl->pbl_Node);
968 } else {
969 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
971 // the count didn't change, just so just change owner
972 pbl->pbl_ReadLock->prl_Task = thistask;
973 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
974 } else {
975 // the alien task still has some read locks
976 // this means we need to split up!
977 // therefore we leave a few lock counts and requeue
978 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
979 pbl->pbl_ReadLock = NULL;
980 AddHead(&reclaims, &pbl->pbl_Node);
984 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
987 // try to reclaim released locks
988 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
989 while(pbl->pbl_Node.ln_Succ)
991 Remove(&pbl->pbl_Node);
992 pls = pbl->pbl_LockSem;
993 while(pbl->pbl_Count)
995 pLockSemShared(ps, pls);
996 --pbl->pbl_Count;
998 while(pbl->pbl_ExclLockCount)
1000 pLockSemExcl(ps, pls);
1001 --pbl->pbl_ExclLockCount;
1003 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
1004 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
1006 Permit();
1008 return(sigmask);
1009 AROS_LIBFUNC_EXIT
1011 /* \\\ */
1013 /* *** Support *** */
1015 /* /// "psdCopyStr()" */
1016 AROS_LH1(STRPTR, psdCopyStr,
1017 AROS_LHA(CONST_STRPTR, name, A0),
1018 LIBBASETYPEPTR, ps, 10, psd)
1020 AROS_LIBFUNC_INIT
1021 STRPTR rs = psdAllocVec((ULONG) strlen(name)+1);
1022 KPRINTF(1, ("psdCopyStr(%s)\n", name));
1023 if(rs)
1025 strcpy(rs, name);
1027 return(rs);
1028 AROS_LIBFUNC_EXIT
1030 /* \\\ */
1032 /* /// "psdSafeRawDoFmtA()" */
1033 AROS_LH4(void, psdSafeRawDoFmtA,
1034 AROS_LHA(STRPTR, buf, A0),
1035 AROS_LHA(ULONG, len, D0),
1036 AROS_LHA(CONST_STRPTR, fmtstr, A1),
1037 AROS_LHA(RAWARG, fmtdata, A2),
1038 LIBBASETYPEPTR, ps, 42, psd)
1040 AROS_LIBFUNC_INIT
1041 struct PsdRawDoFmt rdf;
1043 if(len > 0)
1045 rdf.rdf_Len = len;
1046 rdf.rdf_Buf = buf;
1047 RawDoFmt(fmtstr, fmtdata, (void (*)()) pPutChar, &rdf);
1048 buf[len-1] = 0;
1050 AROS_LIBFUNC_EXIT
1052 /* \\\ */
1054 /* /// "pPutChar()" */
1055 AROS_UFH2(void, pPutChar,
1056 AROS_UFHA(char, ch, D0),
1057 AROS_UFHA(struct PsdRawDoFmt *, rdf, A3))
1059 AROS_USERFUNC_INIT
1060 if(rdf->rdf_Len)
1062 rdf->rdf_Len--;
1063 *rdf->rdf_Buf++ = ch;
1065 AROS_USERFUNC_EXIT
1067 /* \\\ */
1069 /* /// "psdCopyStrFmtA()" */
1070 AROS_LH2(STRPTR, psdCopyStrFmtA,
1071 AROS_LHA(CONST_STRPTR, fmtstr, A0),
1072 AROS_LHA(RAWARG, fmtdata, A1),
1073 LIBBASETYPEPTR, ps, 68, psd)
1075 AROS_LIBFUNC_INIT
1076 ULONG len = 0;
1077 STRPTR buf;
1079 RawDoFmt(fmtstr, fmtdata, (void (*)()) pRawFmtLength, &len);
1080 buf = psdAllocVec(len+1);
1081 if(buf)
1083 psdSafeRawDoFmtA(buf, len+1, fmtstr, fmtdata);
1085 return(buf);
1086 AROS_LIBFUNC_EXIT
1088 /* \\\ */
1090 /* /// "pRawFmtLength()" */
1091 AROS_UFH2(void, pRawFmtLength,
1092 AROS_UFHA(char, ch, D0),
1093 AROS_UFHA(ULONG *, len, A3))
1095 AROS_USERFUNC_INIT
1096 (*len)++;
1097 AROS_USERFUNC_EXIT
1099 /* \\\ */
1101 /* /// "psdDelayMS()" */
1102 AROS_LH1(void, psdDelayMS,
1103 AROS_LHA(ULONG, milli, D0),
1104 LIBBASETYPEPTR, ps, 11, psd)
1106 AROS_LIBFUNC_INIT
1107 struct MsgPort mp;
1108 struct timerequest tr;
1110 /* Clear memory for messageport */
1111 memset(&mp, 0, sizeof(mp));
1113 KPRINTF(1, ("psdDelayMS(%ld)\n", milli));
1114 mp.mp_Flags = PA_SIGNAL;
1115 mp.mp_SigBit = SIGB_SINGLE;
1116 mp.mp_SigTask = FindTask(NULL);
1117 NewList(&mp.mp_MsgList);
1118 CopyMem(&ps->ps_TimerIOReq, &tr, sizeof(tr));
1119 tr.tr_node.io_Message.mn_ReplyPort = &mp;
1120 tr.tr_time.tv_secs = 0;
1121 tr.tr_time.tv_micro = milli * 1000;
1122 DoIO((struct IORequest *) &tr);
1123 AROS_LIBFUNC_EXIT
1125 /* \\\ */
1127 /* /// "psdGetAttrsA()" */
1128 AROS_LH3(LONG, psdGetAttrsA,
1129 AROS_LHA(ULONG, type, D0),
1130 AROS_LHA(APTR, psdstruct, A0),
1131 AROS_LHA(struct TagItem *, tags, A1),
1132 LIBBASETYPEPTR, ps, 22, psd)
1134 AROS_LIBFUNC_INIT
1135 struct TagItem *ti;
1136 ULONG count = 0;
1137 ULONG *packtab = NULL;
1139 KPRINTF(1, ("psdGetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1141 if(type <= PGA_LAST)
1143 packtab = (ULONG *) PsdPTArray[type];
1146 switch(type)
1148 case PGA_STACK:
1149 psdstruct = ps;
1150 if((ti = FindTagItem(PA_HardwareList, tags)))
1152 *((struct List **) ti->ti_Data) = &ps->ps_Hardware;
1153 count++;
1155 if((ti = FindTagItem(PA_ClassList, tags)))
1157 *((struct List **) ti->ti_Data) = &ps->ps_Classes;
1158 count++;
1160 if((ti = FindTagItem(PA_ErrorMsgList, tags)))
1162 *((struct List **) ti->ti_Data) = &ps->ps_ErrorMsgs;
1163 count++;
1165 break;
1167 case PGA_HARDWARE:
1168 if((ti = FindTagItem(HA_DeviceList, tags)))
1170 *((struct List **) ti->ti_Data) = &(((struct PsdHardware *) psdstruct)->phw_Devices);
1171 count++;
1173 break;
1175 case PGA_DEVICE:
1176 if((ti = FindTagItem(DA_ConfigList, tags)))
1178 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Configs);
1179 count++;
1181 if((ti = FindTagItem(DA_DescriptorList, tags)))
1183 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Descriptors);
1184 count++;
1186 break;
1188 case PGA_CONFIG:
1189 if((ti = FindTagItem(CA_InterfaceList, tags)))
1191 *((struct List **) ti->ti_Data) = &(((struct PsdConfig *) psdstruct)->pc_Interfaces);
1192 count++;
1194 break;
1196 case PGA_INTERFACE:
1197 if((ti = FindTagItem(IFA_EndpointList, tags)))
1199 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_EPs);
1200 count++;
1202 if((ti = FindTagItem(IFA_AlternateIfList, tags)))
1204 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_AlterIfs);
1205 count++;
1207 break;
1209 case PGA_ERRORMSG:
1210 if((ti = FindTagItem(EMA_DateStamp, tags)))
1212 *((struct DateStamp **) ti->ti_Data) = &(((struct PsdErrorMsg *) psdstruct)->pem_DateStamp);
1213 count++;
1215 break;
1217 case PGA_PIPE:
1218 if((ti = FindTagItem(PPA_IORequest, tags)))
1220 *((struct IOUsbHWReq **) ti->ti_Data) = &(((struct PsdPipe *) psdstruct)->pp_IOReq);
1221 count++;
1223 break;
1225 case PGA_STACKCFG:
1226 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1228 count++;
1229 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_InsertSndFile;
1231 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1233 count++;
1234 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_RemoveSndFile;
1236 break;
1238 if(packtab)
1240 return((LONG) (UnpackStructureTags(psdstruct, (ULONG *) packtab, tags)+count));
1241 } else {
1242 return(-1);
1244 AROS_LIBFUNC_EXIT
1246 /* \\\ */
1248 /* /// "psdSetAttrsA()" */
1249 AROS_LH3(LONG, psdSetAttrsA,
1250 AROS_LHA(ULONG, type, D0),
1251 AROS_LHA(APTR, psdstruct, A0),
1252 AROS_LHA(struct TagItem *, tags, A1),
1253 LIBBASETYPEPTR, ps, 23, psd)
1255 AROS_LIBFUNC_INIT
1256 struct TagItem *ti;
1257 ULONG count = 0;
1258 ULONG *packtab = NULL;
1259 BOOL savepopocfg = FALSE;
1260 BOOL checkcfgupdate = FALSE;
1261 BOOL powercalc = FALSE;
1262 LONG res;
1264 KPRINTF(1, ("psdSetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1266 if(type <= PGA_LAST)
1268 packtab = (ULONG *) PsdPTArray[type];
1271 switch(type)
1273 case PGA_DEVICE:
1274 if(FindTagItem(DA_InhibitPopup, tags) || FindTagItem(DA_InhibitClassBind, tags))
1276 savepopocfg = TRUE;
1278 if(FindTagItem(DA_OverridePowerInfo, tags))
1280 savepopocfg = TRUE;
1281 powercalc = TRUE;
1283 break;
1285 case PGA_STACK:
1286 psdstruct = ps;
1287 break;
1289 case PGA_STACKCFG:
1290 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1292 count++;
1293 if(strcmp(ps->ps_PoPo.po_InsertSndFile, (STRPTR) ti->ti_Data))
1295 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
1296 ps->ps_PoPo.po_InsertSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1299 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1301 count++;
1302 if(strcmp(ps->ps_PoPo.po_RemoveSndFile, (STRPTR) ti->ti_Data))
1304 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
1305 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1308 checkcfgupdate = TRUE;
1309 break;
1311 case PGA_PIPESTREAM:
1313 struct PsdPipeStream *pps = (struct PsdPipeStream *) psdstruct;
1314 struct PsdPipe *pp;
1315 ULONG oldbufsize = pps->pps_BufferSize;
1316 ULONG oldnumpipes = pps->pps_NumPipes;
1317 ULONG cnt;
1319 KPRINTF(1, ("SetAttrs PIPESTREAM\n"));
1320 ObtainSemaphore(&pps->pps_AccessLock);
1321 if((ti = FindTagItem(PSA_MessagePort, tags)))
1323 count++;
1324 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
1326 KPRINTF(1, ("Deleting old MsgPort\n"));
1327 DeleteMsgPort(pps->pps_MsgPort);
1328 pps->pps_MsgPort = NULL;
1330 pps->pps_Flags &= ~PSFF_OWNMSGPORT;
1332 count += PackStructureTags(psdstruct, packtab, tags);
1333 KPRINTF(1, ("Pipes = %ld (old: %ld), BufferSize = %ld (old: %ld)\n",
1334 pps->pps_NumPipes, oldnumpipes, pps->pps_BufferSize, oldbufsize));
1335 if(pps->pps_NumPipes < 1)
1337 pps->pps_NumPipes = 1; /* minimal */
1339 if(pps->pps_BufferSize < pps->pps_Endpoint->pep_MaxPktSize)
1341 pps->pps_BufferSize = pps->pps_Endpoint->pep_MaxPktSize; /* minimal */
1343 if(!pps->pps_MsgPort)
1345 if((pps->pps_MsgPort = CreateMsgPort()))
1347 KPRINTF(1, ("Creating MsgPort\n"));
1348 pps->pps_Flags |= PSFF_OWNMSGPORT;
1351 /* do we need to reallocate? */
1352 if((oldbufsize != pps->pps_BufferSize) ||
1353 (oldnumpipes != pps->pps_NumPipes) ||
1354 (!pps->pps_Pipes) ||
1355 (!pps->pps_Buffer))
1357 if(pps->pps_Pipes)
1359 KPRINTF(1, ("freeing %ld old pipes\n", oldnumpipes));
1360 for(cnt = 0; cnt < oldnumpipes; cnt++)
1362 pp = pps->pps_Pipes[cnt];
1363 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1365 KPRINTF(1, ("Abort %ld\n", cnt));
1366 psdAbortPipe(pp);
1367 KPRINTF(1, ("Wait %ld\n", cnt));
1368 psdWaitPipe(pp);
1370 KPRINTF(1, ("Free %ld\n", cnt));
1371 psdFreePipe(pp);
1373 psdFreeVec(pps->pps_Pipes);
1375 psdFreeVec(pps->pps_Buffer);
1376 /* reset stuff */
1377 NewList(&pps->pps_FreePipes);
1378 NewList(&pps->pps_ReadyPipes);
1379 pps->pps_Offset = 0;
1380 pps->pps_BytesPending = 0;
1381 pps->pps_ReqBytes = 0;
1382 pps->pps_ActivePipe = NULL;
1383 pps->pps_Buffer = psdAllocVec(pps->pps_NumPipes * pps->pps_BufferSize);
1384 pps->pps_Pipes = psdAllocVec(pps->pps_NumPipes * sizeof(struct PsdPipe *));
1385 if(pps->pps_Pipes && pps->pps_Buffer)
1387 KPRINTF(1, ("allocating %ld new pipes\n", pps->pps_NumPipes));
1388 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
1390 pp = psdAllocPipe(pps->pps_Device, pps->pps_MsgPort, pps->pps_Endpoint);
1391 if((pps->pps_Pipes[cnt] = pp))
1393 pp->pp_Num = cnt;
1394 if(pps->pps_Flags & PSFF_NOSHORTPKT) pp->pp_IOReq.iouh_Flags |= UHFF_NOSHORTPKT;
1395 if(pps->pps_Flags & PSFF_NAKTIMEOUT) pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
1396 if(pps->pps_Flags & PSFF_ALLOWRUNT) pp->pp_IOReq.iouh_Flags |= UHFF_ALLOWRUNTPKTS;
1397 pp->pp_IOReq.iouh_NakTimeout = pps->pps_NakTimeoutTime;
1398 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
1399 } else {
1400 KPRINTF(1, ("Allocating Pipe %ld failed!\n", cnt));
1403 } else {
1404 KPRINTF(1, ("Allocating Pipe array failed!\n"));
1405 psdFreeVec(pps->pps_Buffer);
1406 pps->pps_Buffer = NULL;
1407 psdFreeVec(pps->pps_Pipes);
1408 pps->pps_Pipes = NULL;
1411 ReleaseSemaphore(&pps->pps_AccessLock);
1412 return((LONG) count);
1416 if(packtab)
1418 res = (LONG) PackStructureTags(psdstruct, packtab, tags);
1419 } else {
1420 res = -1;
1422 if(savepopocfg)
1424 struct PsdDevice *pd = (struct PsdDevice *) psdstruct;
1425 struct PsdIFFContext *pic;
1427 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1428 if(!pic)
1430 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
1431 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1433 if(pic)
1435 pAddCfgChunk(ps, pic, &pd->pd_PoPoCfg);
1436 checkcfgupdate = TRUE;
1439 if(checkcfgupdate)
1441 pUpdateGlobalCfg(ps, (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head);
1442 pCheckCfgChanged(ps);
1444 if(powercalc)
1446 psdCalculatePower(((struct PsdDevice *) psdstruct)->pd_Hardware);
1448 return(res);
1449 AROS_LIBFUNC_EXIT
1451 /* \\\ */
1453 /* /// "psdSpawnSubTask()" */
1454 AROS_LH3(struct Task *, psdSpawnSubTask,
1455 AROS_LHA(STRPTR, name, A0),
1456 AROS_LHA(APTR, initpc, A1),
1457 AROS_LHA(APTR, userdata, A2),
1458 LIBBASETYPEPTR, ps, 39, psd)
1460 AROS_LIBFUNC_INIT
1461 #define SUBTASKSTACKSIZE AROS_STACKSIZE
1462 struct
1464 struct MemList mrm_ml;
1465 struct MemEntry mtm_me[2];
1466 } memlist;
1468 struct MemList *newmemlist;
1469 struct MemEntry *me;
1470 struct Task *nt;
1471 struct Process *subtask;
1473 if(!(name && initpc))
1475 return(NULL);
1478 /* If there's dos available, create a process instead of a task */
1479 if(pOpenDOS(ps))
1481 subtask = CreateNewProcTags(NP_Entry, initpc,
1482 NP_StackSize, SUBTASKSTACKSIZE,
1483 NP_Priority, ps->ps_GlobalCfg->pgc_SubTaskPri,
1484 NP_Name, name,
1485 NP_CopyVars, FALSE,
1486 NP_UserData, userdata,
1487 TAG_END);
1488 return((struct Task *) subtask);
1491 /* Allocate memory of memlist */
1493 memlist.mrm_ml.ml_Node.ln_Type = NT_MEMORY;
1494 memlist.mrm_ml.ml_Node.ln_Pri = 0;
1495 memlist.mrm_ml.ml_Node.ln_Name = NULL;
1496 memlist.mrm_ml.ml_NumEntries = 3;
1497 me = &memlist.mrm_ml.ml_ME[0];
1498 me[1].me_Un.meu_Reqs = memlist.mrm_ml.ml_ME[0].me_Un.meu_Reqs = MEMF_CLEAR|MEMF_PUBLIC;
1499 me[0].me_Length = sizeof(struct Task);
1500 me[1].me_Length = SUBTASKSTACKSIZE;
1501 me[2].me_Un.meu_Reqs = MEMF_PUBLIC;
1502 me[2].me_Length = strlen(name) + 1;
1504 #ifdef __AROS__
1505 newmemlist = NewAllocEntry(&memlist.mrm_ml, NULL);
1506 if (!newmemlist)
1507 #else
1508 newmemlist = AllocEntry(&memlist.mrm_ml);
1509 if((IPTR) newmemlist & 0x80000000)
1510 #endif
1512 return(NULL);
1514 me = &newmemlist->ml_ME[0];
1515 nt = me[0].me_Un.meu_Addr;
1516 nt->tc_Node.ln_Name = me[2].me_Un.meu_Addr;
1517 strcpy(nt->tc_Node.ln_Name, name);
1518 nt->tc_Node.ln_Type = NT_TASK;
1519 nt->tc_Node.ln_Pri = ps->ps_GlobalCfg->pgc_SubTaskPri;
1520 nt->tc_SPLower = me[1].me_Un.meu_Addr;
1521 nt->tc_SPUpper = nt->tc_SPReg = (APTR) ((IPTR) nt->tc_SPLower + SUBTASKSTACKSIZE);
1522 nt->tc_UserData = userdata;
1523 NewList(&nt->tc_MemEntry);
1524 AddTail(&nt->tc_MemEntry, (struct Node *) newmemlist);
1525 #if !defined(__AROSEXEC_SMP__)
1526 KPRINTF(1, ("TDNestCnt=%ld\n", SysBase->TDNestCnt));
1527 #endif
1528 if((nt = AddTask(nt, initpc, NULL)))
1530 XPRINTF(10, ("Started task %p (%s)\n", nt, name));
1531 return(nt);
1533 FreeEntry(newmemlist);
1534 return(NULL);
1535 AROS_LIBFUNC_EXIT
1537 /* \\\ */
1539 /* /// "psdNumToStr()" */
1540 AROS_LH3(STRPTR, psdNumToStr,
1541 AROS_LHA(UWORD, type, D0),
1542 AROS_LHA(LONG, idx, D1),
1543 AROS_LHA(STRPTR, defstr, A0),
1544 LIBBASETYPEPTR, ps, 38, psd)
1546 AROS_LIBFUNC_INIT
1547 switch(type)
1549 case NTS_IOERR:
1551 const struct PsdWStringMap *psm = usbhwioerrstr;
1552 while(psm->psm_ID)
1554 if(psm->psm_ID == idx)
1556 return(psm->psm_String);
1558 psm++;
1560 break;
1563 case NTS_LANGID:
1565 const struct PsdUWStringMap *psm = usblangids;
1566 while(psm->psm_ID)
1568 if(psm->psm_ID == idx)
1570 return(psm->psm_String);
1572 psm++;
1574 break;
1577 case NTS_TRANSTYPE:
1578 switch(idx)
1580 case USEAF_CONTROL:
1581 return("control");
1582 case USEAF_ISOCHRONOUS:
1583 return("isochronous");
1584 case USEAF_BULK:
1585 return("bulk");
1586 case USEAF_INTERRUPT:
1587 return("interrupt");
1589 break;
1591 case NTS_SYNCTYPE:
1592 switch(idx)
1594 case USEAF_NOSYNC:
1595 return("no synchronization");
1596 case USEAF_ASYNC:
1597 return("asynchronous");
1598 case USEAF_ADAPTIVE:
1599 return("adaptive");
1600 case USEAF_SYNC:
1601 return("synchronous");
1603 break;
1605 case NTS_USAGETYPE:
1606 switch(idx)
1608 case USEAF_DATA:
1609 return("data");
1610 case USEAF_FEEDBACK:
1611 return("feedback");
1612 case USEAF_IMPLFEEDBACK:
1613 return("implicit feedback data");
1615 break;
1617 case NTS_VENDORID:
1619 const struct PsdUWStringMap *psm = usbvendorids;
1620 while(psm->psm_ID)
1622 if(psm->psm_ID == idx)
1624 return(psm->psm_String);
1626 psm++;
1628 break;
1631 case NTS_CLASSCODE:
1633 const struct PsdWStringMap *psm = usbclasscodestr;
1634 while(psm->psm_ID)
1636 if(psm->psm_ID == idx)
1638 return(psm->psm_String);
1640 psm++;
1642 break;
1645 case NTS_DESCRIPTOR:
1647 const struct PsdULStringMap *psm = usbdesctypestr;
1648 while(psm->psm_ID)
1650 if(psm->psm_ID == idx)
1652 return(psm->psm_String);
1654 psm++;
1656 break;
1659 case NTS_COMBOCLASS:
1661 const struct PsdULStringMap *psm = usbcomboclasscodestr;
1662 if(idx & (NTSCCF_CLASS|NTSCCF_SUBCLASS|NTSCCF_PROTO))
1664 while(psm->psm_ID)
1666 BOOL take;
1667 take = TRUE;
1668 if(psm->psm_ID & NTSCCF_CLASS)
1670 if((!(idx & NTSCCF_CLASS)) || ((idx & 0x0000ff) != (psm->psm_ID & 0x0000ff)))
1672 take = FALSE;
1675 if(psm->psm_ID & NTSCCF_SUBCLASS)
1677 if((!(idx & NTSCCF_SUBCLASS)) || ((idx & 0x00ff00) != (psm->psm_ID & 0x00ff00)))
1679 take = FALSE;
1682 if(psm->psm_ID & NTSCCF_PROTO)
1684 if((!(idx & NTSCCF_PROTO)) || ((idx & 0xff0000) != (psm->psm_ID & 0xff0000)))
1686 take = FALSE;
1689 if(take)
1691 return(psm->psm_String);
1693 psm++;
1696 break;
1699 return(defstr);
1700 AROS_LIBFUNC_EXIT
1702 /* \\\ */
1704 /* *** Endpoint *** */
1706 /* /// "pFreeEndpoint()" */
1707 void pFreeEndpoint(struct PsdEndpoint *pep)
1709 LIBBASETYPEPTR ps = pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Base;
1710 KPRINTF(2, (" FreeEndpoint()\n"));
1711 Remove(&pep->pep_Node);
1712 psdFreeVec(pep);
1714 /* \\\ */
1716 /* /// "pAllocEndpoint()" */
1717 struct PsdEndpoint * pAllocEndpoint(struct PsdInterface *pif)
1719 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1720 struct PsdEndpoint *pep;
1721 if((pep = psdAllocVec(sizeof(struct PsdEndpoint))))
1723 pep->pep_Interface = pif;
1724 AddTail(&pif->pif_EPs, &pep->pep_Node);
1725 return(pep);
1727 return(NULL);
1729 /* \\\ */
1731 /* /// "psdFindEndpointA()" */
1732 AROS_LH3(struct PsdEndpoint *, psdFindEndpointA,
1733 AROS_LHA(struct PsdInterface *, pif, A0),
1734 AROS_LHA(struct PsdEndpoint *, pep, A2),
1735 AROS_LHA(struct TagItem *, tags, A1),
1736 LIBBASETYPEPTR, ps, 67, psd)
1738 AROS_LIBFUNC_INIT
1739 struct TagItem *ti;
1740 BOOL takeit;
1742 KPRINTF(2, ("psdFindEndpointA(%p, %p, %p)\n", pif, pep, tags));
1743 if(!pep)
1745 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1746 } else {
1747 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1749 while(pep->pep_Node.ln_Succ)
1751 takeit = TRUE;
1752 if((ti = FindTagItem(EA_IsIn, tags)))
1754 if((ti->ti_Data && !pep->pep_Direction) || (!ti->ti_Data && pep->pep_Direction))
1756 takeit = FALSE;
1759 if((ti = FindTagItem(EA_EndpointNum, tags)))
1761 if(ti->ti_Data != pep->pep_EPNum)
1763 takeit = FALSE;
1766 if((ti = FindTagItem(EA_TransferType, tags)))
1768 if(ti->ti_Data != pep->pep_TransType)
1770 takeit = FALSE;
1773 if((ti = FindTagItem(EA_MaxPktSize, tags)))
1775 if(ti->ti_Data != pep->pep_MaxPktSize)
1777 takeit = FALSE;
1780 if((ti = FindTagItem(EA_Interval, tags)))
1782 if(ti->ti_Data != pep->pep_Interval)
1784 takeit = FALSE;
1788 if(takeit)
1790 return(pep);
1792 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1794 return(NULL);
1795 AROS_LIBFUNC_EXIT
1797 /* \\\ */
1799 /* *** Interface *** */
1801 /* /// "pFreeInterface()" */
1802 void pFreeInterface(struct PsdInterface *pif)
1804 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1805 struct PsdEndpoint *pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1806 struct PsdInterface *altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1807 KPRINTF(2, (" FreeInterface()\n"));
1808 /* Remove alternate interfaces */
1809 while(altif->pif_Node.ln_Succ)
1811 pFreeInterface(altif);
1812 altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1814 /* Remove endpoints */
1815 while(pep->pep_Node.ln_Succ)
1817 pFreeEndpoint(pep);
1818 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1820 psdFreeVec(pif->pif_IfStr);
1821 psdFreeVec(pif->pif_IDString);
1822 Remove(&pif->pif_Node);
1823 psdFreeVec(pif);
1825 /* \\\ */
1827 /* /// "pAllocInterface()" */
1828 struct PsdInterface * pAllocInterface(struct PsdConfig *pc)
1830 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
1831 struct PsdInterface *pif;
1832 if((pif = psdAllocVec(sizeof(struct PsdInterface))))
1834 pif->pif_Config = pc;
1835 NewList(&pif->pif_EPs);
1836 NewList(&pif->pif_AlterIfs);
1837 AddTail(&pc->pc_Interfaces, &pif->pif_Node);
1838 return(pif);
1840 return(NULL);
1842 /* \\\ */
1844 /* /// "psdFindInterfaceA()" */
1845 AROS_LH3(struct PsdInterface *, psdFindInterfaceA,
1846 AROS_LHA(struct PsdDevice *, pd, A0),
1847 AROS_LHA(struct PsdInterface *, pif, A2),
1848 AROS_LHA(struct TagItem *, tags, A1),
1849 LIBBASETYPEPTR, ps, 66, psd)
1851 AROS_LIBFUNC_INIT
1852 struct PsdConfig *pc;
1853 struct TagItem *ti;
1854 BOOL takeit;
1855 BOOL searchalt = FALSE;
1856 BOOL isalt = FALSE;
1857 struct PsdInterface *oldpif = NULL;
1859 KPRINTF(2, ("psdFindInterfaceA(%p, %p, %p)\n", pd, pif, tags));
1860 if(!pif)
1862 pc = pd->pd_CurrentConfig;
1863 if(pc)
1865 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
1867 if(!pif)
1869 return(NULL);
1871 } else {
1872 if(FindTagItem(IFA_AlternateNum, tags))
1874 searchalt = TRUE;
1876 if(pif->pif_ParentIf)
1878 // special case: we are in an alternate interface right now
1879 searchalt = TRUE;
1880 if(pif->pif_Node.ln_Succ)
1882 isalt = TRUE;
1883 oldpif = pif->pif_ParentIf;
1884 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1885 } else {
1886 pif = (struct PsdInterface *) pif->pif_ParentIf->pif_Node.ln_Succ;
1888 } else {
1889 // go into alt interfaces
1890 if(searchalt && pif->pif_AlterIfs.lh_Head->ln_Succ)
1892 isalt = TRUE;
1893 oldpif = pif;
1894 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1895 } else {
1896 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1901 while(pif->pif_Node.ln_Succ)
1903 takeit = TRUE;
1904 if((ti = FindTagItem(IFA_InterfaceNum, tags)))
1906 if(ti->ti_Data != pif->pif_IfNum)
1908 takeit = FALSE;
1911 if((ti = FindTagItem(IFA_AlternateNum, tags)))
1913 searchalt = TRUE;
1914 if(ti->ti_Data <= 0xff) // if alternate number is greater than 0xff, don't check compliance, but just enable alternate interface searching
1916 if(ti->ti_Data != pif->pif_Alternate)
1918 takeit = FALSE;
1922 if((ti = FindTagItem(IFA_NumEndpoints, tags)))
1924 if(ti->ti_Data != pif->pif_NumEPs)
1926 takeit = FALSE;
1929 if((ti = FindTagItem(IFA_Class, tags)))
1931 if(ti->ti_Data != pif->pif_IfClass)
1933 takeit = FALSE;
1936 if((ti = FindTagItem(IFA_SubClass, tags)))
1938 if(ti->ti_Data != pif->pif_IfSubClass)
1940 takeit = FALSE;
1943 if((ti = FindTagItem(IFA_Protocol, tags)))
1945 if(ti->ti_Data != pif->pif_IfProto)
1947 takeit = FALSE;
1950 if((ti = FindTagItem(IFA_Binding, tags)))
1952 if((APTR) ti->ti_Data != pif->pif_IfBinding)
1954 takeit = FALSE;
1957 if((ti = FindTagItem(IFA_InterfaceName, tags)))
1959 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IfStr))
1961 takeit = FALSE;
1964 if((ti = FindTagItem(IFA_IDString, tags)))
1966 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IDString))
1968 takeit = FALSE;
1972 if(takeit)
1974 return(pif);
1976 if(searchalt)
1978 if(isalt)
1980 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1981 if(!pif->pif_Node.ln_Succ)
1983 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1984 isalt = FALSE;
1986 } else {
1987 oldpif = pif;
1988 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1989 if(!pif->pif_Node.ln_Succ)
1991 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1992 } else {
1993 isalt = TRUE;
1996 } else {
1997 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2000 return(NULL);
2001 AROS_LIBFUNC_EXIT
2003 /* \\\ */
2005 /* *** Config *** */
2007 /* /// "pFreeConfig()" */
2008 void pFreeConfig(struct PsdConfig *pc)
2010 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
2011 struct PsdInterface *pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2012 KPRINTF(2, (" FreeConfig()\n"));
2013 while(pif->pif_Node.ln_Succ)
2015 psdReleaseIfBinding(pif);
2016 pFreeInterface(pif);
2017 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2019 psdFreeVec(pc->pc_CfgStr);
2020 Remove(&pc->pc_Node);
2021 psdFreeVec(pc);
2023 /* \\\ */
2025 /* /// "pAllocConfig()" */
2026 struct PsdConfig * pAllocConfig(struct PsdDevice *pd)
2028 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2029 struct PsdConfig *pc;
2030 KPRINTF(2, (" AllocConfig()\n"));
2031 if((pc = psdAllocVec(sizeof(struct PsdConfig))))
2033 pc->pc_Device = pd;
2034 NewList(&pc->pc_Interfaces);
2035 AddTail(&pd->pd_Configs, &pc->pc_Node);
2036 return(pc);
2038 return(NULL);
2040 /* \\\ */
2042 /* *** Descriptors *** */
2044 /* /// "pFreeDescriptor()" */
2045 void pFreeDescriptor(struct PsdDescriptor *pdd)
2047 LIBBASETYPEPTR ps = pdd->pdd_Device->pd_Hardware->phw_Base;
2048 KPRINTF(2, (" FreeDescriptor()\n"));
2049 //psdFreeVec(pdd->pdd_Data); // part of the structure alloc
2050 Remove(&pdd->pdd_Node);
2051 psdFreeVec(pdd);
2053 /* \\\ */
2055 /* /// "pAllocDescriptor()" */
2056 struct PsdDescriptor * pAllocDescriptor(struct PsdDevice *pd, UBYTE *buf)
2058 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2059 struct PsdDescriptor *pdd;
2061 KPRINTF(2, (" AllocDescriptor()\n"));
2062 if((pdd = psdAllocVec(sizeof(struct PsdDescriptor) + (ULONG) buf[0])))
2064 pdd->pdd_Device = pd;
2065 pdd->pdd_Data = ((UBYTE *) pdd) + sizeof(struct PsdDescriptor);
2066 pdd->pdd_Length = buf[0];
2067 pdd->pdd_Type = buf[1];
2068 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
2070 pdd->pdd_CSSubType = buf[2];
2072 pdd->pdd_Name = psdNumToStr(NTS_DESCRIPTOR, (LONG) pdd->pdd_Type, "<unknown>");
2073 CopyMem(buf, pdd->pdd_Data, (ULONG) buf[0]);
2074 AddTail(&pd->pd_Descriptors, &pdd->pdd_Node);
2075 return(pdd);
2077 return(NULL);
2079 /* \\\ */
2081 /* /// "psdFindDescriptorA()" */
2082 AROS_LH3(struct PsdDescriptor *, psdFindDescriptorA,
2083 AROS_LHA(struct PsdDevice *, pd, A0),
2084 AROS_LHA(struct PsdDescriptor *, pdd, A2),
2085 AROS_LHA(struct TagItem *, tags, A1),
2086 LIBBASETYPEPTR, ps, 91, psd)
2088 AROS_LIBFUNC_INIT
2089 struct PsdConfig *pc = pd->pd_CurrentConfig;
2090 struct TagItem *ti;
2091 BOOL takeit;
2093 KPRINTF(2, ("psdFindDescriptorA(%p, %p, %p)\n", pd, pdd, tags));
2094 if(!pdd)
2096 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2097 } else {
2098 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2101 while(pdd->pdd_Node.ln_Succ)
2103 takeit = TRUE;
2105 if((ti = FindTagItem(DDA_Config, tags)))
2107 // special case to workaround default: with NULL given, all configs are matched
2108 if(ti->ti_Data && (((struct PsdConfig *) ti->ti_Data) != pdd->pdd_Config))
2110 takeit = FALSE;
2112 } else {
2113 // only take descriptors from the current configuration by default
2114 if(pc != pdd->pdd_Config)
2116 takeit = FALSE;
2119 if((ti = FindTagItem(DDA_Interface, tags)))
2121 if(((struct PsdInterface *) ti->ti_Data) != pdd->pdd_Interface)
2123 takeit = FALSE;
2126 if((ti = FindTagItem(DDA_Endpoint, tags)))
2128 if(((struct PsdEndpoint *) ti->ti_Data) != pdd->pdd_Endpoint)
2130 takeit = FALSE;
2133 if((ti = FindTagItem(DDA_DescriptorType, tags)))
2135 if(ti->ti_Data != pdd->pdd_Type)
2137 takeit = FALSE;
2140 if((ti = FindTagItem(DDA_CS_SubType, tags)))
2142 if(ti->ti_Data != pdd->pdd_CSSubType)
2144 takeit = FALSE;
2147 if((ti = FindTagItem(DDA_DescriptorLength, tags)))
2149 if(ti->ti_Data != pdd->pdd_Length)
2151 takeit = FALSE;
2155 if(takeit)
2157 return(pdd);
2159 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2161 return(NULL);
2162 AROS_LIBFUNC_EXIT
2164 /* \\\ */
2166 /* *** Device *** */
2168 /* /// "pFreeBindings()" */
2169 void pFreeBindings(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2171 struct PsdHardware *phw = pd->pd_Hardware;
2172 struct PsdConfig *pc;
2173 struct PsdInterface *pif;
2174 KPRINTF(3, (" FreeBindings(%p)\n", pd));
2176 /* move device to list of dead devices first
2177 This caused a lot of trouble as it could
2178 happen that a device got into class scan
2179 right after the bindings had been released. */
2180 psdLockWritePBase();
2181 Remove(&pd->pd_Node);
2182 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2183 psdUnlockPBase();
2185 /* If there are bindings, get rid of them. */
2186 psdLockWriteDevice(pd);
2187 psdReleaseDevBinding(pd);
2189 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2190 while(pc->pc_Node.ln_Succ)
2192 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2193 while(pif->pif_Node.ln_Succ)
2195 psdReleaseIfBinding(pif);
2196 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2198 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2200 psdUnlockDevice(pd);
2202 /* \\\ */
2204 /* /// "pFreeDevice()" */
2205 void pFreeDevice(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2207 struct PsdHardware *phw = pd->pd_Hardware;
2208 struct PsdConfig *pc;
2209 struct PsdDescriptor *pdd;
2211 psdCalculatePower(phw);
2212 psdLockWriteDevice(pd);
2213 if(pd->pd_UseCnt)
2215 KPRINTF(20, ("Couldn't free device, use cnt %ld\n", pd->pd_UseCnt));
2216 pd->pd_Flags &= ~PDFF_CONNECTED;
2217 pd->pd_Flags |= PDFF_DELEXPUNGE;
2218 psdUnlockDevice(pd);
2219 } else {
2220 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2221 while(pc->pc_Node.ln_Succ)
2223 pFreeConfig(pc);
2224 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2227 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2228 while(pdd->pdd_Node.ln_Succ)
2230 pFreeDescriptor(pdd);
2231 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2234 psdFreeVec(pd->pd_LangIDArray);
2235 pd->pd_LangIDArray = NULL;
2236 psdFreeVec(pd->pd_MnfctrStr);
2237 pd->pd_MnfctrStr = NULL;
2238 /*if(!ps->ps_PoPo.po_Task) // keep name at least
2240 psdFreeVec(pd->pd_ProductStr);
2241 pd->pd_ProductStr = NULL;
2243 psdFreeVec(pd->pd_OldProductStr);
2244 pd->pd_OldProductStr = NULL;
2245 psdFreeVec(pd->pd_SerNumStr);
2246 pd->pd_SerNumStr = NULL;
2247 psdFreeVec(pd->pd_IDString);
2248 pd->pd_IDString = NULL;
2249 if(pd->pd_DevAddr)
2251 KPRINTF(5,("Released DevAddr %ld\n", pd->pd_DevAddr));
2252 phw->phw_DevArray[pd->pd_DevAddr] = NULL;
2254 psdUnlockDevice(pd);
2255 psdLockWritePBase();
2256 Remove(&pd->pd_Node);
2257 psdUnlockPBase();
2258 pDeleteSem(ps, &pd->pd_Lock);
2259 /* cannot free this vector -- tasks might still call LockDevice */
2260 //psdFreeVec(pd);
2262 KPRINTF(3, ("FreeDevice done\n"));
2264 /* \\\ */
2266 /* /// "psdFreeDevice()" */
2267 AROS_LH1(void, psdFreeDevice,
2268 AROS_LHA(struct PsdDevice *, pd, A0),
2269 LIBBASETYPEPTR, ps, 16, psd)
2271 AROS_LIBFUNC_INIT
2272 struct PsdHardware *phw = pd->pd_Hardware;
2273 struct PsdConfig *pc;
2274 struct PsdInterface *pif;
2275 struct PsdRTIsoHandler *prt;
2276 struct PsdRTIsoHandler *nextprt;
2278 KPRINTF(3, (" FreeDevice(%p)\n", pd));
2280 /* move device to list of dead devices first
2281 This caused a lot of trouble as it could
2282 happen that a device got into class scan
2283 right after the bindings had been released. */
2284 psdLockWritePBase();
2285 Remove(&pd->pd_Node);
2286 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2287 pd->pd_Flags &= ~PDFF_DELEXPUNGE;
2288 psdUnlockPBase();
2290 psdLockWriteDevice(pd);
2292 /* Inform all ISO handlers about the device going offline */
2293 prt = (struct PsdRTIsoHandler *) pd->pd_RTIsoHandlers.lh_Head;
2294 while((nextprt = (struct PsdRTIsoHandler *) prt->prt_Node.ln_Succ))
2296 if(prt->prt_ReleaseHook)
2298 CallHookPkt(prt->prt_ReleaseHook, prt, NULL);
2300 prt = nextprt;
2303 /* If there are bindings, get rid of them. */
2304 psdHubReleaseDevBinding(pd);
2306 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2307 while(pc->pc_Node.ln_Succ)
2309 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2310 while(pif->pif_Node.ln_Succ)
2312 psdHubReleaseIfBinding(pif);
2313 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2315 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2317 psdUnlockDevice(pd);
2319 pFreeDevice(ps, pd);
2320 AROS_LIBFUNC_EXIT
2322 /* \\\ */
2324 /* /// "psdAllocDevice()" */
2325 AROS_LH1(struct PsdDevice *, psdAllocDevice,
2326 AROS_LHA(struct PsdHardware *, phw, A0),
2327 LIBBASETYPEPTR, ps, 15, psd)
2329 AROS_LIBFUNC_INIT
2330 struct PsdDevice *pd;
2331 KPRINTF(2, ("psdAllocDevice(%p)\n", phw));
2332 if((pd = psdAllocVec(sizeof(struct PsdDevice))))
2334 pd->pd_Hardware = phw;
2335 pd->pd_Hub = NULL;
2336 pd->pd_MaxPktSize0 = 8;
2338 pInitSem(ps, &pd->pd_Lock, "Device");
2340 NewList(&pd->pd_Configs);
2341 NewList(&pd->pd_Descriptors);
2342 NewList(&pd->pd_RTIsoHandlers);
2344 // init prefs
2345 pd->pd_PoPoCfg.poc_ChunkID = AROS_LONG2BE(IFFCHNK_POPUP);
2346 pd->pd_PoPoCfg.poc_Length = AROS_LONG2BE(sizeof(struct PsdPoPoCfg) - 8);
2347 pd->pd_PoPoCfg.poc_InhibitPopup = FALSE;
2348 pd->pd_PoPoCfg.poc_NoClassBind = FALSE;
2349 pd->pd_PoPoCfg.poc_OverridePowerInfo = POCP_TRUST_DEVICE;
2351 psdLockWritePBase();
2352 AddTail(&phw->phw_Devices, &pd->pd_Node);
2353 psdUnlockPBase();
2354 return(pd);
2355 } else {
2356 KPRINTF(20, ("psdAllocDevice(): out of memory!\n"));
2358 return(NULL);
2359 AROS_LIBFUNC_EXIT
2361 /* \\\ */
2363 /* /// "psdLockReadDevice()" */
2364 AROS_LH1(void, psdLockReadDevice,
2365 AROS_LHA(struct PsdDevice *, pd, A0),
2366 LIBBASETYPEPTR, ps, 17, psd)
2368 AROS_LIBFUNC_INIT
2369 KPRINTF(2, ("psdLockReadDevice(%p, %p)\n", pd, FindTask(NULL)));
2370 pLockSemShared(ps, &pd->pd_Lock);
2371 AROS_LIBFUNC_EXIT
2373 /* \\\ */
2375 /* /// "psdLockWriteDevice()" */
2376 AROS_LH1(void, psdLockWriteDevice,
2377 AROS_LHA(struct PsdDevice *, pd, A0),
2378 LIBBASETYPEPTR, ps, 18, psd)
2380 AROS_LIBFUNC_INIT
2381 KPRINTF(2, ("psdLockWriteDevice(%p, %p)\n", pd, FindTask(NULL)));
2382 pLockSemExcl(ps, &pd->pd_Lock);
2383 AROS_LIBFUNC_EXIT
2385 /* \\\ */
2387 /* /// "psdUnlockDevice()" */
2388 AROS_LH1(void, psdUnlockDevice,
2389 AROS_LHA(struct PsdDevice *, pd, A0),
2390 LIBBASETYPEPTR, ps, 19, psd)
2392 AROS_LIBFUNC_INIT
2393 KPRINTF(2, ("psdUnlockDevice(%p, %p)\n", pd, FindTask(NULL)));
2394 pUnlockSem(ps, &pd->pd_Lock);
2395 AROS_LIBFUNC_EXIT
2397 /* \\\ */
2399 /* /// "pAllocDevAddr()" */
2400 UWORD pAllocDevAddr(struct PsdDevice *pd)
2402 struct PsdHardware *phw = pd->pd_Hardware;
2403 UWORD da;
2404 if(pd->pd_DevAddr)
2406 return(pd->pd_DevAddr);
2408 for(da = 1; da < 128; da++)
2410 if(!phw->phw_DevArray[da])
2412 phw->phw_DevArray[da] = pd;
2413 pd->pd_DevAddr = da;
2414 return(da);
2417 return(0);
2419 /* \\\ */
2421 /* /// "psdGetStringDescriptor()" */
2422 AROS_LH2(STRPTR, psdGetStringDescriptor,
2423 AROS_LHA(struct PsdPipe *, pp, A1),
2424 AROS_LHA(UWORD, idx, D0),
2425 LIBBASETYPEPTR, ps, 33, psd)
2427 AROS_LIBFUNC_INIT
2428 struct PsdDevice *pd = pp->pp_Device;
2429 ULONG len;
2430 UBYTE buf[256];
2431 UWORD *tmpptr;
2432 UWORD *tmpbuf;
2433 STRPTR rs;
2434 STRPTR cbuf;
2435 LONG ioerr;
2436 UWORD widechar;
2437 KPRINTF(1, ("psdGetStringDescriptor(%p, %ld)\n", pp, idx));
2439 buf[0] = 0;
2440 if(!pd->pd_LangIDArray)
2442 KPRINTF(10,("Trying to get language array...\n"));
2443 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2444 USR_GET_DESCRIPTOR, UDT_STRING<<8, 0);
2445 ioerr = psdDoPipe(pp, buf, 2);
2446 if(ioerr == UHIOERR_OVERFLOW)
2448 ioerr = 0;
2449 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Language array overflow.");
2451 if(ioerr)
2453 ioerr = psdDoPipe(pp, buf, 256);
2454 if(ioerr == UHIOERR_RUNTPACKET)
2456 ioerr = 0;
2459 if(!ioerr)
2461 len = buf[0];
2462 if((pd->pd_LangIDArray = psdAllocVec(max(len, 4))))
2464 tmpbuf = tmpptr = pd->pd_LangIDArray;
2465 KPRINTF(1, ("Getting LangID Array length %ld\n", len));
2466 // generate minimal sized array
2467 if(len < 4)
2469 len = 4;
2470 *tmpbuf++ = 0;
2471 *tmpbuf = AROS_WORD2LE(0x0409);
2472 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2473 "Language array descriptor too small (len %ld), using dummy.",
2474 len);*/
2475 ioerr = 0;
2476 } else {
2477 ioerr = psdDoPipe(pp, tmpbuf++, len);
2479 if(!ioerr)
2481 len >>= 1;
2482 while(--len)
2484 KPRINTF(1, ("LangID: %04lx\n", AROS_WORD2LE(*tmpbuf)));
2485 *tmpptr++ = AROS_WORD2LE(*tmpbuf);
2486 tmpbuf++;
2488 *tmpptr = 0;
2489 tmpptr = pd->pd_LangIDArray;
2490 pd->pd_CurrLangID = *tmpptr;
2491 while(*tmpptr)
2493 if(*tmpptr == 0x0409)
2495 pd->pd_CurrLangID = *tmpptr;
2496 break;
2498 tmpptr++;
2500 } else {
2501 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2502 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2503 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2504 KPRINTF(15, ("Error reading lang array descriptor (%ld) failed %ld\n", len, ioerr));
2505 *tmpptr = 0;
2507 } else {
2508 KPRINTF(20, ("No langid array memory!\n"));
2510 } else {
2511 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2512 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2513 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2514 KPRINTF(15, ("Error reading lang array descriptor (2) failed %ld\n", ioerr));
2515 /* Create empty array */
2516 if((pd->pd_LangIDArray = psdAllocVec(2)))
2518 *pd->pd_LangIDArray = 0;
2522 buf[0] = 0;
2523 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2524 USR_GET_DESCRIPTOR, (UDT_STRING<<8)|idx, pd->pd_CurrLangID);
2525 ioerr = psdDoPipe(pp, buf, 2);
2526 if(ioerr == UHIOERR_OVERFLOW)
2528 ioerr = 0;
2529 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "String %ld overflow.", idx);
2531 if(ioerr)
2533 ioerr = psdDoPipe(pp, buf, 256);
2535 if(!ioerr)
2537 len = buf[0];
2538 if(len > 2)
2540 tmpptr = (UWORD *) buf;
2541 KPRINTF(1, ("Getting String Descriptor %ld, length %ld\n", idx, len));
2542 ioerr = psdDoPipe(pp, tmpptr++, len);
2543 if(ioerr == UHIOERR_RUNTPACKET)
2545 len = pp->pp_IOReq.iouh_Actual;
2546 if(len > 3)
2548 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2549 "String descriptor %ld truncated to %ld, requested %ld",
2550 idx, len, buf[0]);
2551 ioerr = 0;
2554 else if(ioerr)
2556 ioerr = psdDoPipe(pp, buf, 256);
2558 if(!ioerr)
2560 if((cbuf = rs = psdAllocVec(len>>1)))
2562 len >>= 1;
2563 while(--len)
2565 widechar = *tmpptr++;
2566 widechar = AROS_LE2WORD(widechar);
2567 if(widechar == 0)
2569 break;
2571 if((widechar < 0x20) || (widechar > 255))
2573 *cbuf++ = '?';
2574 } else {
2575 *cbuf++ = widechar;
2578 *cbuf = 0;
2579 KPRINTF(1, ("String \"%s\"\n", rs));
2580 if(*rs)
2582 return(rs);
2583 } else {
2584 psdFreeVec(rs);
2585 return(NULL);
2587 } else {
2588 KPRINTF(20, ("No memory for string!\n"));
2590 } else {
2591 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2592 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2593 idx, len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2594 KPRINTF(15, ("Error reading string descriptor %ld (%ld) failed %ld\n",
2595 idx, len, ioerr));
2597 } else {
2598 KPRINTF(5, ("Empty string\n"));
2599 return(psdCopyStr(""));
2601 } else {
2602 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2603 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2604 idx, 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2605 KPRINTF(15, ("Error reading string descriptor %ld (2) failed %ld\n", idx, ioerr));
2607 return(NULL);
2608 AROS_LIBFUNC_EXIT
2610 /* \\\ */
2612 /* /// "psdSetDeviceConfig()" */
2613 AROS_LH2(BOOL, psdSetDeviceConfig,
2614 AROS_LHA(struct PsdPipe *, pp, A1),
2615 AROS_LHA(UWORD, cfgnum, D0),
2616 LIBBASETYPEPTR, ps, 34, psd)
2618 AROS_LIBFUNC_INIT
2619 struct PsdConfig *pc;
2620 struct PsdDevice *pd = pp->pp_Device;
2621 //UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2622 LONG ioerr;
2623 BOOL res = FALSE;
2625 KPRINTF(2, ("Setting configuration to %ld...\n", cfgnum));
2626 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2627 USR_SET_CONFIGURATION, cfgnum, 0);
2628 ioerr = psdDoPipe(pp, NULL, 0);
2629 if(!ioerr)
2631 #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
2632 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2633 USR_GET_CONFIGURATION, 0, 0);
2634 ioerr = psdDoPipe(pp, buf, 1);
2635 if(!ioerr)
2637 pd->pd_CurrCfg = buf[0];
2638 if(cfgnum != buf[0])
2640 pd->pd_CurrCfg = cfgnum;
2641 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2642 "Broken: SetConfig/GetConfig mismatch (%ld != %ld) for %s!",
2643 cfgnum, buf[0], pp->pp_Device->pd_ProductStr);
2645 res = TRUE;
2646 } else {
2647 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2648 "GET_CONFIGURATION failed: %s (%ld)",
2649 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2650 pd->pd_CurrCfg = cfgnum;
2651 KPRINTF(15, ("GET_CONFIGURATION failed %ld!\n", ioerr));
2653 #else
2654 pd->pd_CurrCfg = cfgnum;
2655 res = TRUE;
2656 #endif
2657 } else {
2658 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2659 "SET_CONFIGURATION failed: %s (%ld)",
2660 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2661 KPRINTF(15, ("SET_CONFIGURATION failed %ld!\n", ioerr));
2663 // update direct link
2664 Forbid();
2665 pd->pd_CurrentConfig = NULL;
2666 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2667 while(pc->pc_Node.ln_Succ)
2669 if(pc->pc_CfgNum == pd->pd_CurrCfg)
2671 pd->pd_CurrentConfig = pc;
2672 break;
2674 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2676 Permit();
2677 if(!pd->pd_CurrentConfig)
2679 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "No current configuration, huh?");
2680 } else {
2681 UWORD status = 0;
2682 // power saving stuff
2683 if(ps->ps_GlobalCfg->pgc_PowerSaving && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
2685 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2686 USR_SET_FEATURE, UFS_DEVICE_REMOTE_WAKEUP, 0);
2687 ioerr = psdDoPipe(pp, NULL, 0);
2688 if(ioerr)
2690 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2691 "SET_DEVICE_REMOTE_WAKEUP failed: %s (%ld)",
2692 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2693 KPRINTF(15, ("SET_DEVICE_REMOTE_WAKEUP failed %ld!\n", ioerr));
2695 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2696 ioerr = psdDoPipe(pp, &status, 2);
2697 if(!ioerr)
2699 if(status & U_GSF_REMOTE_WAKEUP)
2701 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2702 "Enabled remote wakeup feature for '%s'.",
2703 pd->pd_ProductStr);
2704 } else {
2705 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_REMOTE_WAKEUP;
2706 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2707 "Remote wakeup feature for '%s' could not be enabled.",
2708 pd->pd_ProductStr);
2710 } else {
2711 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2712 "GET_STATUS failed: %s (%ld)",
2713 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2714 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2716 } else {
2717 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2718 ioerr = psdDoPipe(pp, &status, 2);
2720 if(!ioerr)
2722 if((status & U_GSF_SELF_POWERED) && (!(pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED)))
2724 pd->pd_CurrentConfig->pc_Attr |= USCAF_SELF_POWERED;
2725 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2726 "Device '%s' says it is currently self-powered. Fixing config.",
2727 pd->pd_ProductStr);
2729 else if((!(status & U_GSF_SELF_POWERED)) && (pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED))
2731 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_SELF_POWERED;
2732 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2733 "Device '%s' says it is currently bus-powered. Fixing config.",
2734 pd->pd_ProductStr);
2736 } else {
2737 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2738 "GET_STATUS failed: %s (%ld)",
2739 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2740 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2744 return(res);
2745 AROS_LIBFUNC_EXIT
2747 /* \\\ */
2749 /* /// "psdSetAltInterface()" */
2750 AROS_LH2(BOOL, psdSetAltInterface,
2751 AROS_LHA(struct PsdPipe *, pp, A1),
2752 AROS_LHA(struct PsdInterface *, pif, A0),
2753 LIBBASETYPEPTR, ps, 43, psd)
2755 AROS_LIBFUNC_INIT
2756 struct PsdConfig *pc = pif->pif_Config;
2757 struct PsdInterface *curif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2758 struct PsdInterface *tmpif;
2759 struct PsdDevice *pd = pc->pc_Device;
2760 UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2761 LONG ioerr;
2762 UWORD ifnum = pif->pif_IfNum;
2763 UWORD altnum = pif->pif_Alternate;
2765 KPRINTF(2, ("Setting interface %ld to alt %ld...\n", ifnum, altnum));
2766 psdLockWriteDevice(pd);
2768 /* Find root config structure */
2769 while(curif->pif_Node.ln_Succ)
2771 if(curif->pif_IfNum == ifnum)
2773 break;
2775 curif = (struct PsdInterface *) curif->pif_Node.ln_Succ;
2777 if(!curif->pif_Node.ln_Succ)
2779 KPRINTF(20, ("Where did you get that fucking interface from?!?"));
2780 psdUnlockDevice(pd);
2781 return(FALSE);
2783 if(curif == pif) /* Is already the current alternate setting */
2785 psdUnlockDevice(pd);
2786 return(TRUE);
2788 KPRINTF(1, ("really setting interface...\n"));
2789 if(pp)
2791 psdPipeSetup(pp, URTF_STANDARD|URTF_INTERFACE,
2792 USR_SET_INTERFACE, altnum, ifnum);
2793 ioerr = psdDoPipe(pp, NULL, 0);
2794 } else {
2795 ioerr = 0;
2797 if((!ioerr) || (ioerr == UHIOERR_STALL))
2799 if(pp)
2801 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_INTERFACE,
2802 USR_GET_INTERFACE, 0, ifnum);
2803 ioerr = psdDoPipe(pp, buf, 1);
2804 } else {
2805 buf[0] = altnum;
2807 if(!ioerr)
2809 if(altnum == buf[0])
2811 KPRINTF(1, ("resorting list..."));
2812 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2813 "Changed to alt %ld",
2814 altnum);*/
2815 Forbid();
2816 /* Remove pif from alt list */
2817 Remove(&pif->pif_Node);
2818 pif->pif_ParentIf = NULL;
2819 /* Now move bindings */
2820 pif->pif_ClsBinding = curif->pif_ClsBinding;
2821 pif->pif_IfBinding = curif->pif_IfBinding;
2822 curif->pif_IfBinding = NULL;
2823 curif->pif_ClsBinding = NULL;
2824 /* Insert it after root interface */
2825 Insert(&pc->pc_Interfaces, (struct Node *) &pif->pif_Node, (struct Node *) &curif->pif_Node);
2826 /* Unlink root interface */
2827 Remove(&curif->pif_Node);
2828 /* Now move all remaining alt interfaces to the new root interface */
2829 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2830 while(tmpif->pif_Node.ln_Succ)
2832 Remove(&tmpif->pif_Node);
2833 AddTail(&pif->pif_AlterIfs, &tmpif->pif_Node);
2834 tmpif->pif_ParentIf = pif;
2835 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2837 /* Add old root to the end of the alt list */
2838 AddTail(&pif->pif_AlterIfs, &curif->pif_Node);
2839 curif->pif_ParentIf = pif;
2840 Permit();
2841 psdUnlockDevice(pd);
2842 return(TRUE);
2843 } else {
2844 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2845 "Attempt to change interface %ld to alt %ld remained at alt %ld.",
2846 ifnum, altnum, buf[0]);
2848 } else {
2849 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2850 "GET_INTERFACE(%ld) failed: %s (%ld)",
2851 ifnum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2852 KPRINTF(15, ("GET_INTERFACE failed %ld!\n", ioerr));
2854 } else {
2855 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2856 "SET_INTERFACE(%ld)=%ld failed: %s (%ld)",
2857 ifnum, altnum,
2858 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2859 KPRINTF(15, ("SET_INTERFACE failed %ld!\n", ioerr));
2861 psdUnlockDevice(pd);
2862 return(FALSE);
2863 AROS_LIBFUNC_EXIT
2865 /* \\\ */
2867 /* /// "psdEnumerateDevice()" */
2868 AROS_LH1(struct PsdDevice *, psdEnumerateDevice,
2869 AROS_LHA(struct PsdPipe *, pp, A1),
2870 LIBBASETYPEPTR, ps, 20, psd)
2872 AROS_LIBFUNC_INIT
2874 struct PsdDevice *pd = pp->pp_Device;
2875 struct PsdDevice *itpd = pp->pp_Device;
2876 struct PsdConfig *pc;
2877 struct PsdInterface *pif;
2878 struct UsbStdDevDesc usdd;
2880 UWORD oldflags;
2881 ULONG oldnaktimeout;
2883 LONG ioerr;
2885 STRPTR classname;
2886 STRPTR vendorname;
2888 ULONG devclass;
2890 IPTR islowspeed;
2892 BOOL hasprodname;
2893 BOOL haspopupinhibit;
2895 UWORD cfgnum;
2897 struct PsdIFFContext *pic;
2899 ULONG *chnk;
2901 #ifdef AROS_USB30_CODE
2902 struct UsbStdBOSDesc usbosd;
2903 LONG ioerr_bos;
2904 #endif
2906 KPRINTF(2, ("psdEnumerateDevice(%p)\n", pp));
2908 psdLockWriteDevice(pd);
2909 if(pAllocDevAddr(pd)) {
2911 oldflags = pp->pp_IOReq.iouh_Flags;
2912 oldnaktimeout = pp->pp_IOReq.iouh_NakTimeout;
2913 pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
2914 pp->pp_IOReq.iouh_NakTimeout = 1000;
2915 pp->pp_IOReq.iouh_DevAddr = 0;
2918 64 bytes is the maximum packet size for control transfers in fullspeed and highspeed devices
2920 psdGetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, &islowspeed, TAG_END);
2921 if(islowspeed)
2923 pp->pp_IOReq.iouh_MaxPktSize = 8;
2924 } else {
2925 pp->pp_IOReq.iouh_MaxPktSize = 64;
2928 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2929 ioerr = psdDoPipe(pp, &usdd, 8);
2930 if(ioerr && (ioerr != UHIOERR_RUNTPACKET)) {
2931 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "GET_DESCRIPTOR (8) failed: %s (%ld)", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2932 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
2935 KPRINTF(1, ("Setting DevAddr %ld...\n", pd->pd_DevAddr));
2936 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, USR_SET_ADDRESS, pd->pd_DevAddr, 0);
2937 ioerr = psdDoPipe(pp, NULL, 0);
2939 This is tricky: Maybe the device has accepted the command,
2940 but failed to send an ACK. Now, every resend trial will
2941 go to the wrong address!
2943 if((ioerr == UHIOERR_TIMEOUT) || (ioerr == UHIOERR_STALL)) {
2944 KPRINTF(1, ("First attempt failed, retrying new address\n"));
2945 /*pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;*/
2946 psdDelayMS(250);
2947 ioerr = psdDoPipe(pp, NULL, 0);
2948 /*pp->pp_IOReq.iouh_DevAddr = 0;*/
2951 if(!ioerr) {
2952 pd->pd_Flags |= PDFF_HASDEVADDR|PDFF_CONNECTED;
2953 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
2955 psdDelayMS(50); /* Allowed time to settle */
2958 We have already received atleast the first 8 bytes from the descriptor, asking again may confuse some devices
2959 This is somewhat similar to how Windows enumerates USB devices
2961 KPRINTF(1, ("Getting MaxPktSize0...\n"));
2962 switch(usdd.bMaxPacketSize0)
2964 case 8:
2965 case 16:
2966 case 32:
2967 case 64:
2968 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = usdd.bMaxPacketSize0;
2969 break;
2970 #ifdef AROS_USB30_CODE
2971 case 9:
2972 if((AROS_LE2WORD(usdd.bcdUSB) >= 0x0300)) {
2973 /* 9 is the only valid value for superspeed mode and it is the exponent of 2 =512 bytes */
2974 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = (1<<9);
2975 break;
2977 #endif
2978 default:
2979 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Illegal MaxPktSize0=%ld for endpoint 0", (ULONG) usdd.bMaxPacketSize0);
2980 KPRINTF(2, ("Illegal MaxPktSize0=%ld!\n", usdd.bMaxPacketSize0));
2981 //pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = 8;
2982 ioerr = UHIOERR_CRCERROR;
2983 break;
2986 KPRINTF(1, (" MaxPktSize0 = %ld\n", pd->pd_MaxPktSize0));
2988 KPRINTF(1, ("Getting full descriptor...\n"));
2990 We have set a new address for the device so we need to setup the pipe again
2992 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2993 ioerr = psdDoPipe(pp, &usdd, sizeof(struct UsbStdDevDesc));
2994 if(!ioerr)
2996 pAllocDescriptor(pd, (UBYTE *) &usdd);
2997 pd->pd_Flags |= PDFF_HASDEVDESC;
2998 pd->pd_USBVers = AROS_WORD2LE(usdd.bcdUSB);
2999 pd->pd_DevClass = usdd.bDeviceClass;
3000 pd->pd_DevSubClass = usdd.bDeviceSubClass;
3001 pd->pd_DevProto = usdd.bDeviceProtocol;
3002 pd->pd_VendorID = AROS_WORD2LE(usdd.idVendor);
3003 pd->pd_ProductID = AROS_WORD2LE(usdd.idProduct);
3004 pd->pd_DevVers = AROS_WORD2LE(usdd.bcdDevice);
3005 vendorname = psdNumToStr(NTS_VENDORID, (LONG) pd->pd_VendorID, NULL);
3007 // patch to early determine highspeed roothubs
3008 if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x200) && (pd->pd_USBVers < 0x300)) {
3009 pd->pd_Flags |= PDFF_HIGHSPEED;
3012 #ifdef AROS_USB30_CODE
3013 if(((!pd->pd_Hub) && pd->pd_USBVers >= 0x300)) {
3014 pd->pd_Flags |= PDFF_SUPERSPEED;
3018 The USB 3.0 and USB 2.0 LPM specifications define a new USB descriptor called the Binary Device Object Store (BOS)
3019 for a USB device, which reports a bcdUSB value greater than 0x0200 in their device descriptor
3021 if((pd->pd_USBVers > 0x200)) {
3022 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_BOS<<8, 0);
3023 ioerr_bos = psdDoPipe(pp, &usbosd, sizeof(struct UsbStdBOSDesc));
3024 if(!ioerr_bos) {
3025 XPRINTF(1, ("BOS descriptor received...\n"));
3028 BOS descriptor bLength = sizeof(struct UsbStdBOSDesc)
3029 BOS descriptor bNumDeviceCaps != 0
3030 BOS descriptor wTotalLength >= bLength + (bNumDeviceCaps * sizeof(protocol specific capability descriptor))
3032 if(usbosd.bLength != sizeof(struct UsbStdBOSDesc)) {
3033 XPRINTF(1, ("Invalid BOS descriptor bLength!\n"));
3036 if(usbosd.bNumDeviceCaps == 0) {
3037 XPRINTF(1, ("Invalid BOS descriptor bNumDeviceCaps!\n"));
3038 }else if(usbosd.wTotalLength < (usbosd.bLength + (usbosd.bNumDeviceCaps * 2))) {
3039 XPRINTF(1, ("Invalid BOS descriptor wTotalLength!\n"));
3042 } else {
3043 XPRINTF(1, ("GET_DESCRIPTOR (5) failed %ld!\n", ioerr_bos));
3046 #endif
3048 if(usdd.iManufacturer) {
3049 pd->pd_MnfctrStr = psdGetStringDescriptor(pp, usdd.iManufacturer);
3052 if(usdd.iProduct) {
3053 pd->pd_ProductStr = psdGetStringDescriptor(pp, usdd.iProduct);
3056 if(usdd.iSerialNumber) {
3057 pd->pd_SerNumStr = psdGetStringDescriptor(pp, usdd.iSerialNumber);
3060 if(!pd->pd_MnfctrStr) {
3061 pd->pd_MnfctrStr = psdCopyStr(vendorname ? vendorname : (STRPTR) "n/a");
3064 if(!pd->pd_ProductStr) {
3065 hasprodname = FALSE;
3066 classname = psdNumToStr(NTS_CLASSCODE, (LONG) pd->pd_DevClass, NULL);
3067 if(classname) {
3068 pd->pd_ProductStr = psdCopyStrFmt("%s: Vdr=%04lx/PID=%04lx", classname, pd->pd_VendorID, pd->pd_ProductID);
3069 } else {
3070 pd->pd_ProductStr = psdCopyStrFmt("Cls=%ld/Vdr=%04lx/PID=%04lx", pd->pd_DevClass, pd->pd_VendorID, pd->pd_ProductID);
3072 } else {
3073 hasprodname = TRUE;
3076 if(!pd->pd_SerNumStr) {
3077 pd->pd_SerNumStr = psdCopyStr("n/a");
3080 KPRINTF(2, ("Product : %s\n"
3081 "Manufacturer: %s\n"
3082 "SerialNumber: %s\n",
3083 pd->pd_ProductStr, pd->pd_MnfctrStr, pd->pd_SerNumStr));
3084 KPRINTF(2, ("USBVersion: %04lx\n"
3085 "Class : %ld\n"
3086 "SubClass : %ld\n"
3087 "DevProto : %ld\n"
3088 "VendorID : %ld\n"
3089 "ProductID : %ld\n"
3090 "DevVers : %04lx\n",
3091 pd->pd_USBVers, pd->pd_DevClass, pd->pd_DevSubClass, pd->pd_DevProto,
3092 pd->pd_VendorID, pd->pd_ProductID, pd->pd_DevVers));
3094 /* check for clones */
3095 itpd = NULL;
3096 while((itpd = psdGetNextDevice(itpd)))
3098 if(itpd != pd)
3100 if((itpd->pd_ProductID == pd->pd_ProductID) &&
3101 (itpd->pd_VendorID == pd->pd_VendorID) &&
3102 (!strcmp(itpd->pd_SerNumStr, pd->pd_SerNumStr)) &&
3103 (itpd->pd_CloneCount == pd->pd_CloneCount))
3105 pd->pd_CloneCount++;
3106 itpd = NULL;
3111 pd->pd_IDString = psdCopyStrFmt("%s-%04lx-%04lx-%s-%02lx", pd->pd_ProductStr, pd->pd_VendorID, pd->pd_ProductID, pd->pd_SerNumStr, pd->pd_CloneCount);
3113 pStripString(ps, pd->pd_MnfctrStr);
3114 pStripString(ps, pd->pd_ProductStr);
3115 pStripString(ps, pd->pd_SerNumStr);
3117 /* get custom name of device */
3118 pLockSemExcl(ps, &ps->ps_ConfigLock); // Exclusive lock to avoid deadlock situation when promoting read to write
3119 pd->pd_OldProductStr = pd->pd_ProductStr;
3120 pd->pd_ProductStr = NULL;
3121 haspopupinhibit = FALSE;
3122 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
3123 if(pic)
3125 pd->pd_IsNewToMe = FALSE;
3126 if((pd->pd_ProductStr = pGetStringChunk(ps, pic, IFFCHNK_NAME)))
3128 hasprodname = TRUE;
3130 if((chnk = pFindCfgChunk(ps, pic, IFFCHNK_POPUP)))
3132 struct PsdPoPoCfg *poc = (struct PsdPoPoCfg *) chnk;
3133 CopyMem(((UBYTE *) poc) + 8, ((UBYTE *) &pd->pd_PoPoCfg) + 8, min(AROS_LONG2BE(poc->poc_Length), AROS_LONG2BE(pd->pd_PoPoCfg.poc_Length)));
3134 haspopupinhibit = TRUE;
3136 } else {
3137 pd->pd_IsNewToMe = TRUE;
3138 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
3140 if(!pd->pd_ProductStr)
3142 pd->pd_ProductStr = psdCopyStr(pd->pd_OldProductStr);
3144 if(!haspopupinhibit)
3146 if(pd->pd_DevClass == HUB_CLASSCODE) // hubs default to true
3148 pd->pd_PoPoCfg.poc_InhibitPopup = TRUE;
3151 pUnlockSem(ps, &ps->ps_ConfigLock);
3153 pd->pd_NumCfgs = usdd.bNumConfigurations;
3154 KPRINTF(10, ("Device has %ld different configurations\n", pd->pd_NumCfgs));
3156 if(pGetDevConfig(pp))
3158 cfgnum = 1;
3159 if(pd->pd_Configs.lh_Head->ln_Succ)
3161 cfgnum = ((struct PsdConfig *) pd->pd_Configs.lh_Head)->pc_CfgNum;
3163 psdSetDeviceConfig(pp, cfgnum); /* *** FIXME *** Workaround for USB2.0 devices */
3165 if(!hasprodname)
3167 devclass = pd->pd_DevClass;
3168 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
3169 while(pc->pc_Node.ln_Succ)
3171 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3172 while(pif->pif_Node.ln_Succ)
3174 if(pif->pif_IfClass)
3176 if(!devclass)
3178 devclass = pif->pif_IfClass;
3179 } else {
3180 if(devclass != pif->pif_IfClass)
3182 devclass = 0;
3183 break;
3187 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3189 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
3191 if(devclass)
3193 classname = psdNumToStr(NTS_CLASSCODE, (LONG) devclass, NULL);
3194 if(classname)
3196 psdFreeVec(pd->pd_ProductStr);
3197 if(vendorname)
3199 pd->pd_ProductStr = psdCopyStrFmt("%s (%s/%04lx)",
3200 classname, vendorname, pd->pd_ProductID);
3201 } else {
3202 pd->pd_ProductStr = psdCopyStrFmt("%s (%04lx/%04lx)",
3203 classname, pd->pd_VendorID, pd->pd_ProductID);
3208 pFixBrokenConfig(pp);
3209 pp->pp_IOReq.iouh_Flags = oldflags;
3210 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3211 psdUnlockDevice(pd);
3212 psdCalculatePower(pd->pd_Hardware);
3213 return(pd);
3214 } /*else {
3215 KPRINTF(15, ("SetDeviceConfig(1) failed\n"));
3217 } else {
3218 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3219 "Could not acquire device configuration for %s",
3220 pd->pd_ProductStr ? pd->pd_ProductStr : (STRPTR) "new device");
3221 KPRINTF(15, ("GetDevConfig() failed\n"));
3223 /* Although the device failed to configure fully, maybe
3224 some firmware will able to use this device anyway? */
3225 pp->pp_IOReq.iouh_Flags = oldflags;
3226 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3227 psdUnlockDevice(pd);
3228 return(pd);
3229 } else {
3230 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3231 "GET_DESCRIPTOR (len 18) failed: %s (%ld)",
3232 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3233 KPRINTF(15, ("GET_DESCRIPTOR (18) failed %ld!\n", ioerr));
3235 } else {
3236 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
3237 "SET_ADDRESS failed: %s (%ld)",
3238 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3239 KPRINTF(15, ("SET_ADDRESS failed %ld!\n", ioerr));
3241 pp->pp_IOReq.iouh_Flags = oldflags;
3242 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3243 } else {
3244 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "This cannot happen! More than 127 devices on the bus???");
3245 KPRINTF(20, ("out of addresses???\n"));
3248 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Device enumeration failed, sorry.");
3249 psdUnlockDevice(pd);
3250 return(NULL);
3251 AROS_LIBFUNC_EXIT
3253 /* \\\ */
3255 /* /// "psdGetNextDevice()" */
3256 AROS_LH1(struct PsdDevice *, psdGetNextDevice,
3257 AROS_LHA(struct PsdDevice *, pd, A0),
3258 LIBBASETYPEPTR, ps, 21, psd)
3260 AROS_LIBFUNC_INIT
3261 struct PsdHardware *phw;
3263 KPRINTF(1, ("psdGetNextDevice(%p)\n", pd));
3264 if(pd)
3266 /* Is there another device node in the current hardware? */
3267 if(pd->pd_Node.ln_Succ->ln_Succ)
3269 return((struct PsdDevice *) pd->pd_Node.ln_Succ);
3271 /* No, then check if there's another hardware to scan */
3272 phw = (struct PsdHardware *) pd->pd_Hardware->phw_Node.ln_Succ;
3273 } else {
3274 /* No context, start with first hardware */
3275 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3277 while(phw->phw_Node.ln_Succ)
3279 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3280 /* Is this an valid entry, or is the list empty? */
3281 if(pd->pd_Node.ln_Succ)
3283 return(pd);
3285 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3287 /* End of list reached */
3288 return(NULL);
3289 AROS_LIBFUNC_EXIT
3291 /* \\\ */
3293 /* /// "psdSuspendBindings()" */
3294 AROS_LH1(BOOL, psdSuspendBindings,
3295 AROS_LHA(struct PsdDevice *, pd, A0),
3296 LIBBASETYPEPTR, ps, 100, psd)
3298 AROS_LIBFUNC_INIT
3299 struct PsdUsbClass *puc;
3300 struct PsdConfig *pc;
3301 struct PsdInterface *pif;
3302 BOOL res = FALSE;
3303 IPTR suspendable;
3304 BOOL force = FALSE;
3306 KPRINTF(5, ("psdSuspendBindings(%p)\n", pd));
3307 if(pd)
3309 if(ps->ps_GlobalCfg->pgc_ForceSuspend && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
3311 force = TRUE;
3313 // ask existing bindings to go to suspend first -- if they don't support it, break off
3314 if(pd->pd_DevBinding)
3316 if(pd->pd_Flags & PDFF_APPBINDING)
3318 if(!force)
3320 // can't suspend application binding devices
3321 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3322 "Cannot suspend with application binding on '%s'.",
3323 pd->pd_ProductStr);
3324 return FALSE;
3326 psdReleaseDevBinding(pd);
3328 if((puc = pd->pd_ClsBinding))
3330 suspendable = 0;
3331 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3332 if(suspendable)
3334 res = usbDoMethod(UCM_AttemptSuspendDevice, pd->pd_DevBinding);
3335 if(!res)
3337 // didn't want to suspend
3338 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3339 "Class '%s' failed to suspend device '%s'.",
3340 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3341 return FALSE;
3343 } else {
3344 if(pd->pd_IOBusyCount)
3346 if(!force)
3348 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3349 "Class '%s' does not support suspending.",
3350 puc->puc_Node.ln_Name);
3351 return FALSE;
3352 } else {
3353 psdReleaseDevBinding(pd);
3355 } else {
3356 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3357 "Class '%s' does not support suspending, but has no active IO. Suspending anyway.",
3358 puc->puc_Node.ln_Name);
3363 pc = pd->pd_CurrentConfig;
3364 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3365 while(pif->pif_Node.ln_Succ)
3367 if(pif->pif_IfBinding)
3369 if((puc = pif->pif_ClsBinding))
3371 suspendable = 0;
3372 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3373 if(suspendable)
3375 res = usbDoMethod(UCM_AttemptSuspendDevice, pif->pif_IfBinding);
3376 if(!res)
3378 // didn't want to suspend
3379 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3380 "%s failed to suspend device '%s'.",
3381 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3382 return FALSE;
3384 } else {
3385 if(pd->pd_IOBusyCount)
3387 if(!force)
3390 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3391 "%s does not support suspending.",
3392 puc->puc_Node.ln_Name);
3393 return FALSE;
3394 } else {
3395 psdReleaseIfBinding(pif);
3397 } else {
3398 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3399 "%s does not support suspending, but has no active IO. Suspending anyway.",
3400 puc->puc_Node.ln_Name);
3405 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3407 return TRUE;
3409 return FALSE;
3410 AROS_LIBFUNC_EXIT
3412 /* \\\ */
3414 /* /// "psdSuspendDevice()" */
3415 AROS_LH1(BOOL, psdSuspendDevice,
3416 AROS_LHA(struct PsdDevice *, pd, A0),
3417 LIBBASETYPEPTR, ps, 98, psd)
3419 AROS_LIBFUNC_INIT
3420 struct PsdUsbClass *puc;
3421 struct PsdDevice *hubpd;
3422 APTR binding;
3423 BOOL res = FALSE;
3425 KPRINTF(5, ("psdSuspendDevice(%p)\n", pd));
3426 if(pd)
3428 if(pd->pd_Flags & PDFF_SUSPENDED)
3430 return TRUE;
3432 hubpd = pd->pd_Hub;
3433 if(!hubpd) // suspend root hub
3435 // suspend whole USB, using the HCI UHCMD_USBSUSPEND command
3436 // FIXME currently unsupported!
3437 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Suspending of root hub currently not supported.");
3438 return FALSE;
3441 psdLockWriteDevice(pd);
3442 res = psdSuspendBindings(pd);
3443 psdUnlockDevice(pd);
3444 if(res)
3446 psdLockReadDevice(pd);
3447 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3449 res = usbDoMethod(UCM_HubSuspendDevice, binding, pd);
3451 psdUnlockDevice(pd);
3454 if(!res)
3456 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3457 "Suspending of device '%s' failed.",
3458 pd->pd_ProductStr);
3460 return(res);
3461 AROS_LIBFUNC_EXIT
3463 /* \\\ */
3465 /* /// "psdResumeBindings()" */
3466 AROS_LH1(BOOL, psdResumeBindings,
3467 AROS_LHA(struct PsdDevice *, pd, A0),
3468 LIBBASETYPEPTR, ps, 101, psd)
3470 AROS_LIBFUNC_INIT
3471 struct PsdUsbClass *puc;
3472 struct PsdConfig *pc;
3473 struct PsdInterface *pif;
3474 BOOL res = FALSE;
3475 BOOL rescan = FALSE;
3477 KPRINTF(5, ("psdResumeBindings(%p)\n", pd));
3478 if(pd)
3480 // ask existing bindings to resume -- if they don't support it, rebind
3481 if(pd->pd_DevBinding)
3483 if(!(pd->pd_Flags & PDFF_APPBINDING))
3485 if((puc = pd->pd_ClsBinding))
3487 res = usbDoMethod(UCM_AttemptResumeDevice, pd->pd_DevBinding);
3488 if(!res)
3490 // if the device couldn't resume, better get rid of the binding
3491 psdReleaseDevBinding(pd);
3492 rescan = TRUE;
3497 pc = pd->pd_CurrentConfig;
3498 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3499 while(pif->pif_Node.ln_Succ)
3501 if(pif->pif_IfBinding)
3503 if((puc = pif->pif_ClsBinding))
3505 res = usbDoMethod(UCM_AttemptResumeDevice, pif->pif_IfBinding);
3506 if(!res)
3508 // didn't want to suspend
3509 psdReleaseIfBinding(pif);
3510 rescan = TRUE;
3513 break;
3515 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3517 if(rescan)
3519 psdClassScan();
3522 return(TRUE);
3523 AROS_LIBFUNC_EXIT
3525 /* \\\ */
3527 /* /// "psdResumeDevice()" */
3528 AROS_LH1(BOOL, psdResumeDevice,
3529 AROS_LHA(struct PsdDevice *, pd, A0),
3530 LIBBASETYPEPTR, ps, 99, psd)
3532 AROS_LIBFUNC_INIT
3533 struct PsdUsbClass *puc;
3534 struct PsdDevice *hubpd;
3535 APTR binding;
3536 BOOL res = FALSE;
3538 KPRINTF(5, ("psdResumeDevice(%p)\n", pd));
3539 if(pd)
3541 if(!(pd->pd_Flags & PDFF_SUSPENDED))
3543 return(TRUE);
3545 hubpd = pd->pd_Hub;
3546 if(!hubpd) // resume root hub
3548 // resume whole USB, using the HCI UHCMD_USBRESUME command
3549 // FIXME currently unsupported!
3550 return(FALSE);
3552 psdLockWriteDevice(pd);
3553 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3555 res = usbDoMethod(UCM_HubResumeDevice, binding, pd);
3557 psdUnlockDevice(pd);
3559 if(res)
3561 psdResumeBindings(pd);
3565 return(res);
3566 AROS_LIBFUNC_EXIT
3568 /* \\\ */
3570 /* /// "psdFindDeviceA()" */
3571 AROS_LH2(struct PsdDevice *, psdFindDeviceA,
3572 AROS_LHA(struct PsdDevice *, pd, A0),
3573 AROS_LHA(struct TagItem *, tags, A1),
3574 LIBBASETYPEPTR, ps, 44, psd)
3576 AROS_LIBFUNC_INIT
3577 struct TagItem *ti;
3578 BOOL takeit;
3579 KPRINTF(2, ("psdFindDeviceA(%p, %p)\n", pd, tags));
3580 while((pd = psdGetNextDevice(pd)))
3582 takeit = TRUE;
3583 if((ti = FindTagItem(DA_ProductID, tags)))
3585 if(ti->ti_Data != pd->pd_ProductID)
3587 takeit = FALSE;
3590 if((ti = FindTagItem(DA_VendorID, tags)))
3592 if(ti->ti_Data != pd->pd_VendorID)
3594 takeit = FALSE;
3597 if((ti = FindTagItem(DA_Class, tags)))
3599 if(ti->ti_Data != pd->pd_DevClass)
3601 takeit = FALSE;
3604 if((ti = FindTagItem(DA_SubClass, tags)))
3606 if(ti->ti_Data != pd->pd_DevSubClass)
3608 takeit = FALSE;
3611 if((ti = FindTagItem(DA_Protocol, tags)))
3613 if(ti->ti_Data != pd->pd_DevProto)
3615 takeit = FALSE;
3618 if((ti = FindTagItem(DA_Version, tags)))
3620 if(ti->ti_Data != pd->pd_DevVers)
3622 takeit = FALSE;
3625 if((ti = FindTagItem(DA_SerialNumber, tags)))
3627 if(strcmp((STRPTR) ti->ti_Data, pd->pd_SerNumStr))
3629 takeit = FALSE;
3632 if((ti = FindTagItem(DA_ProductName, tags)))
3634 if(strcmp((STRPTR) ti->ti_Data, pd->pd_ProductStr))
3636 takeit = FALSE;
3639 if((ti = FindTagItem(DA_Manufacturer, tags)))
3641 if(strcmp((STRPTR) ti->ti_Data, pd->pd_MnfctrStr))
3643 takeit = FALSE;
3646 if((ti = FindTagItem(DA_IDString, tags)))
3648 if(strcmp((STRPTR) ti->ti_Data, pd->pd_IDString))
3650 takeit = FALSE;
3653 if((ti = FindTagItem(DA_Binding, tags)))
3655 if(ti->ti_Data != (IPTR) pd->pd_DevBinding)
3657 takeit = FALSE;
3660 if((ti = FindTagItem(DA_HubDevice, tags)))
3662 if(ti->ti_Data != (IPTR) pd->pd_Hub)
3664 takeit = FALSE;
3668 if(takeit)
3670 return(pd);
3673 return(NULL);
3674 AROS_LIBFUNC_EXIT
3676 /* \\\ */
3678 /* *** Hardware *** */
3680 /* /// "pFindHardware()" */
3681 struct PsdHardware * pFindHardware(LIBBASETYPEPTR ps, STRPTR name, ULONG unit)
3683 struct PsdHardware *phw;
3684 Forbid();
3685 while(*name)
3687 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3688 while(phw->phw_Node.ln_Succ)
3690 if((phw->phw_Unit == unit) && (!strcmp(phw->phw_DevName, name)))
3692 Permit();
3693 return(phw);
3695 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3699 if((*name == '/') || (*name == ':'))
3701 ++name;
3702 break;
3704 } while(*(++name));
3706 Permit();
3707 return(NULL);
3709 /* \\\ */
3711 /* /// "psdEnumerateHardware()" */
3712 AROS_LH1(struct PsdDevice *, psdEnumerateHardware,
3713 AROS_LHA(struct PsdHardware *, phw, A0),
3714 LIBBASETYPEPTR, ps, 14, psd)
3716 AROS_LIBFUNC_INIT
3717 struct PsdDevice *pd = NULL;
3718 struct PsdPipe *pp;
3719 struct MsgPort *mp;
3720 #ifdef AROS_USB30_CODE
3721 LONG ioerr;
3722 #endif
3723 KPRINTF(2, ("psdEnumerateHardware(%p)\n", phw));
3725 if((mp = CreateMsgPort()))
3727 Forbid();
3728 if((pd = psdAllocDevice(phw)))
3730 Permit();
3731 if((pp = psdAllocPipe(pd, mp, NULL)))
3733 //pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
3734 //pp->pp_IOReq.iouh_NakTimeout = 1000;
3735 pd->pd_Flags |= PDFF_CONNECTED;
3737 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_USBRESET;
3738 #ifdef AROS_USB30_CODE
3739 ioerr = psdDoPipe(pp, NULL, 0);
3740 if(ioerr == UHIOERR_HOSTERROR) {
3741 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "UHCMD_USBRESET reset failed.");
3742 psdFreePipe(pp);
3743 pFreeBindings(ps, pd);
3744 pFreeDevice(ps, pd);
3745 DeleteMsgPort(mp);
3746 return(NULL);
3748 #else
3749 psdDoPipe(pp, NULL, 0);
3750 #endif
3751 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3752 psdDelayMS(100); // wait for root hub to settle
3753 if(psdEnumerateDevice(pp))
3755 KPRINTF(1, ("Enumeration finished!\n"));
3756 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Root hub has been enumerated.");
3757 psdFreePipe(pp);
3758 DeleteMsgPort(mp);
3759 phw->phw_RootDevice = pd;
3760 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
3761 return(pd);
3763 psdFreePipe(pp);
3765 pFreeBindings(ps, pd);
3766 pFreeDevice(ps, pd);
3767 } else {
3768 Permit();
3770 DeleteMsgPort(mp);
3772 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Root hub enumeration failed. Blame your hardware driver programmer.");
3773 return(NULL);
3774 AROS_LIBFUNC_EXIT
3776 /* \\\ */
3778 /* /// "psdRemHardware()" */
3779 AROS_LH1(void, psdRemHardware,
3780 AROS_LHA(struct PsdHardware *, phw, A0),
3781 LIBBASETYPEPTR, ps, 13, psd)
3783 AROS_LIBFUNC_INIT
3784 struct PsdDevice *pd;
3785 ULONG cnt;
3787 KPRINTF(5, ("FreeHardware(%p)\n", phw));
3789 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3790 while(pd->pd_Node.ln_Succ)
3792 pFreeBindings(ps, pd);
3793 pFreeDevice(ps, pd);
3794 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3795 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3797 cnt = 0;
3798 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3799 while(pd->pd_Node.ln_Succ)
3801 if(pd->pd_UseCnt)
3803 KPRINTF(20, ("Can't remove device, usecnt %ld\n", pd->pd_UseCnt));
3804 if(++cnt == 5)
3806 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3807 "Can't remove device '%s', there are still %ld pipes in use...",
3808 pd->pd_ProductStr, pd->pd_UseCnt);
3810 if(++cnt == 30)
3812 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3813 "Okay, going down with device '%s' anyway, maybe the driver crashed?",
3814 pd->pd_ProductStr);
3815 pd->pd_UseCnt = 0;
3816 cnt--;
3817 } else {
3818 psdDelayMS(1000);
3820 } else {
3821 pFreeDevice(ps, pd);
3822 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3824 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3827 Forbid();
3828 /* Note that the subtask unlinks the hardware! */
3829 phw->phw_ReadySignal = SIGB_SINGLE;
3830 phw->phw_ReadySigTask = FindTask(NULL);
3831 if(phw->phw_Task)
3833 Signal(phw->phw_Task, SIGBREAKF_CTRL_C);
3835 Permit();
3836 while(phw->phw_Task)
3838 Wait(1L<<phw->phw_ReadySignal);
3840 //FreeSignal(phw->phw_ReadySignal);
3841 KPRINTF(1, ("FreeHardware(%p) freevec name\n", phw));
3842 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3843 "Removed hardware %s/%ld. Bye bye!",
3844 phw->phw_DevName, phw->phw_Unit);
3845 psdFreeVec(phw->phw_DevName);
3846 psdFreeVec(phw->phw_ProductName);
3847 psdFreeVec(phw->phw_Manufacturer);
3848 psdFreeVec(phw->phw_Description);
3849 psdFreeVec(phw->phw_Copyright);
3850 psdFreeVec(phw);
3851 psdSendEvent(EHMB_REMHARDWARE, phw, NULL);
3852 KPRINTF(1, ("FreeHardware(%p) done\n", phw));
3853 AROS_LIBFUNC_EXIT
3855 /* \\\ */
3857 /* /// "psdAddHardware()" */
3858 AROS_LH2(struct PsdHardware *,psdAddHardware,
3859 AROS_LHA(STRPTR, name, A0),
3860 AROS_LHA(ULONG, unit, D0),
3861 LIBBASETYPEPTR, ps, 12, psd)
3863 AROS_LIBFUNC_INIT
3864 struct PsdHardware *phw;
3865 char buf[64];
3866 struct Task *tmptask;
3867 KPRINTF(5, ("psdAddHardware(%s, %ld)\n", name, unit));
3869 if((phw = psdAllocVec(sizeof(struct PsdHardware))))
3871 NewList(&phw->phw_Devices);
3872 NewList(&phw->phw_DeadDevices);
3873 phw->phw_Unit = unit;
3874 phw->phw_Base = ps;
3875 if((phw->phw_Node.ln_Name = phw->phw_DevName = psdCopyStr(name)))
3877 psdSafeRawDoFmt(buf, 64, "usbhw<%s/%ld>", name, unit);
3878 phw->phw_ReadySignal = SIGB_SINGLE;
3879 phw->phw_ReadySigTask = FindTask(NULL);
3880 SetSignal(0, SIGF_SINGLE); // clear single bit
3881 if((tmptask = psdSpawnSubTask(buf, pDeviceTask, phw)))
3883 psdBorrowLocksWait(tmptask, 1UL<<phw->phw_ReadySignal);
3884 if(phw->phw_Task)
3886 phw->phw_ReadySigTask = NULL;
3887 //FreeSignal(phw->phw_ReadySignal);
3888 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3889 "New hardware %s/%ld added (%s).",
3890 phw->phw_DevName,
3891 phw->phw_Unit,
3892 phw->phw_ProductName);
3893 psdSendEvent(EHMB_ADDHARDWARE, phw, NULL);
3894 return(phw);
3897 phw->phw_ReadySigTask = NULL;
3898 //FreeSignal(phw->phw_ReadySignal);
3899 psdFreeVec(phw->phw_DevName);
3901 psdFreeVec(phw);
3903 return(NULL);
3904 AROS_LIBFUNC_EXIT
3906 /* \\\ */
3908 /* /// "psdCalculatePower()" */
3909 AROS_LH1(void, psdCalculatePower,
3910 AROS_LHA(struct PsdHardware *, phw, A0),
3911 LIBBASETYPEPTR, ps, 78, psd)
3913 AROS_LIBFUNC_INIT
3914 struct PsdDevice *roothub = NULL;
3915 struct PsdDevice *pd;
3917 psdLockReadPBase();
3918 /* goto root */
3919 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3920 while(pd->pd_Node.ln_Succ)
3922 if(!pd->pd_Hub)
3924 roothub = pd;
3925 break;
3927 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
3929 if(!roothub)
3931 psdUnlockPBase();
3932 return;
3934 roothub->pd_PowerDrain = 0;
3935 roothub->pd_PowerSupply = 500;
3937 /* calculate drain */
3938 pPowerRecurseDrain(ps, roothub);
3940 /* calculate supply */
3941 pPowerRecurseSupply(ps, roothub);
3942 psdUnlockPBase();
3943 AROS_LIBFUNC_EXIT
3945 /* \\\ */
3947 /* *** Pipes *** */
3949 /* /// "psdAllocPipe()" */
3950 AROS_LH3(struct PsdPipe *, psdAllocPipe,
3951 AROS_LHA(struct PsdDevice *, pd, A0),
3952 AROS_LHA(struct MsgPort *, mp, A1),
3953 AROS_LHA(struct PsdEndpoint *, pep, A2),
3954 LIBBASETYPEPTR, ps, 24, psd)
3956 AROS_LIBFUNC_INIT
3957 struct PsdPipe *pp;
3958 struct PsdDevice *hubpd;
3960 KPRINTF(2, ("psdAllocPipe(%p, %p, %p)\n", pd, mp, pep));
3961 if(!mp || !pd)
3963 return(NULL);
3965 if(pep && (pep->pep_TransType == USEAF_ISOCHRONOUS) && (!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_ISO)))
3967 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support iso transfers. Sorry.");
3968 return(NULL);
3971 if((pp = psdAllocVec(sizeof(struct PsdPipe))))
3973 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
3974 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = mp;
3975 pp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
3976 pp->pp_Device = pd;
3977 pp->pp_Endpoint = pep;
3978 pp->pp_IOReq = *(pd->pd_Hardware->phw_RootIOReq);
3979 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
3980 if(pd->pd_Flags & PDFF_LOWSPEED)
3982 pp->pp_IOReq.iouh_Flags |= UHFF_LOWSPEED;
3984 if(pd->pd_Flags & PDFF_HIGHSPEED)
3986 pp->pp_IOReq.iouh_Flags |= UHFF_HIGHSPEED;
3987 if(pep)
3989 switch(pep->pep_NumTransMuFr)
3991 case 2:
3992 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_2;
3993 break;
3994 case 3:
3995 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_3;
3996 break;
3998 default:
3999 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
4001 } else {
4002 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
4005 #ifdef AROS_USB30_CODE
4006 if(pd->pd_Flags & PDFF_SUPERSPEED)
4008 pp->pp_IOReq.iouh_Flags |= UHFF_SUPERSPEED;
4010 #endif
4011 if(pd->pd_Flags & PDFF_NEEDSSPLIT)
4013 /* USB1.1 device connected to a USB2.0 hub */
4014 pp->pp_IOReq.iouh_Flags |= UHFF_SPLITTRANS;
4015 hubpd = pd->pd_Hub;
4016 pp->pp_IOReq.iouh_SplitHubPort = pd->pd_HubPort;
4017 // find the root USB 2.0 hub in the tree
4018 while(hubpd && !(hubpd->pd_Flags & PDFF_HIGHSPEED))
4020 pp->pp_IOReq.iouh_SplitHubPort = hubpd->pd_HubPort;
4021 hubpd = hubpd->pd_Hub;
4023 if(!hubpd)
4025 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Internal error obtaining split transaction hub!");
4026 psdFreeVec(pp);
4027 return(NULL);
4029 pp->pp_IOReq.iouh_Flags |= (hubpd->pd_HubThinkTime<<UHFS_THINKTIME);
4030 pp->pp_IOReq.iouh_SplitHubAddr = hubpd->pd_DevAddr;
4032 if(pep)
4034 switch(pep->pep_TransType)
4036 case USEAF_CONTROL:
4037 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4038 break;
4039 case USEAF_ISOCHRONOUS:
4040 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ISOXFER;
4041 break;
4042 case USEAF_BULK:
4043 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_BULKXFER;
4044 break;
4045 case USEAF_INTERRUPT:
4046 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_INTXFER;
4047 break;
4048 default:
4049 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
4050 "AllocPipe(): Illegal transfer type %ld",
4051 pep->pep_TransType);
4052 KPRINTF(20, ("Illegal transfer type for endpoint!"));
4053 psdFreeVec(pp);
4054 return(NULL);
4057 pp->pp_IOReq.iouh_Dir = (pep->pep_Direction ? UHDIR_IN : UHDIR_OUT);
4058 pp->pp_IOReq.iouh_Endpoint = pep->pep_EPNum;
4059 pp->pp_IOReq.iouh_MaxPktSize = pep->pep_MaxPktSize;
4060 pp->pp_IOReq.iouh_Interval = pep->pep_Interval;
4061 } else {
4062 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4063 pp->pp_IOReq.iouh_Dir = UHDIR_SETUP;
4064 pp->pp_IOReq.iouh_Endpoint = 0;
4065 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0;
4067 pd->pd_UseCnt++;
4068 return(pp);
4070 return(NULL);
4071 AROS_LIBFUNC_EXIT
4073 /* \\\ */
4075 /* /// "psdFreePipe()" */
4076 AROS_LH1(void, psdFreePipe,
4077 AROS_LHA(struct PsdPipe *, pp, A1),
4078 LIBBASETYPEPTR, ps, 25, psd)
4080 AROS_LIBFUNC_INIT
4081 struct PsdDevice *pd;
4082 if(!pp)
4084 return;
4086 KPRINTF(2, ("psdFreePipe(%p)\n", pp));
4087 pd = pp->pp_Device;
4089 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4091 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4092 "Tried to free pipe on %s that was still pending!", pd->pd_ProductStr);
4093 psdAbortPipe(pp);
4094 psdWaitPipe(pp);
4097 if(!(--pd->pd_UseCnt) && (pd->pd_Flags & PDFF_DELEXPUNGE))
4099 KPRINTF(20, ("Finally getting rid of device %s\n", pd->pd_ProductStr));
4100 pFreeDevice(ps, pd);
4101 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
4104 psdFreeVec(pp);
4105 AROS_LIBFUNC_EXIT
4107 /* \\\ */
4109 /* /// "psdPipeSetup()" */
4110 AROS_LH5(void, psdPipeSetup,
4111 AROS_LHA(struct PsdPipe *, pp, A1),
4112 AROS_LHA(UWORD, rt, D0),
4113 AROS_LHA(UWORD, rq, D1),
4114 AROS_LHA(UWORD, val, D2),
4115 AROS_LHA(UWORD, idx, D3),
4116 LIBBASETYPEPTR, ps, 26, psd)
4118 AROS_LIBFUNC_INIT
4119 struct UsbSetupData *usd = &pp->pp_IOReq.iouh_SetupData;
4121 KPRINTF(1, ("psdSetupPipe(%p, (%02lx %02lx %04lx %04lx))\n",
4122 pp, rt, rq, val, idx));
4123 usd->bmRequestType = rt;
4124 usd->bRequest = rq;
4125 usd->wValue = AROS_WORD2LE(val);
4126 usd->wIndex = AROS_WORD2LE(idx);
4127 AROS_LIBFUNC_EXIT
4129 /* \\\ */
4131 /* /// "psdDoPipe()" */
4132 AROS_LH3(LONG, psdDoPipe,
4133 AROS_LHA(struct PsdPipe *, pp, A1),
4134 AROS_LHA(APTR, data, A0),
4135 AROS_LHA(ULONG, len, D0),
4136 LIBBASETYPEPTR, ps, 27, psd)
4138 AROS_LIBFUNC_INIT
4139 struct PsdDevice *pd = pp->pp_Device;
4140 KPRINTF(200, ("psdDoPipe(%p, %p, %ld)\n", pp, data, len));
4142 if(pd->pd_Flags & PDFF_CONNECTED)
4144 if(pd->pd_Flags & PDFF_SUSPENDED)
4146 // make sure the device is up and running before trying to send a new pipe
4147 psdResumeDevice(pd);
4150 pp->pp_IOReq.iouh_Data = data;
4151 pp->pp_IOReq.iouh_Length = len;
4152 if(!pp->pp_Endpoint)
4154 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4156 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4157 ++pd->pd_IOBusyCount;
4158 GetSysTime((APTR) &pd->pd_LastActivity);
4159 return(psdWaitPipe(pp));
4160 } else {
4161 psdDelayMS(50);
4162 pp->pp_IOReq.iouh_Actual = 0;
4163 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4164 return(pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT);
4166 AROS_LIBFUNC_EXIT
4168 /* \\\ */
4170 /* /// "psdSendPipe()" */
4171 AROS_LH3(void, psdSendPipe,
4172 AROS_LHA(struct PsdPipe *, pp, A1),
4173 AROS_LHA(APTR, data, A0),
4174 AROS_LHA(ULONG, len, D0),
4175 LIBBASETYPEPTR, ps, 28, psd)
4177 AROS_LIBFUNC_INIT
4178 struct PsdDevice *pd = pp->pp_Device;
4179 KPRINTF(200, ("psdSendPipe(%p, %p, %ld)\n", pp, data, len));
4180 if(pd->pd_Flags & PDFF_CONNECTED)
4182 if(pd->pd_Flags & PDFF_SUSPENDED)
4184 // make sure the device is up and running before trying to send a new pipe
4185 psdResumeDevice(pd);
4188 pp->pp_IOReq.iouh_Data = data;
4189 pp->pp_IOReq.iouh_Length = len;
4190 if(!pp->pp_Endpoint)
4192 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4194 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4195 GetSysTime((APTR) &pd->pd_LastActivity);
4196 ++pd->pd_IOBusyCount;
4197 } else {
4198 psdDelayMS(50);
4199 pp->pp_IOReq.iouh_Actual = 0;
4200 //pp->pp_Msg.mn_Node.ln_Type = NT_REPLYMSG;
4201 pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT;
4202 ReplyMsg(&pp->pp_Msg);
4203 ++pd->pd_IOBusyCount;
4205 AROS_LIBFUNC_EXIT
4207 /* \\\ */
4209 /* /// "psdAbortPipe()" */
4210 AROS_LH1(void, psdAbortPipe,
4211 AROS_LHA(struct PsdPipe *, pp, A1),
4212 LIBBASETYPEPTR, ps, 29, psd)
4214 AROS_LIBFUNC_INIT
4215 struct PsdPipe *npp;
4217 KPRINTF(5, ("psdAbortPipe(%p)\n", pp));
4218 if(pp->pp_Msg.mn_Node.ln_Type != NT_MESSAGE)
4220 KPRINTF(5, ("Nothing to abort %02lx\n", pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type));
4221 return;
4223 if((npp = psdAllocVec(sizeof(struct PsdPipe))))
4225 //npp->pp_Msg.mn_Node.ln_Type = NT_MESSAGE;
4226 npp->pp_Device = pp->pp_Device;
4227 npp->pp_MsgPort = npp->pp_Msg.mn_ReplyPort = pp->pp_MsgPort;
4228 npp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
4230 npp->pp_AbortPipe = pp;
4231 PutMsg(&pp->pp_Device->pd_Hardware->phw_TaskMsgPort, &npp->pp_Msg);
4232 psdWaitPipe(npp);
4233 psdFreeVec(npp);
4235 AROS_LIBFUNC_EXIT
4237 /* \\\ */
4239 /* /// "psdWaitPipe()" */
4240 AROS_LH1(LONG, psdWaitPipe,
4241 AROS_LHA(struct PsdPipe *, pp, A1),
4242 LIBBASETYPEPTR, ps, 30, psd)
4244 AROS_LIBFUNC_INIT
4245 ULONG sigs = 0;
4246 struct PsdDevice *pd = pp->pp_Device;
4247 LONG ioerr;
4248 KPRINTF(5, ("psdWaitPipe(%p)\n", pp));
4249 while(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4251 KPRINTF(5, ("ln_Type = %02lx\n", pp->pp_Msg.mn_Node.ln_Type));
4252 sigs |= Wait(1L<<pp->pp_MsgPort->mp_SigBit);
4253 KPRINTF(5, ("sigs = %p\n", sigs));
4255 #if 1 // broken?
4256 Forbid();
4257 if(pp->pp_Msg.mn_Node.ln_Type == NT_REPLYMSG)
4259 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4260 Remove(&pp->pp_Msg.mn_Node);
4262 //if(pp->pp_MsgPort->mp_MsgList.lh_Head->ln_Succ)
4264 // avoid signals getting lost for other messages arriving.
4265 SetSignal(sigs, sigs);
4267 Permit();
4268 #else
4269 Forbid();
4270 Remove(&pp->pp_Msg.mn_Node);
4271 Permit();
4272 #endif
4273 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4274 switch(ioerr)
4276 case UHIOERR_TIMEOUT:
4277 pd->pd_DeadCount++;
4278 // fall through
4279 case UHIOERR_NAKTIMEOUT:
4280 pd->pd_DeadCount++;
4281 case UHIOERR_CRCERROR:
4282 pd->pd_DeadCount++;
4283 break;
4284 case UHIOERR_RUNTPACKET:
4285 default:
4286 if(pd->pd_DeadCount)
4288 pd->pd_DeadCount >>= 1;
4289 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4290 "Device %s starts recovering with %s (%ld)!",
4291 pd->pd_ProductStr,
4292 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
4295 KPRINTF(200, ("psdWaitPipe(%p)=%ld\n", pp, ioerr));
4296 --pd->pd_IOBusyCount;
4297 GetSysTime((APTR) &pd->pd_LastActivity);
4299 if((pd->pd_DeadCount > 19) || ((pd->pd_DeadCount > 14) && (pd->pd_Flags & (PDFF_HASDEVADDR|PDFF_HASDEVDESC))))
4301 if(!(pd->pd_Flags & PDFF_DEAD))
4303 pd->pd_Flags |= PDFF_DEAD;
4304 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4305 "Device %s probably dropped dead!", pd->pd_ProductStr);
4307 psdSendEvent(EHMB_DEVICEDEAD, pp->pp_Device, NULL);
4309 } else {
4310 if((!pd->pd_DeadCount) && ((pd->pd_Flags & (PDFF_DEAD|PDFF_CONNECTED)) == (PDFF_DEAD|PDFF_CONNECTED)))
4312 pd->pd_Flags &= ~PDFF_DEAD;
4313 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4314 "Uuuhuuuhh, the zombie %s returned from the dead!", pd->pd_ProductStr);
4317 return(ioerr);
4318 AROS_LIBFUNC_EXIT
4320 /* \\\ */
4322 /* /// "psdCheckPipe()" */
4323 AROS_LH1(struct PsdPipe *, psdCheckPipe,
4324 AROS_LHA(struct PsdPipe *, pp, A1),
4325 LIBBASETYPEPTR, ps, 71, psd)
4327 AROS_LIBFUNC_INIT
4328 KPRINTF(5, ("psdCheckPipe(%p)\n", pp));
4329 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4331 return(NULL);
4333 return(pp);
4334 AROS_LIBFUNC_EXIT
4336 /* \\\ */
4338 /* /// "psdGetPipeActual()" */
4339 AROS_LH1(ULONG, psdGetPipeActual,
4340 AROS_LHA(struct PsdPipe *, pp, A1),
4341 LIBBASETYPEPTR, ps, 31, psd)
4343 AROS_LIBFUNC_INIT
4344 KPRINTF(1, ("psdGetPipeActual(%p)\n", pp));
4345 return(pp->pp_IOReq.iouh_Actual);
4346 AROS_LIBFUNC_EXIT
4348 /* \\\ */
4350 /* /// "psdGetPipeError()" */
4351 AROS_LH1(LONG, psdGetPipeError,
4352 AROS_LHA(struct PsdPipe *, pp, A1),
4353 LIBBASETYPEPTR, ps, 32, psd)
4355 AROS_LIBFUNC_INIT
4356 KPRINTF(1, ("psdGetPipeError(%p)\n", pp));
4357 return((LONG) pp->pp_IOReq.iouh_Req.io_Error);
4358 AROS_LIBFUNC_EXIT
4360 /* \\\ */
4362 /* *** Streams *** */
4364 /* /// "psdOpenStreamA()" */
4365 AROS_LH2(struct PsdPipeStream *, psdOpenStreamA,
4366 AROS_LHA(struct PsdEndpoint *, pep, A0),
4367 AROS_LHA(struct TagItem *, tags, A1),
4368 LIBBASETYPEPTR, ps, 72, psd)
4370 AROS_LIBFUNC_INIT
4371 struct PsdPipeStream *pps;
4373 KPRINTF(2, ("psdOpenStream(%p, %p)\n", pep, tags));
4374 if(!pep)
4376 return(NULL);
4378 if((pps = psdAllocVec(sizeof(struct PsdPipeStream))))
4380 pps->pps_Device = pep->pep_Interface->pif_Config->pc_Device;
4381 pps->pps_Endpoint = pep;
4382 NewList(&pps->pps_FreePipes);
4383 NewList(&pps->pps_ReadyPipes);
4384 InitSemaphore(&pps->pps_AccessLock);
4385 pps->pps_NakTimeoutTime = 5000;
4386 if(pep->pep_Direction)
4388 /* Defaults for IN */
4389 pps->pps_NumPipes = 4;
4390 pps->pps_Flags = PSFF_READAHEAD|PSFF_BUFFERREAD|PSFF_ALLOWRUNT;
4391 pps->pps_BufferSize = 32*pps->pps_Endpoint->pep_MaxPktSize;
4392 } else {
4393 /* Defaults for OUT */
4394 pps->pps_NumPipes = 4;
4395 pps->pps_Flags = PSFF_NOSHORTPKT;
4396 pps->pps_BufferSize = 4*pps->pps_Endpoint->pep_MaxPktSize;
4399 psdSetAttrsA(PGA_PIPESTREAM, pps, tags);
4400 if(!pps->pps_Pipes)
4402 psdCloseStream(pps);
4403 pps = NULL;
4405 return(pps);
4407 return(NULL);
4408 AROS_LIBFUNC_EXIT
4410 /* \\\ */
4412 /* /// "psdCloseStream()" */
4413 AROS_LH1(void, psdCloseStream,
4414 AROS_LHA(struct PsdPipeStream *, pps, A1),
4415 LIBBASETYPEPTR, ps, 73, psd)
4417 AROS_LIBFUNC_INIT
4418 struct PsdPipe *pp;
4419 ULONG cnt;
4421 KPRINTF(2, ("psdCloseStream(%p)\n", pps));
4422 if(!pps)
4424 return;
4426 psdStreamFlush(pps);
4427 ObtainSemaphore(&pps->pps_AccessLock);
4428 if(pps->pps_Pipes)
4430 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4432 pp = pps->pps_Pipes[cnt];
4433 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
4435 KPRINTF(1, ("Abort %ld\n", cnt));
4436 psdAbortPipe(pp);
4437 KPRINTF(1, ("Wait %ld\n", cnt));
4438 psdWaitPipe(pp);
4440 KPRINTF(1, ("Free %ld\n", cnt));
4441 psdFreePipe(pp);
4443 psdFreeVec(pps->pps_Pipes);
4444 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
4446 DeleteMsgPort(pps->pps_MsgPort);
4449 psdFreeVec(pps->pps_Buffer);
4450 ReleaseSemaphore(&pps->pps_AccessLock);
4451 psdFreeVec(pps);
4452 AROS_LIBFUNC_EXIT
4454 /* \\\ */
4456 /* /// "psdStreamRead()" */
4457 AROS_LH3(LONG, psdStreamRead,
4458 AROS_LHA(struct PsdPipeStream *, pps, A1),
4459 AROS_LHA(UBYTE *, buffer, A0),
4460 AROS_LHA(LONG, length, D0),
4461 LIBBASETYPEPTR, ps, 74, psd)
4463 AROS_LIBFUNC_INIT
4464 struct PsdPipe *pp;
4465 ULONG cnt;
4466 LONG ioerr;
4467 LONG remlen;
4468 BOOL term = FALSE;
4469 LONG actual = 0;
4470 ULONG sigmask;
4472 UBYTE *bufptr;
4473 UBYTE *srcptr;
4474 UBYTE *tarrptr;
4475 ULONG tcnt;
4476 UBYTE cchar;
4478 KPRINTF(2, ("psdStreamRead(%p, %p, %ld)\n", pps, buffer, length));
4479 if(!pps)
4481 return(-1);
4483 ObtainSemaphore(&pps->pps_AccessLock);
4484 KPRINTF(2, ("Sema\n"));
4485 pps->pps_Error = 0;
4486 if((!pps->pps_Pipes) || (!pps->pps_Endpoint->pep_Direction))
4488 KPRINTF(2, ("Wrong direction!\n"));
4489 pps->pps_Error = UHIOERR_BADPARAMS;
4490 ReleaseSemaphore(&pps->pps_AccessLock);
4491 return(-1);
4493 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4495 if(pps->pps_Flags & PSFF_BUFFERREAD)
4497 /* buffered reading */
4500 /* check for incoming packets */
4501 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4503 KPRINTF(1, ("PktBack(%p, %p, %ld/%ld)=%ld\n",
4504 pp, pp->pp_IOReq.iouh_Data, pp->pp_IOReq.iouh_Actual,
4505 pp->pp_IOReq.iouh_Length, pp->pp_IOReq.iouh_Req.io_Error));
4507 pps->pps_ReqBytes -= pp->pp_IOReq.iouh_Length;
4508 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4509 if((ioerr == UHIOERR_NAKTIMEOUT) && pp->pp_IOReq.iouh_Actual)
4511 ioerr = 0;
4514 if(ioerr)
4516 pps->pps_Error = ioerr;
4517 term = TRUE;
4518 if(ioerr != UHIOERR_TIMEOUT)
4520 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4521 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4522 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4524 /* stop automatic queueing */
4525 pps->pps_Flags &= ~PSFF_READAHEAD;
4526 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4527 } else {
4528 /* successfully received packet */
4529 pps->pps_BytesPending += pp->pp_IOReq.iouh_Actual;
4530 AddTail(&pps->pps_ReadyPipes, &pp->pp_Msg.mn_Node);
4533 if(length == -1) /* get all that's there (STRONGLY DISCOURAGED! Might cause buffer overflows) */
4535 length = pps->pps_BytesPending;
4537 /* check for buffered data */
4538 while(length && pps->pps_BytesPending)
4540 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4541 if(!pp->pp_Msg.mn_Node.ln_Succ) /* debug */
4543 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) "StreamRead", "Readqueue empty!");
4544 ReleaseSemaphore(&pps->pps_AccessLock);
4545 return(-1);
4547 if(pp->pp_IOReq.iouh_Actual < pps->pps_Offset)
4549 psdAddErrorMsg(RETURN_FAIL, (STRPTR) "StreamRead",
4550 "Actual %ld < offset %ld!", pp->pp_IOReq.iouh_Actual, pps->pps_Offset);
4551 ReleaseSemaphore(&pps->pps_AccessLock);
4552 return(-1);
4554 remlen = pp->pp_IOReq.iouh_Actual - pps->pps_Offset;
4555 if(length < remlen)
4557 KPRINTF(1, ("PktBit(%p, %p, %ld)\n", pp, buffer, length));
4558 remlen = length;
4559 } else {
4560 KPRINTF(1, ("PktRem(%p, %p, %ld)\n", pp, buffer, remlen));
4562 /* copy packet */
4563 if(pp->pp_Flags & PFF_INPLACE)
4565 KPRINTF(1, ("PktRemIP(%p, %p, %ld)\n", pp, buffer, remlen));
4566 } else {
4567 if(pps->pps_TermArray)
4569 /* EOF Mode */
4570 KPRINTF(1, ("PktCpyEOF(%p, %p, %ld)\n", pp, buffer, remlen));
4571 bufptr = buffer;
4572 srcptr = &(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]);
4573 tarrptr = pps->pps_TermArray;
4574 cnt = remlen;
4575 remlen = 0;
4576 if(cnt)
4580 cchar = *bufptr++ = *srcptr++;
4581 remlen++;
4582 tcnt = 0;
4585 if(cchar < tarrptr[tcnt])
4587 break;
4589 else if(cchar == tarrptr[tcnt])
4591 cnt = 1;
4592 term = TRUE;
4593 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, remlen));
4594 break;
4596 if(tcnt < 7)
4598 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4600 break;
4603 } while(++tcnt < 8);
4604 } while(--cnt);
4606 } else {
4607 KPRINTF(1, ("PktCpy(%p, %p, %ld)\n", pp, buffer, remlen));
4608 /* quick non-eof mode */
4609 CopyMem(&(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]), buffer, remlen);
4612 actual += remlen;
4613 length -= remlen;
4614 buffer += remlen;
4615 pps->pps_BytesPending -= remlen;
4616 pps->pps_Offset += remlen;
4617 /* end of packet reached? */
4618 if(pps->pps_Offset == pp->pp_IOReq.iouh_Actual)
4620 pps->pps_Offset = 0;
4621 Remove(&pp->pp_Msg.mn_Node);
4622 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4623 /* check for short packet */
4624 if((pps->pps_Flags & PSFF_SHORTTERM) && (pp->pp_IOReq.iouh_Actual % pp->pp_IOReq.iouh_MaxPktSize))
4626 term = TRUE;
4629 if(term)
4631 break;
4634 /* start sending out requests */
4635 remlen = length;
4636 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4637 if(!(pps->pps_BytesPending || pps->pps_ReqBytes || pps->pps_TermArray || (length < pps->pps_BufferSize)))
4639 /* faster non-buffered mode */
4640 if(pp->pp_Msg.mn_Node.ln_Succ)
4642 pp->pp_Flags |= PFF_INPLACE;
4643 Remove(&pp->pp_Msg.mn_Node);
4644 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4645 KPRINTF(1, ("OutFast(%p, %p, %ld/%ld)\n",
4646 pp, buffer, remlen, length));
4647 psdSendPipe(pp, buffer, remlen);
4648 pps->pps_ReqBytes += remlen;
4649 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4652 /* slower buffered mode */
4653 while(pp->pp_Msg.mn_Node.ln_Succ && ((remlen > pps->pps_ReqBytes) || (pps->pps_Flags & PSFF_READAHEAD)))
4655 pp->pp_Flags &= ~PFF_INPLACE;
4656 Remove(&pp->pp_Msg.mn_Node);
4657 if((pps->pps_Flags & PSFF_READAHEAD) || (remlen % pp->pp_IOReq.iouh_MaxPktSize))
4659 KPRINTF(1, ("OutSlow(%p, %p, %ld)\n",
4660 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], pps->pps_BufferSize));
4661 remlen = pps->pps_BufferSize;
4662 } else {
4663 KPRINTF(1, ("OutExact(%p, %p, %ld)\n",
4664 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen));
4666 psdSendPipe(pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen);
4667 pps->pps_ReqBytes += remlen;
4668 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4670 if((!length) || (pps->pps_Flags & PSFF_DONOTWAIT))
4672 term = TRUE;
4674 if(!term)
4676 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4677 KPRINTF(1, ("WaitPort (%p)\n", sigmask));
4678 sigmask = Wait(sigmask);
4679 KPRINTF(1, ("Wait back (%p)\n", sigmask));
4680 if(sigmask & pps->pps_AbortSigMask)
4682 KPRINTF(1, ("Aborted!\n"));
4683 term = TRUE;
4684 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4687 } while(!term);
4688 } else {
4689 /* plain reading (might lose data) */
4690 if(pps->pps_TermArray || (pps->pps_Flags & PSFF_READAHEAD))
4692 psdAddErrorMsg0(RETURN_WARN, (STRPTR) "StreamRead", "This mode combination for the stream is not supported!");
4694 /* start sending out requests */
4695 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4696 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4698 ioerr = psdDoPipe(pp, buffer, length);
4699 if(ioerr)
4701 pps->pps_Error = ioerr;
4702 if(ioerr != UHIOERR_TIMEOUT)
4704 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4705 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4706 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4709 actual = pp->pp_IOReq.iouh_Actual;
4713 ReleaseSemaphore(&pps->pps_AccessLock);
4714 return(actual);
4715 AROS_LIBFUNC_EXIT
4717 /* \\\ */
4719 /* /// "psdStreamWrite()" */
4720 AROS_LH3(LONG, psdStreamWrite,
4721 AROS_LHA(struct PsdPipeStream *, pps, A1),
4722 AROS_LHA(UBYTE *, buffer, A0),
4723 AROS_LHA(LONG, length, D0),
4724 LIBBASETYPEPTR, ps, 75, psd)
4726 AROS_LIBFUNC_INIT
4727 struct PsdPipe *pp;
4728 struct PsdPipe *newpp;
4729 ULONG cnt;
4730 LONG ioerr;
4731 LONG remlen;
4732 LONG actual = 0;
4733 ULONG sigmask;
4735 UBYTE *bufptr;
4736 UBYTE *srcptr;
4737 UBYTE *tarrptr;
4738 ULONG tcnt;
4739 UBYTE cchar;
4741 KPRINTF(2, ("psdStreamWrite(%p, %p, %ld)\n", pps, buffer, length));
4742 if(!pps)
4744 return(-1);
4746 ObtainSemaphore(&pps->pps_AccessLock);
4747 pps->pps_Error = 0;
4748 if((!pps->pps_Pipes) || pps->pps_Endpoint->pep_Direction)
4750 KPRINTF(2, ("Wrong direction!\n"));
4751 pps->pps_Error = UHIOERR_BADPARAMS;
4752 ReleaseSemaphore(&pps->pps_AccessLock);
4753 return(-1);
4755 if(length == -1) /* null terminated string mode */
4757 KPRINTF(2, ("EOL mode!\n"));
4758 length = strlen(buffer);
4760 if((tarrptr = pps->pps_TermArray)) /* EOF Mode */
4762 KPRINTF(1, ("EOFSearch(%p, %ld)\n", buffer, length));
4763 srcptr = buffer;
4764 cnt = length;
4765 length = 0;
4766 if(cnt)
4770 cchar = *srcptr++;
4771 length++;
4772 tcnt = 0;
4775 if(cchar < tarrptr[tcnt])
4777 break;
4779 else if(cchar == tarrptr[tcnt])
4781 cnt = 1;
4782 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, length));
4783 break;
4785 if(tcnt)
4787 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4789 break;
4792 } while(++tcnt < 8);
4793 } while(--cnt);
4796 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4798 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4799 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4801 if(pps->pps_Flags & PSFF_BUFFERWRITE)
4803 /* buffered writing */
4804 if(pps->pps_BytesPending)
4806 remlen = pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize;
4807 /* align to packet boundary */
4808 if(remlen + length >= pp->pp_IOReq.iouh_MaxPktSize)
4810 /* new data crosses at least on packet size */
4811 if(pps->pps_BytesPending + length <= pps->pps_BufferSize)
4813 /* copy everything up to the last (!) boundary */
4814 remlen = pps->pps_BytesPending + length;
4815 remlen = remlen - (remlen % pp->pp_IOReq.iouh_MaxPktSize);
4816 remlen -= pps->pps_BytesPending;
4817 KPRINTF(1, ("PendOptCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4818 } else {
4819 /* just calculate amount to copy to the next boundary */
4820 remlen = pp->pp_IOReq.iouh_MaxPktSize - remlen;
4821 KPRINTF(1, ("PendOneCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4823 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], remlen);
4824 pps->pps_BytesPending += remlen;
4825 actual += remlen;
4826 buffer += remlen;
4827 length -= remlen;
4828 } else {
4829 KPRINTF(1, ("PendAdd(%p, %ld+%ld)\n", buffer, pps->pps_BytesPending, length));
4830 /* only a few bytes, see if we can fit them */
4831 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4832 pps->pps_BytesPending += length;
4833 actual += length;
4834 //buffer += length; /* not needed */
4835 length = 0;
4837 /* flush some buffers */
4838 if((length >= pp->pp_IOReq.iouh_MaxPktSize) ||
4839 ((pps->pps_BytesPending >= (pps->pps_BufferSize>>1)) && (pps->pps_BytesPending >= pp->pp_IOReq.iouh_MaxPktSize)))
4841 remlen = pps->pps_BytesPending - (pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize);
4842 KPRINTF(1, ("PendFlush(%ld/%ld)\n", remlen, pps->pps_BytesPending));
4843 Remove(&pp->pp_Msg.mn_Node);
4844 psdSendPipe(pp, pps->pps_Buffer, remlen);
4845 pps->pps_ActivePipe = pp;
4846 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4848 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4849 sigmask = Wait(sigmask);
4850 if(sigmask & pps->pps_AbortSigMask)
4852 KPRINTF(1, ("Kill signal detected!\n"));
4853 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4854 break;
4857 if(!newpp)
4859 psdAbortPipe(pp);
4861 ioerr = psdWaitPipe(pp);
4862 pps->pps_ActivePipe = NULL;
4863 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4865 /* move end of buffer */
4866 cnt = pps->pps_BytesPending;
4867 tcnt = pp->pp_IOReq.iouh_Actual;
4868 pps->pps_BytesPending -= tcnt;
4869 bufptr = pps->pps_Buffer;
4870 srcptr = bufptr + tcnt;
4871 cnt -= tcnt;
4872 if(cnt)
4876 *bufptr++ = *srcptr++;
4877 } while(--cnt);
4879 if(ioerr)
4881 pps->pps_Error = ioerr;
4882 if(ioerr != UHIOERR_TIMEOUT)
4884 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4885 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4886 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4888 ReleaseSemaphore(&pps->pps_AccessLock);
4889 return(actual);
4893 /* send out large chunk (avoid copying) */
4894 if(length >= pp->pp_IOReq.iouh_MaxPktSize)
4896 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4897 KPRINTF(1, ("BulkFlush(%p, %ld/%ld)\n", buffer, remlen, length));
4898 Remove(&pp->pp_Msg.mn_Node);
4899 psdSendPipe(pp, buffer, remlen);
4900 pps->pps_ActivePipe = pp;
4901 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4903 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4904 sigmask = Wait(sigmask);
4905 if(sigmask & pps->pps_AbortSigMask)
4907 KPRINTF(1, ("Kill signal detected!\n"));
4908 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4909 break;
4912 if(!newpp)
4914 psdAbortPipe(pp);
4916 ioerr = psdWaitPipe(pp);
4917 pps->pps_ActivePipe = NULL;
4918 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4920 actual += pp->pp_IOReq.iouh_Actual;
4921 buffer += pp->pp_IOReq.iouh_Actual;
4922 length -= pp->pp_IOReq.iouh_Actual;
4923 if(ioerr)
4925 pps->pps_Error = ioerr;
4926 if(ioerr != UHIOERR_TIMEOUT)
4928 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4929 "Packet(%s) failed: %s (%ld)", (STRPTR) "c",
4930 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4932 ReleaseSemaphore(&pps->pps_AccessLock);
4933 return(actual);
4936 /* buffer remaining bytes */
4937 if(length)
4939 KPRINTF(1, ("BufAdd(%p, %ld)\n", buffer, length));
4940 /* only a few bytes left, so lets buffer them */
4941 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4942 pps->pps_BytesPending += length;
4943 actual += length;
4945 } else {
4946 /* plain writing */
4947 /* start sending out requests */
4948 KPRINTF(1, ("PlainWrite(%p, %ld)\n", buffer, length));
4949 Remove(&pp->pp_Msg.mn_Node);
4950 psdSendPipe(pp, buffer, length);
4951 pps->pps_ActivePipe = pp;
4952 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4954 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4955 sigmask = Wait(sigmask);
4956 if(sigmask & pps->pps_AbortSigMask)
4958 KPRINTF(1, ("Kill signal detected!\n"));
4959 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4960 break;
4963 if(!newpp)
4965 psdAbortPipe(pp);
4967 ioerr = psdWaitPipe(pp);
4968 pps->pps_ActivePipe = NULL;
4969 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4970 if(ioerr)
4972 pps->pps_Error = ioerr;
4973 if(ioerr != UHIOERR_TIMEOUT)
4975 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4976 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4977 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4980 actual = pp->pp_IOReq.iouh_Actual;
4982 } else {
4983 KPRINTF(2, ("No free pipe!\n"));
4986 ReleaseSemaphore(&pps->pps_AccessLock);
4987 return(actual);
4988 AROS_LIBFUNC_EXIT
4990 /* \\\ */
4992 /* /// "psdStreamFlush()" */
4993 AROS_LH1(LONG, psdStreamFlush,
4994 AROS_LHA(struct PsdPipeStream *, pps, A1),
4995 LIBBASETYPEPTR, ps, 76, psd)
4997 AROS_LIBFUNC_INIT
4998 struct PsdPipe *pp;
4999 ULONG cnt;
5000 LONG ioerr;
5001 LONG ret = FALSE;
5003 KPRINTF(2, ("psdStreamFlush(%p)\n", pps));
5004 if(!pps)
5006 return(-1);
5008 ObtainSemaphore(&pps->pps_AccessLock);
5009 pps->pps_Error = 0;
5010 if(pps->pps_Endpoint->pep_Direction)
5012 /* IN */
5013 KPRINTF(2, ("Flushing in...\n"));
5014 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
5016 psdAbortPipe(pps->pps_Pipes[cnt]);
5018 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
5020 psdWaitPipe(pps->pps_Pipes[cnt]);
5022 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5023 while(pp->pp_Msg.mn_Node.ln_Succ)
5025 Remove(&pp->pp_Msg.mn_Node);
5026 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5027 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5029 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
5031 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5033 pps->pps_ReqBytes = 0;
5034 pps->pps_BytesPending = 0;
5035 pps->pps_Offset = 0;
5036 ret = TRUE;
5037 } else {
5038 /* OUT */
5039 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
5040 if(pp->pp_Msg.mn_Node.ln_Succ)
5042 ret = TRUE;
5043 if(pps->pps_BytesPending)
5045 KPRINTF(2, ("Flushing out %ld...\n", pps->pps_BytesPending));
5046 Remove(&pp->pp_Msg.mn_Node);
5047 ioerr = psdDoPipe(pp, pps->pps_Buffer, pps->pps_BytesPending);
5048 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5049 pps->pps_BytesPending = 0;
5050 if(ioerr)
5052 pps->pps_Error = ioerr;
5053 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamFlush",
5054 "Packet(%s) failed: %s (%ld)", (STRPTR) "f",
5055 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5056 ret = FALSE;
5058 } else {
5059 KPRINTF(2, ("Nothing to flush\n"));
5063 ReleaseSemaphore(&pps->pps_AccessLock);
5064 return(ret);
5065 AROS_LIBFUNC_EXIT
5067 /* \\\ */
5069 /* /// "psdGetStreamError()" */
5070 AROS_LH1(LONG, psdGetStreamError,
5071 AROS_LHA(struct PsdPipeStream *, pps, A1),
5072 LIBBASETYPEPTR, ps, 77, psd)
5074 AROS_LIBFUNC_INIT
5075 KPRINTF(1, ("psdGetStreamError(%p)\n", pps));
5076 if(pps)
5078 return((LONG) pps->pps_Error);
5079 } else {
5080 return(-1);
5082 AROS_LIBFUNC_EXIT
5084 /* \\\ */
5086 /* *** Realtime Iso */
5088 /* /// "psdAllocRTIsoHandler()" */
5089 AROS_LH2(struct PsdRTIsoHandler *, psdAllocRTIsoHandlerA,
5090 AROS_LHA(struct PsdEndpoint *, pep, A0),
5091 AROS_LHA(struct TagItem *, tags, A1),
5092 LIBBASETYPEPTR, ps, 93, psd)
5094 AROS_LIBFUNC_INIT
5095 struct PsdRTIsoHandler *prt;
5096 struct PsdPipe *pp;
5097 LONG ioerr;
5099 KPRINTF(2, ("psdAllocRTIso(%p, %p)\n", pep, tags));
5100 if(!pep)
5102 return(NULL);
5104 if(pep->pep_TransType != USEAF_ISOCHRONOUS)
5106 return(NULL);
5108 if(!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_RT_ISO))
5110 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support realtime iso transfers. Sorry.");
5111 return(NULL);
5113 if((prt = psdAllocVec(sizeof(struct PsdRTIsoHandler))))
5115 prt->prt_Device = pep->pep_Interface->pif_Config->pc_Device;
5116 prt->prt_Endpoint = pep;
5117 prt->prt_RTIso.urti_OutPrefetch = 2048;
5118 if((pp = prt->prt_Pipe = psdAllocPipe(prt->prt_Device, (struct MsgPort *) 0xffffffff, pep)))
5120 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = NULL;
5121 psdSetAttrsA(PGA_RTISO, prt, tags);
5122 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ADDISOHANDLER;
5123 pp->pp_IOReq.iouh_Data = &prt->prt_RTIso;
5124 // hardware must support quick IO for this to work!
5125 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5126 if(!ioerr)
5128 Forbid();
5129 AddTail(&prt->prt_Device->pd_RTIsoHandlers, &prt->prt_Node);
5130 Permit();
5131 return(prt);
5132 } else {
5133 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5134 "Adding RT Iso Handler failed: %s (%ld)",
5135 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5137 psdFreePipe(prt->prt_Pipe);
5139 psdFreeVec(prt);
5141 return(NULL);
5142 AROS_LIBFUNC_EXIT
5144 /* \\\ */
5146 /* /// "psdFreeRTIsoHandler()" */
5147 AROS_LH1(void, psdFreeRTIsoHandler,
5148 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5149 LIBBASETYPEPTR, ps, 94, psd)
5151 AROS_LIBFUNC_INIT
5152 struct PsdPipe *pp;
5154 if(!prt)
5156 return;
5158 Forbid();
5159 Remove(&prt->prt_Node);
5160 Permit();
5161 pp = prt->prt_Pipe;
5162 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_REMISOHANDLER;
5163 DoIO((struct IORequest *) &pp->pp_IOReq);
5164 psdFreePipe(pp);
5165 psdFreeVec(prt);
5166 AROS_LIBFUNC_EXIT
5168 /* \\\ */
5170 /* /// "psdStartRTIso()" */
5171 AROS_LH1(LONG, psdStartRTIso,
5172 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5173 LIBBASETYPEPTR, ps, 95, psd)
5175 AROS_LIBFUNC_INIT
5176 struct PsdPipe *pp;
5177 LONG ioerr;
5179 if(!prt)
5181 return UHIOERR_BADPARAMS;
5183 pp = prt->prt_Pipe;
5184 if(pp->pp_Device->pd_Flags & PDFF_SUSPENDED)
5186 // make sure the device is up and running before trying to send a new pipe
5187 psdResumeDevice(pp->pp_Device);
5189 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STARTRTISO;
5190 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5191 if(!ioerr)
5193 ++pp->pp_Device->pd_IOBusyCount;
5195 return(ioerr);
5196 AROS_LIBFUNC_EXIT
5198 /* \\\ */
5200 /* /// "psdStopRTIso()" */
5201 AROS_LH1(LONG, psdStopRTIso,
5202 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5203 LIBBASETYPEPTR, ps, 96, psd)
5205 AROS_LIBFUNC_INIT
5206 struct PsdPipe *pp;
5207 LONG ioerr;
5209 if(!prt)
5211 return UHIOERR_BADPARAMS;
5213 pp = prt->prt_Pipe;
5214 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STOPRTISO;
5215 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5216 if(!ioerr)
5218 --pp->pp_Device->pd_IOBusyCount;
5220 return(ioerr);
5221 AROS_LIBFUNC_EXIT
5223 /* \\\ */
5225 /* *** Classes *** */
5227 /* /// "psdAddClass()" */
5228 AROS_LH2(struct PsdUsbClass *, psdAddClass,
5229 AROS_LHA(STRPTR, name, A1),
5230 AROS_LHA(ULONG, vers, D0),
5231 LIBBASETYPEPTR, ps, 35, psd)
5233 AROS_LIBFUNC_INIT
5234 struct Library *cls = NULL;
5235 struct PsdUsbClass *puc;
5236 IPTR pri = 0;
5237 STRPTR desc;
5238 UWORD msgoff;
5239 STRPTR origname = name;
5240 STRPTR evilmsg[8] = { "Say hello to %s V%ld.%ld (%s).",
5241 "Whoah! %s V%ld.%ld surprised as %s.",
5242 "The door bell rang for %s V%ld.%ld (%s).",
5243 "Welcome %s V%ld.%ld (%s) to the party.",
5245 "Don't laugh at %s V%ld.%ld for %s.",
5246 "Time has come for %s V%ld.%ld (%s) to join the show.",
5247 "Start blaming %s V%ld.%ld for helping at %s.",
5248 "Ain't %s V%ld.%ld useful for %s?" };
5250 KPRINTF(5, ("psdAddClass(%s, %ld)\n", name, vers));
5252 while(*name)
5254 if((cls = OpenLibrary(name, vers)))
5256 break;
5260 if((*name == '/') || (*name == ':'))
5262 ++name;
5263 break;
5265 } while(*(++name));
5267 if(cls)
5269 Forbid();
5270 if(FindName(&ps->ps_Classes, cls->lib_Node.ln_Name))
5272 Permit();
5273 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5274 "Attempted to add class %s twice. Nothing is good enough for people like you.",
5275 name);
5276 KPRINTF(20, ("attempt to add class twice!\n"));
5277 CloseLibrary(cls);
5278 return(NULL);
5280 Permit();
5281 if((puc = psdAllocVec(sizeof(struct PsdUsbClass))))
5283 puc->puc_Base = ps;
5284 puc->puc_ClassBase = cls;
5285 puc->puc_Node.ln_Name = puc->puc_ClassName = psdCopyStr(cls->lib_Node.ln_Name);
5286 puc->puc_FullPath = psdCopyStr(origname);
5288 usbGetAttrs(UGA_CLASS, NULL,
5289 UCCA_Priority, &pri,
5290 UCCA_Description, &desc,
5291 TAG_END);
5293 puc->puc_Node.ln_Pri = pri;
5294 psdLockWritePBase();
5295 Enqueue(&ps->ps_Classes, &puc->puc_Node);
5296 psdUnlockPBase();
5297 msgoff = ps->ps_FunnyCount++ & 7;
5299 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5300 evilmsg[msgoff],
5301 cls->lib_Node.ln_Name, cls->lib_Version, cls->lib_Revision, desc);
5302 psdSendEvent(EHMB_ADDCLASS, puc, NULL);
5303 return(puc);
5305 CloseLibrary(cls);
5307 return(NULL);
5308 AROS_LIBFUNC_EXIT
5310 /* \\\ */
5312 /* /// "psdRemClass()" */
5313 AROS_LH1(void, psdRemClass,
5314 AROS_LHA(struct PsdUsbClass *, puc, A1),
5315 LIBBASETYPEPTR, ps, 36, psd)
5317 AROS_LIBFUNC_INIT
5318 KPRINTF(5, ("psdRemClass(%p)\n", puc));
5319 psdLockWritePBase();
5320 Remove(&puc->puc_Node);
5321 psdUnlockPBase();
5323 /* Check if there are still bindings remaining */
5324 while(puc->puc_UseCnt)
5326 struct PsdDevice *pd;
5327 struct PsdConfig *pc;
5328 struct PsdInterface *pif;
5330 KPRINTF(20, ("This should never happen: Class %s still in use (%ld), can't close!\n",
5331 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt));
5333 /* Well, try to release the open bindings in a best effort attempt */
5334 psdLockReadPBase();
5335 pd = NULL;
5336 while((pd = psdGetNextDevice(pd)))
5338 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
5340 psdUnlockPBase();
5341 psdReleaseDevBinding(pd);
5342 psdLockReadPBase();
5343 pd = NULL; /* restart */
5344 continue;
5346 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5347 while(pc->pc_Node.ln_Succ)
5349 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5350 while(pif->pif_Node.ln_Succ)
5352 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
5354 psdUnlockPBase();
5355 psdReleaseIfBinding(pif);
5356 psdLockReadPBase();
5357 pd = NULL; /* restart */
5358 continue;
5360 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5362 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5365 psdUnlockPBase();
5366 if(puc->puc_UseCnt)
5368 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
5369 "This should never happen! Class %s still in use (cnt=%ld). Could not get rid of it! Sorry, we're broke.",
5370 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt);
5372 /*psdDelayMS(2000);*/
5375 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5376 "I shot class %s, but I didn't kill the deputy.",
5377 puc->puc_ClassBase->lib_Node.ln_Name);
5378 CloseLibrary(puc->puc_ClassBase);
5379 psdFreeVec(puc->puc_ClassName);
5380 psdFreeVec(puc->puc_FullPath);
5381 psdFreeVec(puc);
5382 psdSendEvent(EHMB_REMCLASS, puc, NULL);
5383 AROS_LIBFUNC_EXIT
5385 /* \\\ */
5387 /* *** Error Msgs *** */
5389 /* /// "psdAddErrorMsgA()" */
5390 AROS_LH4(struct PsdErrorMsg *, psdAddErrorMsgA,
5391 AROS_LHA(UWORD, level, D0),
5392 AROS_LHA(STRPTR, origin, A0),
5393 AROS_LHA(STRPTR, fmtstr, A1),
5394 AROS_LHA(RAWARG, fmtdata, A2),
5395 LIBBASETYPEPTR, ps, 40, psd)
5397 AROS_LIBFUNC_INIT
5398 struct PsdErrorMsg *pem;
5399 if(((!ps->ps_GlobalCfg->pgc_LogInfo) && (level < RETURN_WARN)) ||
5400 ((!ps->ps_GlobalCfg->pgc_LogWarning) && (level >= RETURN_WARN) && (level < RETURN_ERROR)) ||
5401 ((!ps->ps_GlobalCfg->pgc_LogError) && (level >= RETURN_ERROR) && (level < RETURN_FAIL)) ||
5402 ((!ps->ps_GlobalCfg->pgc_LogFailure) && (level >= RETURN_FAIL)))
5404 return(NULL);
5406 if((pem = psdAllocVec(sizeof(struct PsdErrorMsg))))
5408 pem->pem_Base = ps;
5409 pem->pem_Level = level;
5410 if((pem->pem_Origin = psdCopyStr(origin)))
5412 if((pem->pem_Msg = psdCopyStrFmtA(fmtstr, fmtdata)))
5414 if (ps->ps_Flags & PSF_KLOG) {
5415 KPrintF("[%s] %s\n", origin, pem->pem_Msg);
5418 if(pOpenDOS(ps))
5420 DateStamp(&pem->pem_DateStamp);
5421 } else {
5422 struct timerequest tr = ps->ps_TimerIOReq;
5423 tr.tr_node.io_Command = TR_GETSYSTIME;
5424 DoIO((struct IORequest *) &tr);
5425 pem->pem_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60);
5426 pem->pem_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60;
5427 pem->pem_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50;
5429 Forbid();
5430 AddTail(&ps->ps_ErrorMsgs, &pem->pem_Node);
5431 Permit();
5432 psdSendEvent(EHMB_ADDERRORMSG, pem, NULL);
5433 return(pem);
5435 psdFreeVec(pem->pem_Origin);
5437 psdFreeVec(pem);
5439 return(NULL);
5440 AROS_LIBFUNC_EXIT
5442 /* \\\ */
5444 /* /// "psdRemErrorMsg()" */
5445 AROS_LH1(void, psdRemErrorMsg,
5446 AROS_LHA(struct PsdErrorMsg *, pem, A0),
5447 LIBBASETYPEPTR, ps, 41, psd)
5449 AROS_LIBFUNC_INIT
5450 KPRINTF(1, ("psdRemErrorMsg()\n"));
5451 Forbid();
5452 Remove(&pem->pem_Node);
5453 Permit();
5454 psdFreeVec(pem->pem_Origin);
5455 psdFreeVec(pem->pem_Msg);
5456 psdFreeVec(pem);
5457 psdSendEvent(EHMB_REMERRORMSG, pem, NULL);
5458 AROS_LIBFUNC_EXIT
5460 /* \\\ */
5462 /* *** Bindings *** */
5464 /* /// "psdClassScan()" */
5465 AROS_LH0(void, psdClassScan,
5466 LIBBASETYPEPTR, ps, 37, psd)
5468 AROS_LIBFUNC_INIT
5469 struct PsdHardware *phw;
5470 struct PsdDevice *pd;
5471 struct PsdUsbClass *puc;
5473 psdLockReadPBase();
5475 if((FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS) && (!ps->ps_ConfigRead))
5477 // it's the first time we were reading the config and DOS was not available
5478 ps->ps_StartedAsTask = TRUE;
5481 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5482 if(!puc->puc_Node.ln_Succ)
5484 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "ClassScan attempted with no classes installed!");
5485 psdUnlockPBase();
5486 return;
5489 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5490 while(phw->phw_Node.ln_Succ)
5492 if((pd = phw->phw_RootDevice))
5494 // for the root, do it ourselves, the rest is done by each hub task
5495 psdHubClassScan(pd);
5497 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5499 psdUnlockPBase();
5500 //psdSendEvent(EHMB_CLSSCANRDY, NULL, NULL);
5501 KPRINTF(5, ("************ Scanning finished!\n"));
5502 AROS_LIBFUNC_EXIT
5504 /* \\\ */
5506 /* /// "psdDoHubMethodA()" */
5507 AROS_LH3(LONG, psdDoHubMethodA,
5508 AROS_LHA(struct PsdDevice *, pd, A0),
5509 AROS_LHA(ULONG, methodid, D0),
5510 AROS_LHA(APTR, methoddata, A1),
5511 LIBBASETYPEPTR, ps, 92, psd)
5513 AROS_LIBFUNC_INIT
5514 struct PsdUsbClass *puc;
5515 KPRINTF(2, ("psdDoHubMethodA(%p)\n", pd));
5517 if(pd)
5519 if(pd->pd_Hub)
5521 if((pd->pd_Hub->pd_DevBinding) && (puc = pd->pd_Hub->pd_ClsBinding))
5523 return(usbDoMethodA(methodid, methoddata));
5527 return 0;
5528 AROS_LIBFUNC_EXIT
5530 /* \\\ */
5532 /* /// "psdClaimAppBindingA()" */
5533 AROS_LH1(struct PsdAppBinding *, psdClaimAppBindingA,
5534 AROS_LHA(struct TagItem *, tags, A1),
5535 LIBBASETYPEPTR, ps, 45, psd)
5537 AROS_LIBFUNC_INIT
5538 struct PsdDevice *pd;
5539 struct PsdConfig *pc;
5540 struct PsdInterface *pif;
5541 struct PsdDevice *hubpd;
5542 struct PsdAppBinding tmppab;
5543 struct PsdAppBinding *pab = NULL;
5544 struct PsdUsbClass *puc;
5546 APTR binding;
5548 KPRINTF(2, ("psdClaimAppBindingA(%p)\n", tags));
5550 tmppab.pab_Device = NULL;
5551 tmppab.pab_ReleaseHook = NULL;
5552 tmppab.pab_Task = NULL;
5553 tmppab.pab_ForceRelease = FALSE;
5554 psdSetAttrsA(PGA_APPBINDING, &tmppab, tags);
5555 if(tmppab.pab_Device && tmppab.pab_ReleaseHook)
5557 pd = tmppab.pab_Device;
5559 // force release of other bindings first
5560 if(tmppab.pab_ForceRelease)
5562 /* If there are bindings, get rid of them. */
5563 if(pd->pd_DevBinding)
5565 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5566 "%s really wants to bind to %s, so I'm letting the old binding go.",
5567 FindTask(NULL)->tc_Node.ln_Name,
5568 pd->pd_ProductStr);
5570 psdReleaseDevBinding(pd);
5571 } else {
5572 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5573 while(pc->pc_Node.ln_Succ)
5575 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5576 while(pif->pif_Node.ln_Succ)
5578 if(pif->pif_IfBinding)
5580 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5581 "%s really wants to bind to %s, so I'm letting the old binding go.",
5582 FindTask(NULL)->tc_Node.ln_Name,
5583 pd->pd_ProductStr);
5584 psdReleaseIfBinding(pif);
5586 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5588 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5592 hubpd = pd->pd_Hub;
5593 if(!hubpd) // claim app binding at the root hub -- improbable, but possible.
5595 pab = psdHubClaimAppBindingA(tags);
5596 } else {
5597 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5599 pab = (struct PsdAppBinding *) usbDoMethod(UCM_HubClaimAppBinding, binding, tags);
5602 if(pab)
5604 // fill in task names
5605 pab->pab_Task = FindTask(NULL);
5606 pab->pab_Node.ln_Name = pab->pab_Task->tc_Node.ln_Name;
5607 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5608 return(pab);
5611 return(NULL);
5612 AROS_LIBFUNC_EXIT
5614 /* \\\ */
5616 /* /// "psdReleaseAppBinding()" */
5617 AROS_LH1(void, psdReleaseAppBinding,
5618 AROS_LHA(struct PsdAppBinding *, pab, A0),
5619 LIBBASETYPEPTR, ps, 46, psd)
5621 AROS_LIBFUNC_INIT
5622 struct PsdDevice *pd;
5623 struct PsdDevice *hubpd;
5624 struct PsdUsbClass *puc;
5625 APTR binding;
5627 KPRINTF(2, ("psdReleaseAppBinding(%p)\n", pab));
5629 if(pab)
5631 pd = pab->pab_Device;
5632 hubpd = pd->pd_Hub;
5633 if(!hubpd) // release binding of hub (improbable)
5635 psdHubReleaseDevBinding(pd);
5636 return;
5638 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5640 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5643 AROS_LIBFUNC_EXIT
5645 /* \\\ */
5647 /* /// "psdReleaseDevBinding()" */
5648 AROS_LH1(void, psdReleaseDevBinding,
5649 AROS_LHA(struct PsdDevice *, pd, A0),
5650 LIBBASETYPEPTR, ps, 50, psd)
5652 AROS_LIBFUNC_INIT
5653 struct PsdUsbClass *puc;
5654 struct PsdDevice *hubpd;
5655 APTR binding;
5657 KPRINTF(5, ("psdReleaseDevBinding(%p)\n", pd));
5658 if(pd->pd_DevBinding)
5660 hubpd = pd->pd_Hub;
5661 if(!hubpd) // release binding of hub
5663 psdHubReleaseDevBinding(pd);
5664 return;
5666 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5668 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5671 AROS_LIBFUNC_EXIT
5673 /* \\\ */
5675 /* /// "psdReleaseIfBinding()" */
5676 AROS_LH1(void, psdReleaseIfBinding,
5677 AROS_LHA(struct PsdInterface *, pif, A0),
5678 LIBBASETYPEPTR, ps, 51, psd)
5680 AROS_LIBFUNC_INIT
5681 struct PsdUsbClass *puc;
5682 struct PsdDevice *hubpd;
5683 APTR binding;
5685 KPRINTF(5, ("psdReleaseIfBinding(%p)\n", pif));
5686 if(pif->pif_IfBinding && pif->pif_ClsBinding)
5688 hubpd = pif->pif_Config->pc_Device->pd_Hub;
5689 if(!hubpd) // release binding of hub (improbable)
5691 psdHubReleaseIfBinding(pif);
5692 return;
5694 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5696 usbDoMethod(UCM_HubReleaseIfBinding, binding, pif);
5699 AROS_LIBFUNC_EXIT
5701 /* \\\ */
5703 /* /// "psdUnbindAll()" */
5704 AROS_LH0(void, psdUnbindAll,
5705 LIBBASETYPEPTR, ps, 61, psd)
5707 AROS_LIBFUNC_INIT
5708 struct PsdHardware *phw;
5709 struct PsdDevice *pd;
5710 struct PsdConfig *pc;
5711 struct PsdInterface *pif;
5712 BOOL restart;
5714 KPRINTF(10, ("pUnbindAll()\n"));
5715 /* FIXME What happens if devices or hardware gets removed during the process? Need notify semaphore */
5716 psdLockReadPBase();
5719 restart = FALSE;
5720 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5721 while(phw->phw_Node.ln_Succ)
5723 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
5724 while(pd->pd_Node.ln_Succ)
5726 /* If there are bindings, get rid of them. */
5727 if(pd->pd_DevBinding)
5729 psdUnlockPBase();
5730 psdReleaseDevBinding(pd);
5731 psdLockReadPBase();
5732 restart = TRUE;
5733 break;
5735 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5736 while(pc->pc_Node.ln_Succ)
5738 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5739 while(pif->pif_Node.ln_Succ)
5741 if(pif->pif_IfBinding)
5743 psdUnlockPBase();
5744 psdReleaseIfBinding(pif);
5745 psdLockReadPBase();
5746 restart = TRUE;
5747 break;
5749 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5751 if(restart)
5753 break;
5755 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5757 if(restart)
5759 break;
5761 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
5763 if(restart)
5765 break;
5767 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5769 } while(restart);
5770 psdUnlockPBase();
5771 AROS_LIBFUNC_EXIT
5773 /* \\\ */
5775 /* /// "psdHubClassScan()" */
5776 AROS_LH1(void, psdHubClassScan,
5777 AROS_LHA(struct PsdDevice *, pd, A0),
5778 LIBBASETYPEPTR, ps, 82, psd)
5780 AROS_LIBFUNC_INIT
5781 struct PsdUsbClass *puc;
5782 struct PsdConfig *pc;
5783 struct PsdInterface *pif;
5784 struct PsdInterface *firstpif;
5785 struct PsdPipe *pp = NULL;
5786 struct MsgPort *mp;
5787 APTR binding;
5788 UWORD hasifbinding;
5789 BOOL mainif;
5790 STRPTR owner;
5792 KPRINTF(5, ("psdClassScan()\n"));
5794 if(!(mp = CreateMsgPort()))
5796 return;
5798 psdLockReadPBase();
5799 psdLockWriteDevice(pd);
5800 while(!(pd->pd_PoPoCfg.poc_NoClassBind || pd->pd_DevBinding))
5802 if(!(pp = psdAllocPipe(pd, mp, NULL)))
5804 break;
5806 KPRINTF(5, ("Doing ClassScan on Device: %s\n", pd->pd_ProductStr));
5807 hasifbinding = 0;
5808 /* First look if there is any interface binding. We may not change
5809 the current config in this case! */
5810 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5811 while(pc->pc_Node.ln_Succ)
5813 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5815 while(pif->pif_Node.ln_Succ)
5817 if(pif->pif_IfBinding)
5819 hasifbinding = pc->pc_CfgNum;
5820 break;
5822 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5824 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5827 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5828 if((!hasifbinding) && owner)
5830 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5831 while(puc->puc_Node.ln_Succ)
5833 if(!strcmp(owner, puc->puc_ClassName))
5835 if((pd->pd_DevBinding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd)))
5837 pd->pd_ClsBinding = puc;
5838 puc->puc_UseCnt++;
5839 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5840 } else {
5841 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5842 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5844 break;
5846 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5848 /* no more scanning required, abort here */
5849 break;
5852 /* Second attempt */
5853 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5854 while(pc->pc_Node.ln_Succ)
5856 if((!hasifbinding) || (hasifbinding == pc->pc_CfgNum))
5858 /* If the current config is not the one selected, change it */
5859 if(pd->pd_CurrCfg != pc->pc_CfgNum)
5861 psdSetDeviceConfig(pp, pc->pc_CfgNum);
5863 KPRINTF(5, (" Config %ld\n", pc->pc_CfgNum));
5864 /* If something went wrong above, we must exclude this config */
5865 if(pd->pd_CurrCfg == pc->pc_CfgNum)
5867 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5868 while(pif->pif_Node.ln_Succ)
5870 KPRINTF(5, (" Interface %ld\n", pif->pif_IfNum));
5871 firstpif = pif;
5872 mainif = TRUE;
5873 if(!pif->pif_IfBinding)
5875 binding = NULL;
5878 if(!psdSetAltInterface(pp, pif))
5880 pif->pif_IfBinding = NULL;
5881 /* Okay, this alternate setting failed. Try to get next one */
5882 if(!mainif)
5884 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5885 if(pif->pif_Node.ln_Succ)
5887 KPRINTF(5, ("CONT!\n"));
5888 continue;
5889 } else {
5890 KPRINTF(5, ("BREAK!\n"));
5891 pif = firstpif;
5892 break;
5896 owner = psdGetForcedBinding(pd->pd_IDString, pif->pif_IDString);
5897 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5898 while(puc->puc_Node.ln_Succ)
5900 KPRINTF(5, (">>>PING %s!\n", puc->puc_ClassName));
5901 if(owner)
5903 if(!strcmp(owner, puc->puc_ClassName))
5905 binding = (APTR) usbDoMethod(UCM_ForceInterfaceBinding, pif);
5906 if(!binding)
5908 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5909 "Forced interface binding of %s to %s failed.", pd->pd_ProductStr, owner);
5912 if(!binding)
5914 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5915 continue;
5917 } else {
5918 binding = (APTR) usbDoMethod(UCM_AttemptInterfaceBinding, pif);
5920 Forbid();
5921 KPRINTF(5, ("<<<PONG!!\n"));
5922 if(binding)
5924 KPRINTF(5, ("Got binding!\n"));
5925 /* Find root config structure */
5926 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5927 while(pif->pif_Node.ln_Succ)
5929 if(pif->pif_IfNum == firstpif->pif_IfNum)
5931 break;
5933 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5935 if(!pif->pif_Node.ln_Succ)
5937 KPRINTF(5, ("Fucked it up!\n"));
5938 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Something incredibly stupid happend. I've given up.");
5939 Permit();
5940 break;
5942 pif->pif_IfBinding = binding;
5943 pif->pif_ClsBinding = puc;
5944 hasifbinding = pc->pc_CfgNum;
5945 puc->puc_UseCnt++;
5946 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5947 Permit();
5948 break;
5950 Permit();
5951 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5953 if(binding)
5955 break;
5957 //break; /* FIXME: DISABLED ALTSCANNING */
5958 /* Check alternate setting */
5959 if(pif->pif_AlterIfs.lh_Head->ln_Succ)
5961 /* There are some alternative interfaces, start at top */
5962 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
5963 mainif = FALSE;
5965 } while(pif != firstpif);
5966 //pif->pif_IfBinding = binding;
5967 if(!binding)
5969 psdSetAltInterface(pp, pif);
5971 /* Hohum, search current main interface then */
5972 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5973 while(pif->pif_Node.ln_Succ)
5975 if(pif->pif_IfNum == firstpif->pif_IfNum)
5977 break;
5979 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5982 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5986 KPRINTF(5, ("End, next ConfigCheck!\n"));
5987 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5989 /* Could not establish interface binding, try device binding then */
5990 //psdUnlockPBase();
5991 if(!hasifbinding)
5993 //pd->pd_DevBinding = (APTR) ~0UL;
5994 binding = NULL;
5995 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5996 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5997 while(puc->puc_Node.ln_Succ)
5999 binding = NULL;
6000 if(owner)
6002 if(!strcmp(owner, puc->puc_ClassName))
6004 binding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd, TAG_END);
6005 if(!binding)
6007 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6008 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
6011 if(!binding)
6013 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6014 continue;
6016 } else {
6017 binding = (APTR) usbDoMethod(UCM_AttemptDeviceBinding, pd);
6019 if(binding)
6021 pd->pd_DevBinding = binding;
6022 pd->pd_ClsBinding = puc;
6023 puc->puc_UseCnt++;
6024 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
6025 break;
6027 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6029 pd->pd_DevBinding = binding;
6031 break;
6033 if(pp)
6035 psdFreePipe(pp);
6037 // call hub class scan code
6038 if((binding = pd->pd_DevBinding) && (puc = pd->pd_ClsBinding))
6040 usbDoMethod(UCM_HubClassScan, binding);
6042 psdUnlockDevice(pd);
6043 psdUnlockPBase();
6044 DeleteMsgPort(mp);
6045 AROS_LIBFUNC_EXIT
6047 /* \\\ */
6049 /* /// "psdHubClaimAppBindingA()" */
6050 AROS_LH1(struct PsdAppBinding *, psdHubClaimAppBindingA,
6051 AROS_LHA(struct TagItem *, tags, A1),
6052 LIBBASETYPEPTR, ps, 83, psd)
6054 AROS_LIBFUNC_INIT
6055 struct PsdDevice *pd;
6056 struct PsdAppBinding *pab;
6057 struct PsdConfig *pc;
6058 struct PsdInterface *pif;
6060 BOOL hasbinding = FALSE;
6061 KPRINTF(2, ("psdHubClaimAppBindingA(%p)\n", tags));
6063 if((pab = psdAllocVec(sizeof(struct PsdAppBinding))))
6065 psdSetAttrsA(PGA_APPBINDING, pab, tags);
6066 if(pab->pab_Device && pab->pab_ReleaseHook)
6068 pd = pab->pab_Device;
6069 if(pd->pd_DevBinding)
6071 hasbinding = TRUE;
6072 } else {
6073 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6074 while(pc->pc_Node.ln_Succ)
6076 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6078 while(pif->pif_Node.ln_Succ)
6080 if(pif->pif_IfBinding)
6082 hasbinding = TRUE;
6083 break;
6085 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6087 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6090 if(!hasbinding)
6092 pd->pd_Flags |= PDFF_APPBINDING;
6093 pd->pd_DevBinding = pab;
6094 pd->pd_ClsBinding = NULL;
6095 return(pab);
6098 psdFreeVec(pab);
6100 return(NULL);
6101 AROS_LIBFUNC_EXIT
6103 /* \\\ */
6105 /* /// "psdHubReleaseDevBinding()" */
6106 AROS_LH1(void, psdHubReleaseDevBinding,
6107 AROS_LHA(struct PsdDevice *, pd, A0),
6108 LIBBASETYPEPTR, ps, 84, psd)
6110 AROS_LIBFUNC_INIT
6111 struct PsdUsbClass *puc;
6112 APTR binding;
6113 struct PsdAppBinding *pab;
6115 KPRINTF(5, ("psdHubReleaseDevBinding(%p)\n", pd));
6116 if(pd)
6118 psdLockWriteDevice(pd);
6119 if((binding = pd->pd_DevBinding))
6121 pd->pd_DevBinding = NULL;
6122 if(pd->pd_Flags & PDFF_APPBINDING)
6124 pab = (struct PsdAppBinding *) binding;
6125 CallHookPkt(pab->pab_ReleaseHook, pab, (APTR) pab->pab_UserData);
6126 pd->pd_ClsBinding = NULL;
6127 pd->pd_Flags &= ~PDFF_APPBINDING;
6128 psdFreeVec(pab);
6129 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6130 } else {
6131 puc = pd->pd_ClsBinding;
6132 if(puc)
6134 pd->pd_ClsBinding = NULL;
6135 usbDoMethod(UCM_ReleaseDeviceBinding, binding);
6136 puc->puc_UseCnt--;
6137 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6141 psdUnlockDevice(pd);
6143 AROS_LIBFUNC_EXIT
6145 /* \\\ */
6147 /* /// "psdHubReleaseIfBinding()" */
6148 AROS_LH1(void, psdHubReleaseIfBinding,
6149 AROS_LHA(struct PsdInterface *, pif, A0),
6150 LIBBASETYPEPTR, ps, 85, psd)
6152 AROS_LIBFUNC_INIT
6153 struct PsdUsbClass *puc;
6154 struct PsdDevice *pd;
6155 APTR binding;
6157 KPRINTF(5, ("psdHubReleaseIfBinding(%p)\n", pif));
6159 if(pif)
6161 pd = pif->pif_Config->pc_Device;
6162 psdLockWriteDevice(pd);
6163 if((binding = pif->pif_IfBinding))
6165 pif->pif_IfBinding = NULL;
6166 puc = pif->pif_ClsBinding;
6167 if(puc)
6169 pif->pif_ClsBinding = NULL;
6170 usbDoMethod(UCM_ReleaseInterfaceBinding, binding);
6171 puc->puc_UseCnt--;
6173 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6175 psdUnlockDevice(pd);
6177 AROS_LIBFUNC_EXIT
6179 /* \\\ */
6181 /* *** Events *** */
6183 /* /// "psdAddEventHandler()" */
6184 AROS_LH2(struct PsdEventHook *, psdAddEventHandler,
6185 AROS_LHA(struct MsgPort *, mp, A1),
6186 AROS_LHA(ULONG, msgmask, D0),
6187 LIBBASETYPEPTR, ps, 47, psd)
6189 AROS_LIBFUNC_INIT
6190 struct PsdEventHook *peh = NULL;
6192 KPRINTF(5, ("psdAddEventHandler(%p, %p)\n", mp, msgmask));
6194 if(mp)
6196 ObtainSemaphore(&ps->ps_ReentrantLock);
6197 if((peh = psdAllocVec(sizeof(struct PsdEventHook))))
6199 peh->peh_MsgPort = mp;
6200 peh->peh_MsgMask = msgmask;
6201 AddTail(&ps->ps_EventHooks, &peh->peh_Node);
6203 ReleaseSemaphore(&ps->ps_ReentrantLock);
6205 return(peh);
6206 AROS_LIBFUNC_EXIT
6208 /* \\\ */
6210 /* /// "psdRemEventHandler()" */
6211 AROS_LH1(void, psdRemEventHandler,
6212 AROS_LHA(struct PsdEventHook *, peh, A0),
6213 LIBBASETYPEPTR, ps, 48, psd)
6215 AROS_LIBFUNC_INIT
6216 struct Message *msg;
6218 KPRINTF(5, ("psdRemEventHandler(%p)\n", peh));
6219 if(!peh)
6221 return;
6223 ObtainSemaphore(&ps->ps_ReentrantLock);
6224 Remove(&peh->peh_Node);
6225 while((msg = GetMsg(peh->peh_MsgPort)))
6227 ReplyMsg(msg);
6229 ReleaseSemaphore(&ps->ps_ReentrantLock);
6230 pGarbageCollectEvents(ps);
6231 psdFreeVec(peh);
6232 AROS_LIBFUNC_EXIT
6234 /* \\\ */
6236 /* /// "psdSendEvent()" */
6237 AROS_LH3(void, psdSendEvent,
6238 AROS_LHA(ULONG, ehmt, D0),
6239 AROS_LHA(APTR, param1, A0),
6240 AROS_LHA(APTR, param2, A1),
6241 LIBBASETYPEPTR, ps, 49, psd)
6243 AROS_LIBFUNC_INIT
6244 struct PsdEventNote *pen;
6245 struct PsdEventHook *peh;
6246 ULONG msgmask = (1L<<ehmt);
6248 KPRINTF(1, ("psdSendEvent(%p, %p, %p)\n", ehmt, param1, param2));
6250 pGarbageCollectEvents(ps);
6251 ObtainSemaphore(&ps->ps_ReentrantLock);
6252 peh = (struct PsdEventHook *) ps->ps_EventHooks.lh_Head;
6253 while(peh->peh_Node.ln_Succ)
6255 if(peh->peh_MsgMask & msgmask)
6257 if((pen = psdAllocVec(sizeof(struct PsdEventNote))))
6259 pen->pen_Msg.mn_ReplyPort = &ps->ps_EventReplyPort;
6260 pen->pen_Msg.mn_Length = sizeof(struct PsdEventNote);
6261 pen->pen_Event = ehmt;
6262 pen->pen_Param1 = param1;
6263 pen->pen_Param2 = param2;
6264 PutMsg(peh->peh_MsgPort, &pen->pen_Msg);
6267 peh = (struct PsdEventHook *) peh->peh_Node.ln_Succ;
6269 ReleaseSemaphore(&ps->ps_ReentrantLock);
6270 AROS_LIBFUNC_EXIT
6272 /* \\\ */
6274 /* *** Configuration *** */
6276 /* /// "psdReadCfg()" */
6277 AROS_LH2(BOOL, psdReadCfg,
6278 AROS_LHA(struct PsdIFFContext *, pic, A0),
6279 AROS_LHA(APTR, formdata, A1),
6280 LIBBASETYPEPTR, ps, 52, psd)
6282 AROS_LIBFUNC_INIT
6283 struct PsdIFFContext *subpic;
6284 LONG len;
6285 ULONG chlen;
6286 ULONG *buf = formdata;
6287 BOOL res = TRUE;
6288 KPRINTF(10, ("psdReadCfg(%p, %p)\n", pic, formdata));
6290 pLockSemExcl(ps, &ps->ps_ConfigLock);
6291 if(!pic)
6293 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6294 if(!(pic->pic_Node.ln_Succ))
6296 pUnlockSem(ps, &ps->ps_ConfigLock);
6297 return(FALSE);
6300 if((AROS_LONG2BE(*buf) != ID_FORM) || (AROS_LONG2BE(buf[2]) != pic->pic_FormID))
6302 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to replace a cfg form with a chunk or with an alien form!");
6303 pUnlockSem(ps, &ps->ps_ConfigLock);
6304 return(FALSE);
6306 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6307 while(subpic->pic_Node.ln_Succ)
6309 pFreeForm(ps, subpic);
6310 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6312 pic->pic_ChunksLen = 0;
6313 len = (AROS_LONG2BE(buf[1]) - 3) & ~1UL;
6314 buf += 3;
6315 while(len >= 8)
6317 if(!(pAddCfgChunk(ps, pic, buf)))
6319 break;
6321 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
6322 len -= chlen;
6323 buf = (ULONG *) (((UBYTE *) buf) + chlen);
6325 if(len)
6327 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
6328 res = 0;
6331 pUnlockSem(ps, &ps->ps_ConfigLock);
6332 ps->ps_CheckConfigReq = TRUE;
6333 return(res);
6334 AROS_LIBFUNC_EXIT
6336 /* \\\ */
6338 /* /// "psdLoadCfgFromDisk()" */
6339 AROS_LH1(BOOL, psdLoadCfgFromDisk,
6340 AROS_LHA(STRPTR, filename, A1),
6341 LIBBASETYPEPTR, ps, 79, psd)
6343 AROS_LIBFUNC_INIT
6344 ULONG *buf;
6345 BOOL loaded = FALSE;
6346 BPTR filehandle;
6347 ULONG formhead[3];
6348 ULONG formlen;
6350 XPRINTF(10, ("Loading config file: %s\n", filename));
6352 if(!filename)
6354 loaded = psdLoadCfgFromDisk("ENV:Sys/poseidon.prefs");
6355 if(loaded)
6357 return(TRUE);
6360 loaded = psdLoadCfgFromDisk("ENVARC:Sys/poseidon.prefs");
6362 return(loaded);
6365 if(!pOpenDOS(ps))
6367 KPRINTF(1, ("dos.library not available yet\n"));
6368 return(FALSE);
6371 filehandle = Open(filename, MODE_OLDFILE);
6372 KPRINTF(1, ("File handle 0x%p\n", filehandle));
6373 if(filehandle)
6375 if(Read(filehandle, formhead, 12) == 12)
6377 KPRINTF(1, ("Read header\n"));
6378 if((AROS_LONG2BE(formhead[0]) == ID_FORM) && (AROS_LONG2BE(formhead[2]) == IFFFORM_PSDCFG))
6380 formlen = AROS_LONG2BE(formhead[1]);
6381 KPRINTF(1, ("Header OK, %lu bytes\n", formlen));
6383 buf = (ULONG *) psdAllocVec(formlen + 8);
6384 if(buf)
6386 buf[0] = formhead[0];
6387 buf[1] = formhead[1];
6388 buf[2] = formhead[2];
6389 if(Read(filehandle, &buf[3], formlen - 4) == formlen - 4)
6391 KPRINTF(1, ("Data read OK\n"));
6393 psdReadCfg(NULL, buf);
6394 psdParseCfg();
6396 KPRINTF(1, ("All done\n"));
6397 loaded = TRUE;
6399 psdFreeVec(buf);
6403 Close(filehandle);
6404 } else {
6405 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6406 "Failed to load config from '%s'!",
6407 filename);
6409 if(loaded)
6411 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6413 return(loaded);
6414 AROS_LIBFUNC_EXIT
6416 /* \\\ */
6418 /* /// "psdSaveCfgToDisk()" */
6419 AROS_LH2(BOOL, psdSaveCfgToDisk,
6420 AROS_LHA(STRPTR, filename, A1),
6421 AROS_LHA(BOOL, executable, D0),
6422 LIBBASETYPEPTR, ps, 80, psd)
6424 AROS_LIBFUNC_INIT
6425 ULONG *buf;
6426 BOOL saved = FALSE;
6427 BPTR filehandle;
6429 if(!filename)
6431 saved = psdSaveCfgToDisk("ENVARC:Sys/poseidon.prefs", FALSE);
6432 saved &= psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE);
6433 return(saved);
6436 if(!pOpenDOS(ps))
6438 return(FALSE);
6440 pLockSemShared(ps, &ps->ps_ConfigLock);
6442 buf = (ULONG *) psdWriteCfg(NULL);
6443 if(buf)
6445 /* Write file */
6446 filehandle = Open(filename, MODE_NEWFILE);
6447 if(filehandle)
6449 Write(filehandle, buf, (AROS_LONG2BE(buf[1])+9) & ~1UL);
6450 Close(filehandle);
6451 saved = TRUE;
6452 } else {
6453 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6454 "Failed to write config to '%s'!",
6455 filename);
6457 psdFreeVec(buf);
6459 pUnlockSem(ps, &ps->ps_ConfigLock);
6460 if(saved)
6462 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6464 return(saved);
6465 AROS_LIBFUNC_EXIT
6467 /* \\\ */
6469 /* /// "psdWriteCfg()" */
6470 AROS_LH1(APTR, psdWriteCfg,
6471 AROS_LHA(struct PsdIFFContext *, pic, A0),
6472 LIBBASETYPEPTR, ps, 53, psd)
6474 AROS_LIBFUNC_INIT
6475 ULONG len;
6476 APTR buf = NULL;
6478 KPRINTF(10, ("psdWriteCfg(%p)\n", pic));
6480 pLockSemShared(ps, &ps->ps_ConfigLock);
6481 if(!pic)
6483 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6484 if(!(pic->pic_Node.ln_Succ))
6486 pUnlockSem(ps, &ps->ps_ConfigLock);
6487 return(NULL);
6490 pUpdateGlobalCfg(ps, pic);
6491 ps->ps_CheckConfigReq = TRUE;
6492 len = pGetFormLength(pic);
6493 if((buf = psdAllocVec(len)))
6495 pInternalWriteForm(pic, buf);
6497 pUnlockSem(ps, &ps->ps_ConfigLock);
6498 return(buf);
6499 AROS_LIBFUNC_EXIT
6501 /* \\\ */
6503 /* /// "psdFindCfgForm()" */
6504 AROS_LH2(struct PsdIFFContext *, psdFindCfgForm,
6505 AROS_LHA(struct PsdIFFContext *, pic, A0),
6506 AROS_LHA(ULONG, formid, D0),
6507 LIBBASETYPEPTR, ps, 54, psd)
6509 AROS_LIBFUNC_INIT
6510 struct PsdIFFContext *subpic;
6512 KPRINTF(160, ("psdFindCfgForm(0x%p, 0x%08lx)\n", pic, formid));
6513 pLockSemShared(ps, &ps->ps_ConfigLock);
6514 if(!pic)
6516 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6517 if(!(pic->pic_Node.ln_Succ))
6519 pUnlockSem(ps, &ps->ps_ConfigLock);
6520 return(NULL);
6523 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6524 while(subpic->pic_Node.ln_Succ)
6526 if(subpic->pic_FormID == formid)
6528 pUnlockSem(ps, &ps->ps_ConfigLock);
6529 return(subpic);
6531 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
6533 pUnlockSem(ps, &ps->ps_ConfigLock);
6534 return(NULL);
6535 AROS_LIBFUNC_EXIT
6537 /* \\\ */
6539 /* /// "psdNextCfgForm()" */
6540 AROS_LH1(struct PsdIFFContext *, psdNextCfgForm,
6541 AROS_LHA(struct PsdIFFContext *, pic, A0),
6542 LIBBASETYPEPTR, ps, 55, psd)
6544 AROS_LIBFUNC_INIT
6545 ULONG formid;
6546 KPRINTF(160, ("psdNextCfgForm(%p)\n", pic));
6548 if(!pic)
6550 return(NULL);
6552 pLockSemShared(ps, &ps->ps_ConfigLock);
6553 formid = pic->pic_FormID;
6554 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6555 while(pic->pic_Node.ln_Succ)
6557 if(pic->pic_FormID == formid)
6559 pUnlockSem(ps, &ps->ps_ConfigLock);
6561 KPRINTF(1, ("Found context 0x%p\n", pic));
6562 return(pic);
6564 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6566 pUnlockSem(ps, &ps->ps_ConfigLock);
6567 return(NULL);
6568 AROS_LIBFUNC_EXIT
6570 /* \\\ */
6572 /* /// "psdAllocCfgForm()" */
6573 AROS_LH1(struct PsdIFFContext *, psdAllocCfgForm,
6574 AROS_LHA(ULONG, formid, D0),
6575 LIBBASETYPEPTR, ps, 86, psd)
6577 AROS_LIBFUNC_INIT
6578 struct PsdIFFContext *pic;
6579 KPRINTF(10, ("psdAllocCfgForm(%p)\n", formid));
6580 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
6582 NewList(&pic->pic_SubForms);
6583 //pic->pic_Parent = parent;
6584 pic->pic_FormID = formid;
6585 pic->pic_FormLength = 4;
6586 pic->pic_Chunks = NULL;
6587 pic->pic_ChunksLen = 0;
6588 pic->pic_BufferLen = 0;
6589 Forbid();
6590 AddTail(&ps->ps_AlienConfigs, &pic->pic_Node);
6591 Permit();
6593 return(pic);
6594 AROS_LIBFUNC_EXIT
6596 /* \\\ */
6598 /* /// "psdRemCfgForm()" */
6599 AROS_LH1(void, psdRemCfgForm,
6600 AROS_LHA(struct PsdIFFContext *, pic, A0),
6601 LIBBASETYPEPTR, ps, 56, psd)
6603 AROS_LIBFUNC_INIT
6604 KPRINTF(10, ("psdRemCfgForm(%p)\n", pic));
6606 pLockSemExcl(ps, &ps->ps_ConfigLock);
6607 if(!pic)
6609 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6610 if(!(pic->pic_Node.ln_Succ))
6612 pUnlockSem(ps, &ps->ps_ConfigLock);
6613 return;
6616 pFreeForm(ps, pic);
6617 pUnlockSem(ps, &ps->ps_ConfigLock);
6618 ps->ps_CheckConfigReq = TRUE;
6619 AROS_LIBFUNC_EXIT
6621 /* \\\ */
6623 /* /// "psdAddCfgEntry()" */
6624 AROS_LH2(struct PsdIFFContext *, psdAddCfgEntry,
6625 AROS_LHA(struct PsdIFFContext *, pic, A0),
6626 AROS_LHA(APTR, formdata, A1),
6627 LIBBASETYPEPTR, ps, 57, psd)
6629 AROS_LIBFUNC_INIT
6630 struct PsdIFFContext *res;
6632 KPRINTF(10, ("psdAddCfgEntry(%p, %p)\n", pic, formdata));
6633 pLockSemExcl(ps, &ps->ps_ConfigLock);
6634 if(!pic)
6636 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6637 if(!(pic->pic_Node.ln_Succ))
6639 pUnlockSem(ps, &ps->ps_ConfigLock);
6640 return(NULL);
6643 res = pAddCfgChunk(ps, pic, formdata);
6644 pUnlockSem(ps, &ps->ps_ConfigLock);
6645 ps->ps_CheckConfigReq = TRUE;
6646 return(res);
6647 AROS_LIBFUNC_EXIT
6649 /* \\\ */
6651 /* /// "psdRemCfgChunk()" */
6652 AROS_LH2(BOOL, psdRemCfgChunk,
6653 AROS_LHA(struct PsdIFFContext *, pic, A0),
6654 AROS_LHA(ULONG, chnkid, D0),
6655 LIBBASETYPEPTR, ps, 58, psd)
6657 AROS_LIBFUNC_INIT
6658 BOOL res = FALSE;
6660 KPRINTF(10, ("psdRemCfgChunk(%p, %p)\n", pic, chnkid));
6661 pLockSemExcl(ps, &ps->ps_ConfigLock);
6662 if(!pic)
6664 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6665 if(!(pic->pic_Node.ln_Succ))
6667 pUnlockSem(ps, &ps->ps_ConfigLock);
6668 return(FALSE);
6671 if(chnkid)
6673 res = pRemCfgChunk(ps, pic, chnkid);
6674 } else {
6675 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6676 while(subpic->pic_Node.ln_Succ)
6678 pFreeForm(ps, subpic);
6679 res = TRUE;
6680 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6682 if(pic->pic_ChunksLen)
6684 res = TRUE;
6686 pic->pic_ChunksLen = 0;
6687 pic->pic_FormLength = 4;
6690 pUnlockSem(ps, &ps->ps_ConfigLock);
6691 ps->ps_CheckConfigReq = TRUE;
6692 return(res);
6693 AROS_LIBFUNC_EXIT
6695 /* \\\ */
6697 /* /// "psdGetCfgChunk()" */
6698 AROS_LH2(APTR, psdGetCfgChunk,
6699 AROS_LHA(struct PsdIFFContext *, pic, A0),
6700 AROS_LHA(ULONG, chnkid, D0),
6701 LIBBASETYPEPTR, ps, 59, psd)
6703 AROS_LIBFUNC_INIT
6704 ULONG *chnk;
6705 ULONG *res = NULL;
6707 KPRINTF(10, ("psdGetCfgChunk(%p, 0x%08lx)\n", pic, chnkid));
6709 pLockSemShared(ps, &ps->ps_ConfigLock);
6710 if(!pic)
6712 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6713 if(!(pic->pic_Node.ln_Succ))
6715 pUnlockSem(ps, &ps->ps_ConfigLock);
6716 return(NULL);
6719 pUpdateGlobalCfg(ps, pic);
6720 chnk = pFindCfgChunk(ps, pic, chnkid);
6721 if(chnk)
6723 res = psdAllocVec(AROS_LONG2BE(chnk[1])+8);
6724 if(res)
6726 memcpy(res, chnk, AROS_LONG2BE(chnk[1])+8);
6729 pUnlockSem(ps, &ps->ps_ConfigLock);
6730 return(res);
6731 AROS_LIBFUNC_EXIT
6733 /* \\\ */
6735 /* /// "psdParseCfg()" */
6736 AROS_LH0(void, psdParseCfg,
6737 LIBBASETYPEPTR, ps, 60, psd)
6739 AROS_LIBFUNC_INIT
6740 struct PsdIFFContext *pic;
6741 struct PsdIFFContext *subpic;
6742 ULONG *chnk;
6743 STRPTR name;
6744 ULONG unit;
6745 struct PsdHardware *phw;
6746 struct PsdUsbClass *puc;
6747 BOOL removeall = TRUE;
6748 BOOL nodos = (FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS);
6749 IPTR restartme;
6751 XPRINTF(10, ("psdParseCfg()\n"));
6753 pLockSemShared(ps, &ps->ps_ConfigLock);
6754 pCheckCfgChanged(ps);
6755 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6756 if(!pic)
6758 pUnlockSem(ps, &ps->ps_ConfigLock);
6759 return;
6762 // if no config for hardware is found, we don't remove the devices,
6763 // because this could render the system useless (no USB mice or
6764 // keyboards to configure the hardware!)
6765 if(!psdFindCfgForm(pic, IFFFORM_UHWDEVICE))
6767 XPRINTF(10, ("No hardware data present\n"));
6768 removeall = FALSE;
6771 psdLockReadPBase();
6773 /* select all hardware devices for removal */
6774 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6775 while(phw->phw_Node.ln_Succ)
6777 phw->phw_RemoveMe = removeall;
6778 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6781 /* select all classes for removal */
6782 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6783 while(puc->puc_Node.ln_Succ)
6786 * For kickstart-resident classes we check usage count, and
6787 * remove them only if it's zero.
6788 * These classes can be responsible for devices which we can use
6789 * at boot time. If we happen to remove them, we can end up with
6790 * no input or storage devices at all.
6792 if (FindResident(puc->puc_ClassName))
6793 puc->puc_RemoveMe = (puc->puc_UseCnt == 0);
6794 else
6795 puc->puc_RemoveMe = TRUE;
6797 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6800 psdUnlockPBase();
6802 /* Get Hardware config */
6803 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6804 while(subpic)
6806 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6807 if(chnk)
6809 name = (STRPTR) &chnk[2];
6810 unit = 0;
6811 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6812 if(chnk)
6814 unit = chnk[2];
6816 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6818 phw = pFindHardware(ps, name, unit);
6819 XPRINTF(5, ("Have configuration for device 0x%p (%s unit %u)\n", phw, name, unit));
6820 if(phw)
6822 phw->phw_RemoveMe = FALSE;
6826 subpic = psdNextCfgForm(subpic);
6829 /* Get Class config */
6830 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6831 while(subpic)
6833 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6834 if(chnk)
6836 name = (STRPTR) &chnk[2];
6837 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6838 XPRINTF(5, ("Have configuration for class 0x%p (%s)\n", puc, name));
6839 if(puc)
6841 puc->puc_RemoveMe = FALSE;
6844 subpic = psdNextCfgForm(subpic);
6847 // unlock config while removing to avoid deadlocks.
6848 pUnlockSem(ps, &ps->ps_ConfigLock);
6850 /* now remove remaining classes not found in the config */
6851 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6852 while(puc->puc_Node.ln_Succ)
6854 if(puc->puc_RemoveMe)
6856 XPRINTF(5, ("Removing class %s\n", puc->puc_ClassName));
6857 psdRemClass(puc);
6858 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6859 } else {
6860 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6864 /* now remove all remaining hardware not found in the config */
6865 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6866 while(phw->phw_Node.ln_Succ)
6868 if(phw->phw_RemoveMe)
6870 XPRINTF(5, ("Removing device %s unit %u\n", phw->phw_DevName, phw->phw_Unit));
6871 psdRemHardware(phw);
6872 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6873 } else {
6874 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6878 pLockSemShared(ps, &ps->ps_ConfigLock);
6879 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6880 if(!pic)
6882 pUnlockSem(ps, &ps->ps_ConfigLock);
6883 // oops!
6884 return;
6887 /* Add missing Classes */
6888 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6889 while(subpic)
6891 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6892 if(chnk)
6894 /* *** FIXME *** POSSIBLE DEADLOCK WHEN CLASS TRIES TO DO CONFIG STUFF IN
6895 AN EXTERNAL TASK INSIDE LIBOPEN CODE */
6896 name = (STRPTR) &chnk[2];
6897 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6898 if(!puc)
6900 psdAddClass(name, 0);
6903 subpic = psdNextCfgForm(subpic);
6906 /* Now really mount Hardware found in config */
6907 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6908 while(subpic)
6910 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6911 if(chnk)
6913 name = (STRPTR) &chnk[2];
6914 unit = 0;
6915 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6916 if(chnk)
6918 unit = chnk[2];
6920 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6922 phw = pFindHardware(ps, name, unit);
6923 if(!phw)
6925 phw = psdAddHardware(name, unit);
6926 if(phw)
6928 #ifdef AROS_USB30_CODE
6929 if(psdEnumerateHardware(phw) == NULL) {
6930 psdRemHardware(phw);
6932 #else
6933 psdEnumerateHardware(phw);
6934 #endif
6939 subpic = psdNextCfgForm(subpic);
6941 pUnlockSem(ps, &ps->ps_ConfigLock);
6943 if(!nodos && ps->ps_StartedAsTask)
6945 // last time we were reading the config before DOS, so maybe we need to
6946 // unbind some classes that need to be overruled by newly available classes,
6947 // such as hid.class overruling bootmouse & bootkeyboard.
6948 // so unbind those classes that promote themselves as AfterDOS
6950 psdLockReadPBase();
6951 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Checking AfterDOS...");
6952 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6953 while(puc->puc_Node.ln_Succ)
6955 restartme = FALSE;
6956 usbGetAttrs(UGA_CLASS, NULL,
6957 UCCA_AfterDOSRestart, &restartme,
6958 TAG_END);
6960 if(restartme && puc->puc_UseCnt)
6962 struct PsdDevice *pd;
6963 struct PsdConfig *pc;
6964 struct PsdInterface *pif;
6966 /* Well, try to release the open bindings in a best effort attempt */
6967 pd = NULL;
6968 while((pd = psdGetNextDevice(pd)))
6970 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
6972 psdUnlockPBase();
6973 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6974 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6975 puc->puc_ClassName, "device", pd->pd_ProductStr);
6976 psdReleaseDevBinding(pd);
6977 psdLockReadPBase();
6978 pd = NULL; /* restart */
6979 continue;
6981 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6982 while(pc->pc_Node.ln_Succ)
6984 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6985 while(pif->pif_Node.ln_Succ)
6987 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
6989 psdUnlockPBase();
6990 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6991 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6992 puc->puc_ClassName, "interface", pd->pd_ProductStr);
6993 psdReleaseIfBinding(pif);
6994 psdLockReadPBase();
6995 pd = NULL; /* restart */
6996 continue;
6998 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
7000 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
7004 usbDoMethodA(UCM_DOSAvailableEvent, NULL);
7005 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
7007 ps->ps_StartedAsTask = FALSE;
7008 psdUnlockPBase();
7011 if(nodos && (!ps->ps_ConfigRead))
7013 // it's the first time we were reading the config and DOS was not available
7014 ps->ps_StartedAsTask = TRUE;
7016 ps->ps_ConfigRead = TRUE;
7017 ps->ps_SavedConfigHash = ps->ps_ConfigHash; // update saved hash
7019 /* do a class scan */
7020 psdClassScan();
7022 if(nodos && ps->ps_GlobalCfg->pgc_BootDelay)
7024 // wait for hubs to settle
7025 psdDelayMS(1000);
7026 puc = (struct PsdUsbClass *) FindName(&ps->ps_Classes, "massstorage.class");
7027 if(puc && puc->puc_UseCnt)
7029 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
7030 "Delaying further execution by %ld second(s) (boot delay).",
7031 ps->ps_GlobalCfg->pgc_BootDelay);
7032 if(ps->ps_GlobalCfg->pgc_BootDelay >= 1)
7034 psdDelayMS((ps->ps_GlobalCfg->pgc_BootDelay-1)*1000);
7036 } else {
7037 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Boot delay skipped, no mass storage devices found.");
7040 AROS_LIBFUNC_EXIT
7042 /* \\\ */
7044 /* /// "psdSetClsCfg()" */
7045 AROS_LH2(BOOL, psdSetClsCfg,
7046 AROS_LHA(STRPTR, owner, A0),
7047 AROS_LHA(APTR, form, A1),
7048 LIBBASETYPEPTR, ps, 62, psd)
7050 AROS_LIBFUNC_INIT
7051 struct PsdIFFContext *pic;
7052 BOOL result = FALSE;
7054 KPRINTF(10, ("psdSetClsCfg(%s, %p)\n", owner, form));
7055 pLockSemExcl(ps, &ps->ps_ConfigLock);
7056 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7057 while(pic)
7059 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7061 pic = psdFindCfgForm(pic, IFFFORM_CLASSDATA);
7062 if(pic)
7064 if(form)
7066 result = psdReadCfg(pic, form);
7067 } else {
7068 psdRemCfgChunk(pic, 0);
7069 result = TRUE;
7071 break;
7072 } else {
7073 break;
7076 pic = psdNextCfgForm(pic);
7078 if(result)
7080 pUnlockSem(ps, &ps->ps_ConfigLock);
7081 pCheckCfgChanged(ps);
7082 return(result);
7084 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7085 if(pic->pic_Node.ln_Succ)
7087 pic = pAllocForm(ps, pic, IFFFORM_CLASSCFG);
7088 if(pic)
7090 if(pAddStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7092 if(form)
7094 if(pAddCfgChunk(ps, pic, form))
7096 pUnlockSem(ps, &ps->ps_ConfigLock);
7097 pCheckCfgChanged(ps);
7098 return(TRUE);
7100 } else {
7101 ULONG buf[3];
7102 buf[0] = AROS_LONG2BE(ID_FORM);
7103 buf[1] = AROS_LONG2BE(4);
7104 buf[2] = AROS_LONG2BE(IFFFORM_CLASSDATA);
7105 if(pAddCfgChunk(ps, pic, buf))
7107 pUnlockSem(ps, &ps->ps_ConfigLock);
7108 pCheckCfgChanged(ps);
7109 return(TRUE);
7115 pUnlockSem(ps, &ps->ps_ConfigLock);
7116 pCheckCfgChanged(ps);
7117 return(FALSE);
7118 AROS_LIBFUNC_EXIT
7120 /* \\\ */
7122 /* /// "psdGetClsCfg()" */
7123 AROS_LH1(struct PsdIFFContext *, psdGetClsCfg,
7124 AROS_LHA(STRPTR, owner, A0),
7125 LIBBASETYPEPTR, ps, 63, psd)
7127 AROS_LIBFUNC_INIT
7128 struct PsdIFFContext *pic;
7130 KPRINTF(10, ("psdGetClsCfg(%s)\n", owner));
7131 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7132 while(pic)
7134 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7136 return(psdFindCfgForm(pic, IFFFORM_CLASSDATA));
7138 pic = psdNextCfgForm(pic);
7140 return(NULL);
7141 AROS_LIBFUNC_EXIT
7143 /* \\\ */
7145 /* /// "psdSetUsbDevCfg()" */
7146 AROS_LH4(BOOL, psdSetUsbDevCfg,
7147 AROS_LHA(STRPTR, owner, A0),
7148 AROS_LHA(STRPTR, devid, A2),
7149 AROS_LHA(STRPTR, ifid, A3),
7150 AROS_LHA(APTR, form, A1),
7151 LIBBASETYPEPTR, ps, 64, psd)
7153 AROS_LIBFUNC_INIT
7154 struct PsdIFFContext *pic;
7155 struct PsdIFFContext *cpic = NULL;
7156 struct PsdIFFContext *mpic = NULL;
7157 BOOL result = FALSE;
7159 KPRINTF(10, ("psdSetUsbDevCfg(%s, %s, %s, %p)\n", owner, devid, ifid, form));
7160 pLockSemExcl(ps, &ps->ps_ConfigLock);
7161 /* Find device config form. It contains all device config data */
7162 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7163 while(pic)
7165 /* Find DEVID-Chunk. Check if it matches our device id */
7166 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7168 cpic = NULL;
7169 /* We found the correct device. Now if we need to store interface data, find the interface first */
7170 if(ifid)
7172 /* Search interface config form */
7173 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7174 while(mpic)
7176 /* Found the form. Find the the ID String for the interface */
7177 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7179 /* ID did match, now check for owner */
7180 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7182 /* found it! So there is already a config saved in there. Search for dev config data form */
7183 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7184 if(!cpic)
7186 /* not found, generate it */
7187 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7189 break;
7192 mpic = psdNextCfgForm(mpic);
7194 if(!cpic)
7196 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7198 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7200 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7202 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7207 } else {
7208 /* Search for device config */
7209 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7210 while(mpic)
7212 /* search for the right owner */
7213 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7215 /* found it! So there is already a config saved in there. Search for dev config data form */
7216 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7217 if(!cpic)
7219 /* not found, generate it */
7220 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7222 break;
7224 mpic = psdNextCfgForm(mpic);
7226 if(!cpic) /* no device config form */
7228 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7230 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7232 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7237 if(cpic)
7239 if(form)
7241 result = psdReadCfg(cpic, form);
7242 } else {
7243 psdRemCfgChunk(cpic, 0);
7244 result = TRUE;
7246 break;
7249 pic = psdNextCfgForm(pic);
7251 if(result)
7253 pUnlockSem(ps, &ps->ps_ConfigLock);
7254 pCheckCfgChanged(ps);
7255 return(result);
7257 cpic = NULL;
7258 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7259 if(pic->pic_Node.ln_Succ)
7261 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7262 if(pic)
7264 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7266 if(ifid)
7268 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7270 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7272 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7274 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7278 } else {
7279 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7281 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7283 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7287 if(cpic)
7289 if(form)
7291 result = psdReadCfg(cpic, form);
7292 } else {
7293 psdRemCfgChunk(cpic, 0);
7294 result = TRUE;
7300 pUnlockSem(ps, &ps->ps_ConfigLock);
7301 pCheckCfgChanged(ps);
7302 return(result);
7303 AROS_LIBFUNC_EXIT
7305 /* \\\ */
7307 /* /// "psdGetUsbDevCfg()" */
7308 AROS_LH3(struct PsdIFFContext *, psdGetUsbDevCfg,
7309 AROS_LHA(STRPTR, owner, A0),
7310 AROS_LHA(STRPTR, devid, A2),
7311 AROS_LHA(STRPTR, ifid, A3),
7312 LIBBASETYPEPTR, ps, 65, psd)
7314 AROS_LIBFUNC_INIT
7315 struct PsdIFFContext *pic;
7316 struct PsdIFFContext *cpic = NULL;
7317 struct PsdIFFContext *mpic = NULL;
7319 KPRINTF(10, ("psdGetUsbDevCfg(%s, %s, %s)\n", owner, devid, ifid));
7320 pLockSemShared(ps, &ps->ps_ConfigLock);
7321 /* Find device config form. It contains all device config data */
7322 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7323 while(pic)
7325 /* Find DEVID-Chunk. Check if it matches our device id */
7326 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7328 cpic = NULL;
7329 /* We found the correct device. Now if we need to store interface data, find the interface first */
7330 if(ifid)
7332 /* Search interface config form */
7333 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7334 while(mpic)
7336 /* Found the form. Find the the ID String for the interface */
7337 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7339 /* ID did match, now check for owner */
7340 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7342 /* found it! So there is already a config saved in there. Search for dev config data form */
7343 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7344 break;
7347 mpic = psdNextCfgForm(mpic);
7349 } else {
7350 /* Search for device config */
7351 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7352 while(mpic)
7354 /* search for the right owner */
7355 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7357 /* found it! So there is already a config saved in there. Search for dev config data form */
7358 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7359 break;
7361 mpic = psdNextCfgForm(mpic);
7364 break;
7366 pic = psdNextCfgForm(pic);
7368 pUnlockSem(ps, &ps->ps_ConfigLock);
7369 KPRINTF(1, ("Result %p\n", cpic));
7370 return(cpic);
7371 AROS_LIBFUNC_EXIT
7373 /* \\\ */
7375 /* /// "psdSetForcedBinding()" */
7376 AROS_LH3(BOOL, psdSetForcedBinding,
7377 AROS_LHA(STRPTR, owner, A2),
7378 AROS_LHA(STRPTR, devid, A0),
7379 AROS_LHA(STRPTR, ifid, A1),
7380 LIBBASETYPEPTR, ps, 69, psd)
7382 AROS_LIBFUNC_INIT
7383 struct PsdIFFContext *pic;
7384 struct PsdIFFContext *mpic = NULL;
7385 ULONG olen = 0;
7386 BOOL result = FALSE;
7388 if(owner)
7390 olen = strlen(owner);
7392 pLockSemExcl(ps, &ps->ps_ConfigLock);
7393 /* Find device config form. It contains all device config data */
7394 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7395 while(pic)
7397 /* Find DEVID-Chunk. Check if it matches our device id */
7398 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7400 /* We found the correct device. Now if we need to store interface data, find the interface first */
7401 if(ifid)
7403 /* Search interface config form */
7404 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7405 while(mpic)
7407 /* Found the form. Find the the ID String for the interface */
7408 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7410 /* ID did match, insert/replace forced binding */
7411 if(olen)
7413 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7415 result = TRUE;
7417 } else {
7418 pRemCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7419 result = TRUE;
7422 mpic = psdNextCfgForm(mpic);
7424 if(!olen)
7426 result = TRUE;
7428 if((!result) && olen)
7430 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7432 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7434 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7436 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7438 result = TRUE;
7444 } else {
7445 /* Add FBND chunk */
7446 if(olen)
7448 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7450 result = TRUE;
7452 } else {
7453 pRemCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7454 result = TRUE;
7457 break;
7459 pic = psdNextCfgForm(pic);
7461 if(!olen)
7463 result = TRUE;
7465 if(result)
7467 pUnlockSem(ps, &ps->ps_ConfigLock);
7468 pCheckCfgChanged(ps);
7469 return(result);
7471 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7472 if(pic->pic_Node.ln_Succ)
7474 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7475 if(pic)
7477 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7479 if(ifid)
7481 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7483 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7485 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7487 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7489 result = TRUE;
7494 } else {
7495 /* Add FBND chunk */
7496 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7498 result = TRUE;
7504 pUnlockSem(ps, &ps->ps_ConfigLock);
7505 pCheckCfgChanged(ps);
7506 return(result);
7507 AROS_LIBFUNC_EXIT
7509 /* \\\ */
7511 /* /// "psdGetForcedBinding()" */
7512 AROS_LH2(STRPTR, psdGetForcedBinding,
7513 AROS_LHA(STRPTR, devid, A0),
7514 AROS_LHA(STRPTR, ifid, A1),
7515 LIBBASETYPEPTR, ps, 70, psd)
7517 AROS_LIBFUNC_INIT
7518 struct PsdIFFContext *pic;
7519 struct PsdIFFContext *mpic = NULL;
7520 ULONG *chunk;
7521 STRPTR owner = NULL;
7523 pLockSemShared(ps, &ps->ps_ConfigLock);
7524 /* Find device config form. It contains all device config data */
7525 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7526 while(pic)
7528 /* Find DEVID-Chunk. Check if it matches our device id */
7529 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7531 /* We found the correct device. Now if we need to store interface data, find the interface first */
7532 if(ifid)
7534 /* Search interface config form */
7535 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7536 while(mpic)
7538 /* Found the form. Find the the ID String for the interface */
7539 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7541 /* ID did match, now check for forced binding */
7542 chunk = pFindCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7543 if(chunk)
7545 owner = (STRPTR) &chunk[2];
7546 break;
7549 mpic = psdNextCfgForm(mpic);
7551 } else {
7552 /* Search for device forced binding */
7553 chunk = pFindCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7554 if(chunk)
7556 owner = (STRPTR) &chunk[2];
7557 break;
7560 break;
7562 pic = psdNextCfgForm(pic);
7564 pUnlockSem(ps, &ps->ps_ConfigLock);
7565 return(owner);
7566 AROS_LIBFUNC_EXIT
7568 /* \\\ */
7570 /* /// "psdAddStringChunk()" */
7571 AROS_LH3(BOOL, psdAddStringChunk,
7572 AROS_LHA(struct PsdIFFContext *, pic, A0),
7573 AROS_LHA(ULONG, chunkid, D0),
7574 AROS_LHA(CONST_STRPTR, str, A1),
7575 LIBBASETYPEPTR, ps, 87, psd)
7577 AROS_LIBFUNC_INIT
7578 BOOL res;
7579 KPRINTF(10, ("psdAddStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7580 pLockSemExcl(ps, &ps->ps_ConfigLock);
7581 res = pAddStringChunk(ps, pic, chunkid, str);
7582 pUnlockSem(ps, &ps->ps_ConfigLock);
7583 return(res);
7584 AROS_LIBFUNC_EXIT
7586 /* \\\ */
7588 /* /// "psdMatchStringChunk()" */
7589 AROS_LH3(BOOL, psdMatchStringChunk,
7590 AROS_LHA(struct PsdIFFContext *, pic, A0),
7591 AROS_LHA(ULONG, chunkid, D0),
7592 AROS_LHA(CONST_STRPTR, str, A1),
7593 LIBBASETYPEPTR, ps, 88, psd)
7595 AROS_LIBFUNC_INIT
7596 BOOL res;
7597 KPRINTF(10, ("psdMatchStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7598 pLockSemShared(ps, &ps->ps_ConfigLock);
7599 res = pMatchStringChunk(ps, pic, chunkid, str);
7600 pUnlockSem(ps, &ps->ps_ConfigLock);
7601 return(res);
7602 AROS_LIBFUNC_EXIT
7604 /* \\\ */
7606 /* /// "psdGetStringChunk()" */
7607 AROS_LH2(STRPTR, psdGetStringChunk,
7608 AROS_LHA(struct PsdIFFContext *, pic, A0),
7609 AROS_LHA(ULONG, chunkid, D0),
7610 LIBBASETYPEPTR, ps, 89, psd)
7612 AROS_LIBFUNC_INIT
7613 STRPTR str;
7614 KPRINTF(10, ("psdGetStringChunk(%p, %p)\n", pic, chunkid));
7615 pLockSemShared(ps, &ps->ps_ConfigLock);
7616 str = pGetStringChunk(ps, pic, chunkid);
7617 pUnlockSem(ps, &ps->ps_ConfigLock);
7618 return(str);
7619 AROS_LIBFUNC_EXIT
7621 /* \\\ */
7623 /* *** Configuration (non-library subroutines) *** */
7625 /* /// "pAllocForm()" */
7626 struct PsdIFFContext * pAllocForm(LIBBASETYPEPTR ps, struct PsdIFFContext *parent, ULONG formid)
7628 struct PsdIFFContext *pic;
7629 KPRINTF(10, ("pAllocForm(%p, %p)\n", parent, formid));
7630 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
7632 NewList(&pic->pic_SubForms);
7633 //pic->pic_Parent = parent;
7634 pic->pic_FormID = formid;
7635 pic->pic_FormLength = 4;
7636 pic->pic_Chunks = NULL;
7637 pic->pic_ChunksLen = 0;
7638 pic->pic_BufferLen = 0;
7639 Forbid();
7640 if(parent)
7642 AddTail(&parent->pic_SubForms, &pic->pic_Node);
7643 } else {
7644 AddTail(&ps->ps_ConfigRoot, &pic->pic_Node);
7646 Permit();
7648 return(pic);
7650 /* \\\ */
7652 /* /// "pFreeForm()" */
7653 void pFreeForm(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7655 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7656 KPRINTF(10, ("pFreeForm(%p)\n", pic));
7657 Remove(&pic->pic_Node);
7658 while(subpic->pic_Node.ln_Succ)
7660 pFreeForm(ps, subpic);
7661 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7663 psdFreeVec(pic->pic_Chunks);
7664 psdFreeVec(pic);
7666 /* \\\ */
7668 /* /// "pGetFormLength()" */
7669 ULONG pGetFormLength(struct PsdIFFContext *pic)
7671 ULONG len = (5 + pic->pic_ChunksLen) & ~1UL;
7672 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7673 //KPRINTF(10, ("pGetFormLength(%p)\n", pic));
7674 while(subpic->pic_Node.ln_Succ)
7676 len += pGetFormLength(subpic);
7677 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7679 pic->pic_FormLength = len;
7680 //KPRINTF(10, ("FormLen=%ld\n", len+8));
7681 return(len + 8);
7683 /* \\\ */
7685 /* /// "pFindCfgChunk()" */
7686 APTR pFindCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7688 ULONG *buf = pic->pic_Chunks;
7689 ULONG len = pic->pic_ChunksLen;
7690 ULONG chlen;
7691 KPRINTF(10, ("pFindCfgChunk(%p, %p)\n", pic, chnkid));
7693 while(len)
7695 if(AROS_LONG2BE(*buf) == chnkid)
7697 KPRINTF(10, ("Found at %p\n", buf));
7698 return(buf);
7700 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7701 len -= chlen;
7702 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7704 KPRINTF(10, ("Not found!\n"));
7705 return(NULL);
7707 /* \\\ */
7709 /* /// "pRemCfgChunk()" */
7710 BOOL pRemCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7712 ULONG *buf = pic->pic_Chunks;
7713 ULONG len = pic->pic_ChunksLen;
7714 ULONG chlen;
7715 KPRINTF(10, ("pRemCfgChunk(%p, %p)\n", pic, chnkid));
7717 while(len)
7719 chlen = ((AROS_LONG2BE(buf[1])) + 9) & ~1UL;
7720 if(AROS_LONG2BE(*buf) == chnkid)
7722 len -= chlen;
7723 if(len)
7725 memcpy(buf, &((UBYTE *) buf)[chlen], (size_t) len);
7727 pic->pic_ChunksLen -= chlen;
7728 KPRINTF(10, ("Deleted %ld bytes to %ld chunk len\n", chlen, pic->pic_ChunksLen));
7729 return(TRUE);
7731 len -= chlen;
7732 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7734 KPRINTF(10, ("Not found!\n"));
7735 return(FALSE);
7737 /* \\\ */
7739 /* /// "pAddCfgChunk()" */
7740 struct PsdIFFContext * pAddCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, APTR chunk)
7742 LONG len;
7743 LONG chlen;
7744 ULONG *buf = chunk;
7745 ULONG *newbuf;
7746 struct PsdIFFContext *subpic;
7747 KPRINTF(10, ("pAddCfgChunk(%p, %p)\n", pic, chunk));
7748 if(AROS_LONG2BE(*buf) == ID_FORM)
7750 buf++;
7751 len = ((AROS_LONG2BE(*buf)) - 3) & ~1UL;
7752 buf++;
7753 if((subpic = pAllocForm(ps, pic, AROS_LONG2BE(*buf))))
7755 buf++;
7756 while(len >= 8)
7758 if(!(pAddCfgChunk(ps, subpic, buf)))
7760 break;
7762 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7763 len -= chlen;
7764 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7766 if(len)
7768 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
7769 return(NULL);
7771 } else {
7772 return(NULL);
7774 return(subpic);
7775 } else {
7776 pRemCfgChunk(ps, pic, AROS_LONG2BE(*buf));
7777 len = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7778 if(pic->pic_ChunksLen+len > pic->pic_BufferLen)
7780 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));
7782 /* Expand buffer */
7783 if((newbuf = psdAllocVec((pic->pic_ChunksLen+len)<<1)))
7785 if(pic->pic_ChunksLen)
7787 memcpy(newbuf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7788 psdFreeVec(pic->pic_Chunks);
7790 pic->pic_Chunks = newbuf;
7791 pic->pic_BufferLen = (pic->pic_ChunksLen+len)<<1;
7792 } else {
7793 return(NULL);
7796 memcpy(&(((UBYTE *) pic->pic_Chunks)[pic->pic_ChunksLen]), chunk, (size_t) len);
7797 pic->pic_ChunksLen += len;
7798 return(pic);
7801 /* \\\ */
7803 /* /// "pInternalWriteForm()" */
7804 ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf)
7806 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7807 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7808 *buf++ = AROS_LONG2BE(ID_FORM);
7809 *buf++ = AROS_LONG2BE(pic->pic_FormLength);
7810 *buf++ = AROS_LONG2BE(pic->pic_FormID);
7811 if(pic->pic_ChunksLen)
7813 memcpy(buf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7814 buf = (ULONG *) (((UBYTE *) buf) + pic->pic_ChunksLen);
7816 while(subpic->pic_Node.ln_Succ)
7818 buf = pInternalWriteForm(subpic, buf);
7819 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7821 return(buf);
7823 /* \\\ */
7825 /* /// "pCalcCfgCRC()" */
7826 ULONG pCalcCfgCRC(struct PsdIFFContext *pic)
7828 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7829 ULONG len;
7830 ULONG crc = pic->pic_FormID;
7831 UWORD *ptr;
7833 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7834 if(pic->pic_ChunksLen)
7836 len = pic->pic_ChunksLen>>1;
7837 if(len)
7839 ptr = (UWORD *) pic->pic_Chunks;
7842 crc = ((crc<<1)|(crc>>31))^(*ptr++);
7843 } while(--len);
7846 while(subpic->pic_Node.ln_Succ)
7848 crc ^= pCalcCfgCRC(subpic);
7849 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7851 return(crc);
7853 /* \\\ */
7855 /* /// "pCheckCfgChanged()" */
7856 BOOL pCheckCfgChanged(LIBBASETYPEPTR ps)
7858 ULONG crc;
7859 struct PsdIFFContext *pic;
7860 struct PsdIFFContext *subpic;
7861 STRPTR tmpstr;
7863 pLockSemShared(ps, &ps->ps_ConfigLock);
7864 ps->ps_CheckConfigReq = FALSE;
7865 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7866 if(!(pic->pic_Node.ln_Succ))
7868 pUnlockSem(ps, &ps->ps_ConfigLock);
7869 return(FALSE);
7871 crc = pCalcCfgCRC(pic);
7872 if(crc != ps->ps_ConfigHash)
7874 ULONG *chnk;
7875 ps->ps_ConfigHash = crc;
7876 /* Get Global config */
7877 if((subpic = psdFindCfgForm(pic, IFFFORM_STACKCFG)))
7879 if((chnk = pFindCfgChunk(ps, subpic, IFFCHNK_GLOBALCFG)))
7881 CopyMem(&chnk[2], ((UBYTE *) ps->ps_GlobalCfg) + 8, min(AROS_LONG2BE(chnk[1]), AROS_LONG2BE(ps->ps_GlobalCfg->pgc_Length)));
7883 if(!pMatchStringChunk(ps, subpic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile))
7885 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_INSERTSND)))
7887 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
7888 ps->ps_PoPo.po_InsertSndFile = tmpstr;
7891 if(!pMatchStringChunk(ps, subpic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile))
7893 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_REMOVESND)))
7895 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
7896 ps->ps_PoPo.po_RemoveSndFile = tmpstr;
7900 pUnlockSem(ps, &ps->ps_ConfigLock);
7901 psdSendEvent(EHMB_CONFIGCHG, NULL, NULL);
7902 return(TRUE);
7904 pUnlockSem(ps, &ps->ps_ConfigLock);
7905 return(FALSE);
7907 /* \\\ */
7909 /* /// "pAddStringChunk()" */
7910 BOOL pAddStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7912 BOOL res = FALSE;
7913 ULONG len = strlen(str);
7914 ULONG *chnk = (ULONG *) psdAllocVec((ULONG) len+8+2);
7915 if(chnk)
7917 chnk[0] = AROS_LONG2BE(chunkid);
7918 chnk[1] = AROS_LONG2BE(len+1);
7919 strcpy((STRPTR) &chnk[2], str);
7920 if(pAddCfgChunk(ps, pic, chnk))
7922 res = TRUE;
7924 psdFreeVec(chnk);
7926 return(res);
7928 /* \\\ */
7930 /* /// "pMatchStringChunk()" */
7931 BOOL pMatchStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7933 ULONG *chunk;
7934 ULONG len;
7935 STRPTR srcptr;
7936 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7938 srcptr = (STRPTR) &chunk[2];
7939 len = AROS_LONG2BE(chunk[1]);
7940 while(len-- && *srcptr)
7942 if(*str++ != *srcptr++)
7944 return(FALSE);
7947 if(!*str)
7949 return(TRUE);
7952 return(FALSE);
7954 /* \\\ */
7956 /* /// "pGetStringChunk()" */
7957 STRPTR pGetStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid)
7959 ULONG *chunk;
7960 STRPTR str;
7961 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7963 if((str = (STRPTR) psdAllocVec(AROS_LONG2BE(chunk[1]) + 1)))
7965 memcpy(str, &chunk[2], (size_t) AROS_LONG2BE(chunk[1]));
7966 return(str);
7969 return(NULL);
7971 /* \\\ */
7973 /* /// "pUpdateGlobalCfg()" */
7974 void pUpdateGlobalCfg(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7976 struct PsdIFFContext *tmppic;
7977 /* Set Global config */
7978 if(pic == (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head)
7980 if((tmppic = psdFindCfgForm(NULL, IFFFORM_STACKCFG)))
7982 pAddCfgChunk(ps, tmppic, ps->ps_GlobalCfg);
7983 pAddStringChunk(ps, tmppic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile);
7984 pAddStringChunk(ps, tmppic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile);
7988 /* \\\ */
7990 /* *** Misc (non library functions) ***/
7992 /* /// "pGetDevConfig()" */
7993 BOOL pGetDevConfig(struct PsdPipe *pp)
7995 struct PsdDevice *pd = pp->pp_Device;
7996 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
7997 UBYTE *tempbuf;
7998 struct UsbStdCfgDesc uscd;
7999 ULONG len;
8000 LONG ioerr;
8001 STRPTR classname;
8002 UWORD curcfg = 0;
8004 KPRINTF(1, ("Getting configuration descriptor...\n"));
8005 psdLockWriteDevice(pd);
8006 while(curcfg < pd->pd_NumCfgs)
8008 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
8009 USR_GET_DESCRIPTOR, (UDT_CONFIGURATION<<8)|curcfg, 0);
8011 /*tempbuf = psdAllocVec(256);
8012 ioerr = psdDoPipe(pp, tempbuf, 34);
8013 if(ioerr == UHIOERR_RUNTPACKET)
8015 ioerr = 0;
8017 memcpy(&uscd, tempbuf, 9);*/
8018 ioerr = psdDoPipe(pp, &uscd, 9);//sizeof(struct UsbStdCfgDesc));
8019 if(!ioerr)
8021 KPRINTF(1, ("Config type: %ld\n", (ULONG) uscd.bDescriptorType));
8022 len = (ULONG) AROS_WORD2LE(uscd.wTotalLength);
8023 KPRINTF(1, ("Configsize %ld, total size %ld\n", (ULONG) uscd.bLength, len));
8024 if((tempbuf = psdAllocVec(len)))
8025 //if(1)
8027 KPRINTF(1, ("Getting whole configuration descriptor...\n"));
8028 ioerr = psdDoPipe(pp, tempbuf, len);
8029 if(!ioerr)
8031 struct PsdConfig *pc = NULL;
8032 struct PsdInterface *pif = NULL;
8033 struct PsdInterface *altif = NULL;
8034 struct PsdEndpoint *pep = NULL;
8035 struct PsdDescriptor *pdd = NULL;
8036 UBYTE *dbuf = tempbuf;
8037 UBYTE *bufend;
8038 ULONG dlen;
8039 bufend = &dbuf[len];
8040 while(dbuf < bufend)
8042 dlen = dbuf[0]; /* bLength */
8043 if(dlen < 2)
8045 break;
8047 if(&dbuf[dlen] > bufend)
8049 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "End of descriptor past buffer!");
8051 switch(dbuf[1]) /* bDescriptorType */
8053 case UDT_CONFIGURATION:
8055 struct UsbStdCfgDesc *usc = (struct UsbStdCfgDesc *) dbuf;
8056 pif = NULL;
8057 altif = NULL;
8058 pep = NULL;
8059 if((pc = pAllocConfig(pd)))
8061 pd->pd_Flags |= PDFF_CONFIGURED;
8062 pc->pc_NumIfs = usc->bNumInterfaces;
8063 pc->pc_CfgNum = usc->bConfigurationValue;
8064 pc->pc_Attr = usc->bmAttributes;
8065 pc->pc_MaxPower = usc->bMaxPower<<1;
8066 pc->pc_CfgStr = 0;
8067 KPRINTF(1, (" Config %ld\n", pc->pc_CfgNum));
8068 if(usc->iConfiguration)
8070 pc->pc_CfgStr = psdGetStringDescriptor(pp, usc->iConfiguration);
8072 if(!pc->pc_CfgStr)
8074 pc->pc_CfgStr = psdCopyStrFmt("Configuration %ld", pc->pc_CfgNum);
8076 } else {
8077 KPRINTF(20, (" Config allocation failed\n"));
8079 break;
8082 case UDT_INTERFACE:
8084 struct UsbStdIfDesc *usif = (struct UsbStdIfDesc *) dbuf;
8085 pep = NULL;
8086 if(pc)
8088 if((altif = pAllocInterface(pc)))
8090 altif->pif_IfNum = usif->bInterfaceNumber;
8091 altif->pif_Alternate = usif->bAlternateSetting;
8092 altif->pif_NumEPs = usif->bNumEndpoints;
8093 altif->pif_IfClass = usif->bInterfaceClass;
8094 altif->pif_IfSubClass = usif->bInterfaceSubClass;
8095 altif->pif_IfProto = usif->bInterfaceProtocol;
8096 KPRINTF(2, (" Interface %ld\n", altif->pif_IfNum));
8097 if(usif->iInterface)
8099 altif->pif_IfStr = psdGetStringDescriptor(pp, usif->iInterface);
8101 if(!altif->pif_IfStr)
8103 classname = psdNumToStr(NTS_CLASSCODE, (LONG) altif->pif_IfClass, NULL);
8104 if(classname)
8106 altif->pif_IfStr = psdCopyStrFmt("%s interface (%ld)", classname, altif->pif_IfNum);
8107 } else {
8108 altif->pif_IfStr = psdCopyStrFmt("Interface %ld", altif->pif_IfNum);
8111 KPRINTF(2, (" IfName : %s\n"
8112 " Alternate : %ld\n"
8113 " NumEPs : %ld\n"
8114 " IfClass : %ld\n"
8115 " IfSubClass: %ld\n"
8116 " IfProto : %ld\n",
8117 altif->pif_IfStr, altif->pif_Alternate,
8118 altif->pif_NumEPs,
8119 altif->pif_IfClass,
8120 altif->pif_IfSubClass, altif->pif_IfProto));
8121 if(pc->pc_CfgNum == 1)
8123 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx",
8124 altif->pif_IfNum, altif->pif_Alternate,
8125 altif->pif_IfClass, altif->pif_IfSubClass,
8126 altif->pif_IfProto);
8127 } else {
8128 // for more than one config, add config number (retain backwards compatibility with most devices)
8129 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx-%02lx",
8130 pc->pc_CfgNum,
8131 altif->pif_IfNum, altif->pif_Alternate,
8132 altif->pif_IfClass, altif->pif_IfSubClass,
8133 altif->pif_IfProto);
8136 /* Move the interface to the alternatives if possible */
8137 if(altif->pif_Alternate)
8139 if(!pif)
8141 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Alternate interface without prior main interface!");
8142 KPRINTF(20, (" Alternate interface without prior main interface\n"));
8143 pif = altif;
8144 } else {
8145 Remove(&altif->pif_Node);
8146 AddTail(&pif->pif_AlterIfs, &altif->pif_Node);
8147 altif->pif_ParentIf = pif;
8149 } else {
8150 altif->pif_ParentIf = NULL;
8151 pif = altif;
8153 } else {
8154 KPRINTF(20, (" Interface allocation failed\n"));
8156 } else {
8157 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Interface without prior config descriptor!");
8158 KPRINTF(20, (" Interface descriptor without Config\n"));
8160 break;
8163 case UDT_ENDPOINT:
8165 struct UsbStdEPDesc *usep = (struct UsbStdEPDesc *) dbuf;
8166 if(altif)
8168 if((pep = pAllocEndpoint(altif)))
8170 STRPTR eptype;
8171 pep->pep_EPNum = usep->bEndpointAddress & 0x0f;
8172 pep->pep_Direction = usep->bEndpointAddress>>7;
8173 pep->pep_TransType = usep->bmAttributes & 0x03;
8174 pep->pep_SyncType = (usep->bmAttributes>>2) & 0x03;
8175 pep->pep_UsageType = (usep->bmAttributes>>4) & 0x03;
8176 eptype = (pep->pep_TransType == USEAF_INTERRUPT) ? "int" : "iso";
8178 pep->pep_MaxPktSize = AROS_WORD2LE(usep->wMaxPacketSize) & 0x07ff;
8179 pep->pep_NumTransMuFr = ((AROS_WORD2LE(usep->wMaxPacketSize)>>11) & 3) + 1;
8180 if(pep->pep_NumTransMuFr == 4)
8182 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains illegal Num Trans �Frame value!");
8183 pep->pep_NumTransMuFr = 1;
8186 pep->pep_Interval = usep->bInterval;
8187 if(pd->pd_Flags & PDFF_HIGHSPEED)
8189 switch(pep->pep_TransType)
8191 case USEAF_CONTROL:
8192 case USEAF_BULK:
8193 //pep->pep_Interval = 0; // no use here, NAK rate not of interest
8194 break;
8196 case USEAF_ISOCHRONOUS:
8197 if(pep->pep_MaxPktSize > 1024)
8199 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8200 "Endpoint contains %s (%ld) MaxPktSize value!",
8201 (STRPTR) "too high", pep->pep_MaxPktSize);
8202 pep->pep_MaxPktSize = 1024;
8205 case USEAF_INTERRUPT:
8206 if(!pep->pep_Interval)
8208 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8209 "%sspeed %s endpoint contains %s interval value! Fixing.",
8210 (STRPTR) "High", eptype, (STRPTR) "zero");
8211 pep->pep_Interval = 1;
8213 else if(pep->pep_Interval > 16)
8215 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8216 "%sspeed %s endpoint contains %s interval value! Fixing.",
8217 (STRPTR) "High", eptype, (STRPTR) "too high");
8218 pep->pep_Interval = 16;
8220 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8221 break;
8224 else if(pd->pd_Flags & PDFF_LOWSPEED)
8226 switch(pep->pep_TransType)
8228 case USEAF_INTERRUPT:
8229 if(pep->pep_Interval < 8)
8231 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8232 (STRPTR) "Low", eptype, (STRPTR) "too low");
8233 pep->pep_Interval = 8;
8235 break;
8237 case USEAF_CONTROL:
8238 case USEAF_BULK:
8239 pep->pep_Interval = 0; // no use here
8240 break;
8242 case USEAF_ISOCHRONOUS:
8243 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Lowspeed devices cannot have isochronous endpoints!");
8244 break;
8246 } else {
8247 switch(pep->pep_TransType)
8249 case USEAF_INTERRUPT:
8250 if(!pep->pep_Interval)
8252 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8253 (STRPTR) "Full", eptype, (STRPTR) "zero");
8254 pep->pep_Interval = 1;
8256 break;
8258 case USEAF_CONTROL:
8259 case USEAF_BULK:
8260 pep->pep_Interval = 0; // no use here
8261 break;
8263 case USEAF_ISOCHRONOUS:
8264 if(pep->pep_MaxPktSize > 1023)
8266 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains too high (%ld) MaxPktSize value! Fixing.", pep->pep_MaxPktSize);
8267 pep->pep_MaxPktSize = 1023;
8269 if(!pep->pep_Interval)
8271 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8272 (STRPTR) "Full", eptype, (STRPTR) "zero");
8273 pep->pep_Interval = 1;
8275 else if(pep->pep_Interval > 16)
8277 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8278 (STRPTR) "Full", eptype, (STRPTR) "too high");
8279 pep->pep_Interval = 16;
8281 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8282 break;
8286 KPRINTF(2, (" Endpoint %ld\n", pep->pep_EPNum));
8287 KPRINTF(2, (" Direction : %s\n"
8288 " TransType : %ld\n"
8289 " MaxPktSize: %ld\n"
8290 " Interval : %ld\n",
8291 (pep->pep_Direction ? "IN" : "OUT"),
8292 pep->pep_TransType, pep->pep_MaxPktSize,
8293 pep->pep_Interval));
8295 } else {
8296 KPRINTF(20, (" Endpoint allocation failed\n"));
8298 } else {
8299 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint without prior interface descriptor!");
8300 KPRINTF(20, (" Endpoint descriptor without Interface\n"));
8302 break;
8305 case UDT_DEVICE:
8306 case UDT_HUB:
8307 case UDT_HID:
8308 case UDT_REPORT:
8309 case UDT_PHYSICAL:
8310 case UDT_CS_INTERFACE:
8311 case UDT_CS_ENDPOINT:
8312 case UDT_DEVICE_QUALIFIER:
8313 case UDT_OTHERSPEED_QUALIFIER:
8314 case UDT_INTERFACE_POWER:
8315 case UDT_OTG:
8316 //psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping descriptor %02lx (pc=%p, pif=%p altpif=%p).", dbuf[1], pc, pif, altif);
8317 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8318 break;
8320 default:
8321 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping unknown descriptor %02lx.", dbuf[1]);
8322 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8323 break;
8325 // add descriptor to device
8326 pdd = pAllocDescriptor(pd, dbuf);
8327 if(pdd)
8329 STRPTR descname = NULL;
8331 pdd->pdd_Config = pc;
8332 pdd->pdd_Interface = altif;
8333 pdd->pdd_Endpoint = pep;
8334 if(pdd->pdd_Interface)
8336 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
8338 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8339 if(!descname)
8341 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8344 if(!descname)
8346 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8348 if(!descname)
8350 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8353 if(descname)
8355 pdd->pdd_Name = descname;
8358 dbuf += dlen;
8360 KPRINTF(1, ("Configuration acquired!\n"));
8361 psdFreeVec(tempbuf);
8362 curcfg++;
8363 continue;
8364 //psdUnlockDevice(pd);
8365 //return(TRUE);
8366 } else {
8367 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8368 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8369 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8370 KPRINTF(15, ("GET_DESCRIPTOR failed %ld!\n", ioerr));
8372 psdFreeVec(tempbuf);
8373 } else {
8374 KPRINTF(20, ("No memory for %ld bytes config temp buffer!\n", len));
8376 } else {
8377 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8378 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8379 9, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8380 KPRINTF(15, ("GET_DESCRIPTOR (9) failed %ld!\n", ioerr));
8382 psdUnlockDevice(pd);
8383 return(FALSE);
8385 psdUnlockDevice(pd);
8386 return(TRUE);
8388 /* \\\ */
8390 /* /// "pPowerRecurseDrain()" */
8391 ULONG pPowerRecurseDrain(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8393 struct PsdDevice *nextpd;
8394 struct PsdConfig *pc;
8395 UWORD maxdrain = 666;
8396 UWORD childdrain;
8397 BOOL selfpwd = TRUE;
8398 pd->pd_PowerDrain = 0;
8400 /* look at config */
8401 if((pc = pd->pd_CurrentConfig))
8404 /* if suspended, no more than 500�A are drained */
8405 if(pd->pd_Flags & PDFF_SUSPENDED)
8407 pd->pd_PowerDrain = (pc->pc_MaxPower >= 100) ? 3 : 1;
8408 return(pd->pd_PowerDrain);
8410 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8411 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8412 maxdrain = selfpwd ? 500 : 100;
8415 /* examine children */
8416 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8417 while(nextpd->pd_Node.ln_Succ)
8419 if(nextpd->pd_Hub == pd)
8421 childdrain = pPowerRecurseDrain(ps, nextpd);
8422 // limit the drain to the maximum power suckage
8423 pd->pd_PowerDrain += (childdrain > maxdrain) ? maxdrain : childdrain;
8425 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8428 /* look at config */
8429 if(selfpwd)
8431 pd->pd_PowerDrain = 0;
8432 } else {
8433 pd->pd_PowerDrain += pc->pc_MaxPower;
8435 return(pd->pd_PowerDrain);
8437 /* \\\ */
8439 /* /// "pPowerRecurseSupply()" */
8440 void pPowerRecurseSupply(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8442 struct PsdDevice *nextpd;
8443 struct PsdConfig *pc;
8444 UWORD ports = 0;
8445 UWORD supply = 666;
8446 BOOL selfpwd = TRUE;
8448 /* look at config */
8449 if((pc = pd->pd_CurrentConfig))
8451 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8452 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8455 /* count children */
8456 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8457 while(nextpd->pd_Node.ln_Succ)
8459 if(nextpd->pd_Hub == pd) // this device is a child of us (we're a hub!)
8461 ports++;
8463 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8466 /* look at config */
8467 if(selfpwd)
8469 if(pc)
8471 pd->pd_PowerSupply = ports ? 500*ports + pc->pc_MaxPower : pc->pc_MaxPower;
8473 supply = 500; // each downstream port gets the full monty
8474 } else {
8475 // the parent hub has already set the amount of supply for this port
8476 if(pd->pd_PowerSupply >= pc->pc_MaxPower)
8478 // the downstream ports get the remaining divided attention
8479 if(ports)
8481 // avoid division by zero
8482 supply = (pd->pd_PowerSupply - pc->pc_MaxPower) / ports;
8483 if(supply > 100)
8485 // limit to 100 mA per port
8486 supply = 100;
8489 } else {
8490 supply = 1; // bad luck, out of power
8494 /* set supply */
8495 if(ports) /* needs to be a hub */
8497 // propagate supply down to the children
8498 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8499 while(nextpd->pd_Node.ln_Succ)
8501 if(nextpd->pd_Hub == pd)
8503 nextpd->pd_PowerSupply = supply;
8504 pPowerRecurseSupply(ps, nextpd);
8506 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8509 if(pd->pd_PowerDrain > pd->pd_PowerSupply)
8511 if(!(pd->pd_Flags & PDFF_LOWPOWER))
8513 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8514 "Detected low power condition for '%s'.", pd->pd_ProductStr);
8515 pd->pd_Flags |= PDFF_LOWPOWER;
8516 psdSendEvent(EHMB_DEVICELOWPW, pd, NULL);
8518 } else {
8519 if(pd->pd_Flags & PDFF_LOWPOWER)
8521 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
8522 "Low power condition resolved for '%s'.", pd->pd_ProductStr);
8523 pd->pd_Flags &= ~PDFF_LOWPOWER;
8527 /* \\\ */
8529 /* /// "pGarbageCollectEvents()" */
8530 void pGarbageCollectEvents(LIBBASETYPEPTR ps)
8532 struct PsdEventNote *pen;
8533 while((pen = (struct PsdEventNote *) GetMsg(&ps->ps_EventReplyPort)))
8535 psdFreeVec(pen);
8538 /* \\\ */
8540 /* /// "pFindName()" */
8541 struct Node * pFindName(LIBBASETYPEPTR ps, struct List *list, STRPTR name)
8543 struct Node *res = NULL;
8545 Forbid();
8546 while(*name)
8548 res = FindName(list, name);
8549 if(res)
8551 break;
8555 if((*name == '/') || (*name == ':'))
8557 ++name;
8558 break;
8560 } while(*(++name));
8562 Permit();
8563 return(res);
8565 /* \\\ */
8567 /* /// "pStripString()" */
8568 void pStripString(LIBBASETYPEPTR ps, STRPTR str)
8570 STRPTR srcptr = str;
8571 STRPTR tarptr = str;
8572 STRPTR lastgoodchar = str;
8573 BOOL leadingspaces = TRUE;
8574 UBYTE ch;
8575 ULONG len = 0;
8577 while((ch = *srcptr++))
8579 len++;
8580 if(ch == ' ')
8582 if(!leadingspaces)
8584 *tarptr++ = ch;
8586 } else {
8587 *tarptr++ = ch;
8588 lastgoodchar = tarptr;
8589 leadingspaces = FALSE;
8592 *lastgoodchar = 0;
8593 // empty string?
8594 if((str == lastgoodchar) && (len > 6))
8596 strcpy(str, "<empty>");
8599 /* \\\ */
8601 /* /// "pFixBrokenConfig()" */
8602 BOOL pFixBrokenConfig(struct PsdPipe *pp)
8604 struct PsdDevice *pd = pp->pp_Device;
8605 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
8606 struct PsdConfig *pc;
8607 struct PsdInterface *pif;
8608 BOOL fixed = FALSE;
8610 switch(pd->pd_VendorID)
8612 case 0x03eb: /* Atmel */
8613 if(pd->pd_ProductID == 0x3312)
8615 psdFreeVec(pd->pd_ProductStr);
8616 pd->pd_ProductStr = psdCopyStr("Highway/Subway Root Hub");
8618 break;
8620 case 0x04e6: /* E-Shuttle */
8621 if(pd->pd_ProductID == 0x0001) /* LS120 */
8623 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8624 /* Get msd interface and fix it */
8625 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8626 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8628 fixed = TRUE;
8629 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "E-Shuttle LS120");
8630 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8631 pif->pif_IfSubClass = MS_ATAPI_SUBCLASS;
8632 pif->pif_IfProto = MS_PROTO_CB;
8635 break;
8637 case 0x054C: /* Sony */
8638 if((pd->pd_ProductID == 0x002E) || (pd->pd_ProductID == 0x0010)) /* Handycam */
8640 fixed = TRUE;
8641 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Sony MSD");
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 pif->pif_IfSubClass = MS_RBC_SUBCLASS;
8647 break;
8649 case 0x057b: /* Y-E Data */
8650 if(pd->pd_ProductID == 0x0000) /* Flashbuster U */
8652 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8653 /* Get msd interface and fix it */
8654 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8655 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8657 fixed = TRUE;
8658 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Y-E Data USB Floppy");
8659 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8660 pif->pif_IfSubClass = MS_UFI_SUBCLASS;
8661 pif->pif_IfProto = (pd->pd_DevVers < 0x0300) ? MS_PROTO_CB : MS_PROTO_CBI;
8664 break;
8666 case 0x04ce: /* ScanLogic */
8667 if(pd->pd_ProductID == 0x0002)
8669 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "ScanLogic");
8670 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8671 /* Get msd interface and fix it */
8672 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8673 fixed = TRUE;
8674 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8676 break;
8678 case 0x0584: /* Ratoc cardreader */
8679 if(pd->pd_ProductID == 0x0008)
8681 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "RATOC");
8682 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8683 /* Get msd interface and fix it */
8684 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8685 fixed = TRUE;
8686 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8687 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8688 pif->pif_IfProto = MS_PROTO_BULK;
8690 break;
8692 case 0x04b8: /* Epson */
8693 if(pd->pd_ProductID == 0x0602) /* EPX Storage device (Card slot in Printer) */
8695 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Epson storage");
8696 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8697 /* Get msd interface and fix it */
8698 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8699 fixed = TRUE;
8700 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8701 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8702 pif->pif_IfProto = MS_PROTO_BULK;
8704 break;
8706 default:
8707 break;
8709 return(fixed);
8711 /* \\\ */
8713 /* /// "pOpenDOS()" */
8714 BOOL pOpenDOS(LIBBASETYPEPTR ps)
8716 if(DOSBase)
8718 return TRUE;
8720 if((DOSBase = OpenLibrary("dos.library", 39)))
8722 return TRUE;
8724 return FALSE;
8726 /* \\\ */
8728 /* *** Class Scan Task *** */
8730 /* /// "pStartEventHandler()" */
8731 BOOL pStartEventHandler(LIBBASETYPEPTR ps)
8733 struct PsdHandlerTask *ph = &ps->ps_EventHandler;
8735 ObtainSemaphore(&ps->ps_PoPoLock);
8736 if(ph->ph_Task)
8738 ReleaseSemaphore(&ps->ps_PoPoLock);
8739 return(TRUE);
8741 ph->ph_ReadySignal = SIGB_SINGLE;
8742 ph->ph_ReadySigTask = FindTask(NULL);
8743 SetSignal(0, SIGF_SINGLE); // clear single bit
8744 if(psdSpawnSubTask("Poseidon Event Broadcast", pEventHandlerTask, ps))
8746 Wait(1UL<<ph->ph_ReadySignal);
8748 ph->ph_ReadySigTask = NULL;
8749 //FreeSignal(ph->ph_ReadySignal);
8750 if(ph->ph_Task)
8752 ReleaseSemaphore(&ps->ps_PoPoLock);
8753 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Event broadcaster started.");
8754 return(TRUE);
8756 ReleaseSemaphore(&ps->ps_PoPoLock);
8757 return(FALSE);
8759 /* \\\ */
8761 /* *** Hardware Driver Task *** */
8763 /* /// "pQuickForwardRequest()" */
8764 AROS_UFH1(void, pQuickForwardRequest,
8765 AROS_UFHA(struct MsgPort *, msgport, A1))
8767 AROS_USERFUNC_INIT
8768 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8769 struct PsdPipe *pp;
8771 while((pp = (struct PsdPipe *) RemHead(&msgport->mp_MsgList)))
8773 if(pp->pp_AbortPipe)
8775 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8776 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8777 ReplyMsg(&pp->pp_Msg);
8778 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8779 } else {
8780 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8781 pp->pp_IOReq.iouh_UserData = pp;
8782 SendIO((struct IORequest *) &pp->pp_IOReq);
8783 ++phw->phw_MsgCount;
8786 AROS_USERFUNC_EXIT
8788 /* \\\ */
8790 /* /// "pQuickReplyRequest()" */
8791 AROS_UFH1(void, pQuickReplyRequest,
8792 AROS_UFHA(struct MsgPort *, msgport, A1))
8794 AROS_USERFUNC_INIT
8795 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8796 struct IOUsbHWReq *ioreq;
8798 while((ioreq = (struct IOUsbHWReq *) RemHead(&msgport->mp_MsgList)))
8800 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8801 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8802 --phw->phw_MsgCount;
8804 AROS_USERFUNC_EXIT
8806 /* \\\ */
8808 /* /// "pDeviceTask()" */
8809 AROS_UFH0(void, pDeviceTask)
8811 AROS_USERFUNC_INIT
8812 LIBBASETYPEPTR ps;
8813 struct PsdHardware *phw;
8814 struct Task *thistask;
8815 ULONG sigs;
8816 ULONG sigmask;
8817 LONG ioerr;
8818 struct TagItem taglist[11];
8819 struct TagItem *tag;
8820 struct PsdPipe *pp;
8821 struct IOUsbHWReq *ioreq;
8823 STRPTR prodname = NULL;
8824 STRPTR manufacturer = NULL;
8825 STRPTR description = NULL;
8826 STRPTR copyright = NULL;
8827 ULONG version = 0;
8828 ULONG revision = 0;
8829 ULONG driververs = 0x0100;
8830 ULONG caps = UHCF_ISO;
8831 STRPTR devname;
8832 ULONG cnt;
8834 if(!(ps = (LIBBASETYPEPTR) OpenLibrary("poseidon.library", 4)))
8836 Alert(AG_OpenLib);
8837 return;
8839 thistask = FindTask(NULL);
8840 SetTaskPri(thistask, 21);
8841 phw = thistask->tc_UserData;
8843 #ifndef PA_CALLBACK // undocumented exec feature
8844 #define PA_CALLBACK 3
8845 #endif
8847 memset(&phw->phw_TaskMsgPort, 0, sizeof(phw->phw_TaskMsgPort));
8848 phw->phw_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8849 phw->phw_TaskMsgPort.mp_Node.ln_Name = (APTR) phw;
8850 phw->phw_TaskMsgPort.mp_Flags = PA_SIGNAL;
8851 phw->phw_TaskMsgPort.mp_SigTask = thistask;
8852 phw->phw_TaskMsgPort.mp_SigBit = AllocSignal(-1L);
8853 NewList(&phw->phw_TaskMsgPort.mp_MsgList);
8855 memset(&phw->phw_DevMsgPort, 0, sizeof(phw->phw_DevMsgPort));
8856 phw->phw_DevMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8857 phw->phw_DevMsgPort.mp_Node.ln_Name = (APTR) phw;
8858 phw->phw_DevMsgPort.mp_Flags = PA_SIGNAL;
8859 phw->phw_DevMsgPort.mp_SigTask = thistask;
8860 phw->phw_DevMsgPort.mp_SigBit = AllocSignal(-1L);
8861 NewList(&phw->phw_DevMsgPort.mp_MsgList);
8863 if((phw->phw_RootIOReq = (struct IOUsbHWReq *) CreateIORequest(&phw->phw_DevMsgPort, sizeof(struct IOUsbHWReq))))
8865 devname = phw->phw_DevName;
8866 ioerr = -1;
8867 while(*devname)
8869 if(!(ioerr = OpenDevice(devname, phw->phw_Unit, (struct IORequest *) phw->phw_RootIOReq, 0)))
8871 break;
8875 if((*devname == '/') || (*devname == ':'))
8877 ++devname;
8878 break;
8880 } while(*(++devname));
8883 if(!ioerr)
8885 phw->phw_Node.ln_Name = phw->phw_RootIOReq->iouh_Req.io_Device->dd_Library.lib_Node.ln_Name;
8886 tag = taglist;
8887 tag->ti_Tag = UHA_ProductName;
8888 tag->ti_Data = (IPTR) &prodname;
8889 ++tag;
8890 tag->ti_Tag = UHA_Manufacturer;
8891 tag->ti_Data = (IPTR) &manufacturer;
8892 ++tag;
8893 tag->ti_Tag = UHA_Description;
8894 tag->ti_Data = (IPTR) &description;
8895 ++tag;
8896 tag->ti_Tag = UHA_Version;
8897 tag->ti_Data = (IPTR) &version;
8898 ++tag;
8899 tag->ti_Tag = UHA_Revision;
8900 tag->ti_Data = (IPTR) &revision;
8901 ++tag;
8902 tag->ti_Tag = UHA_Copyright;
8903 tag->ti_Data = (IPTR) &copyright;
8904 ++tag;
8905 tag->ti_Tag = UHA_DriverVersion;
8906 tag->ti_Data = (IPTR) &driververs;
8907 ++tag;
8908 tag->ti_Tag = UHA_Capabilities;
8909 tag->ti_Data = (IPTR) &caps;
8910 ++tag;
8911 tag->ti_Tag = TAG_END;
8912 phw->phw_RootIOReq->iouh_Data = taglist;
8913 phw->phw_RootIOReq->iouh_Req.io_Command = UHCMD_QUERYDEVICE;
8914 DoIO((struct IORequest *) phw->phw_RootIOReq);
8916 phw->phw_ProductName = psdCopyStr(prodname ? prodname : (STRPTR) "n/a");
8917 phw->phw_Manufacturer = psdCopyStr(manufacturer ? manufacturer : (STRPTR) "n/a");
8918 phw->phw_Description = psdCopyStr(description ? description : (STRPTR) "n/a");
8919 phw->phw_Copyright = psdCopyStr(copyright ? copyright : (STRPTR) "n/a");
8920 phw->phw_Version = version;
8921 phw->phw_Revision = revision;
8922 phw->phw_DriverVers = driververs;
8923 phw->phw_Capabilities = caps;
8925 sigmask = SIGBREAKF_CTRL_C;
8926 if(caps & UHCF_QUICKIO)
8928 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Enabling QuickIO for %s.", prodname);
8929 phw->phw_TaskMsgPort.mp_Flags = PA_CALLBACK;
8930 phw->phw_TaskMsgPort.mp_SigTask = (APTR) pQuickForwardRequest;
8932 phw->phw_DevMsgPort.mp_Flags = PA_CALLBACK;
8933 phw->phw_DevMsgPort.mp_SigTask = (APTR) pQuickReplyRequest;
8934 } else {
8935 sigmask |= (1UL<<phw->phw_DevMsgPort.mp_SigBit)|(1UL<<phw->phw_TaskMsgPort.mp_SigBit);
8938 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
8939 phw->phw_Task = thistask;
8941 psdLockWritePBase();
8942 AddTail(&ps->ps_Hardware, &phw->phw_Node);
8943 psdUnlockPBase();
8945 Forbid();
8946 if(phw->phw_ReadySigTask)
8948 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
8950 Permit();
8953 KPRINTF(1, ("Main loop wait.\n"));
8954 while((pp = (struct PsdPipe *) GetMsg(&phw->phw_TaskMsgPort)))
8956 if(pp->pp_AbortPipe)
8958 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8959 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8960 ReplyMsg(&pp->pp_Msg);
8961 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8962 } else {
8963 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8964 pp->pp_IOReq.iouh_UserData = pp;
8965 SendIO((struct IORequest *) &pp->pp_IOReq);
8966 ++phw->phw_MsgCount;
8969 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8971 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8972 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8973 --phw->phw_MsgCount;
8975 sigs = Wait(sigmask);
8976 } while(!(sigs & SIGBREAKF_CTRL_C));
8977 /* Flush all pending IO Requests */
8978 phw->phw_RootIOReq->iouh_Req.io_Command = CMD_FLUSH;
8979 DoIO((struct IORequest *) phw->phw_RootIOReq);
8980 cnt = 0;
8981 while(phw->phw_MsgCount)
8983 KPRINTF(20, ("Still %ld iorequests pending!\n", phw->phw_MsgCount));
8984 psdDelayMS(100);
8985 if(++cnt == 50)
8987 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8988 "There are still %ld IORequests pending, before unit can go down. Driver buggy?",
8989 phw->phw_MsgCount);
8991 if(cnt == 300)
8993 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8994 "Okay, I've waited long enough, sod these %ld IORequests.",
8995 phw->phw_MsgCount);
8996 phw->phw_MsgCount = 0;
8997 break;
8999 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
9001 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
9002 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
9003 --phw->phw_MsgCount;
9006 psdLockWritePBase();
9007 Remove(&phw->phw_Node);
9008 psdUnlockPBase();
9009 CloseDevice((struct IORequest *) phw->phw_RootIOReq);
9010 } else {
9011 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
9012 "Opening %s unit %ld failed %s (%ld).",
9013 phw->phw_DevName, phw->phw_Unit, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
9015 DeleteIORequest((struct IORequest *) phw->phw_RootIOReq);
9016 phw->phw_RootIOReq = NULL;
9018 FreeSignal((LONG) phw->phw_TaskMsgPort.mp_SigBit);
9019 FreeSignal((LONG) phw->phw_DevMsgPort.mp_SigBit);
9021 CloseLibrary((struct Library *) ps);
9022 phw->phw_Task = NULL;
9024 Forbid();
9025 if(phw->phw_ReadySigTask)
9027 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
9029 AROS_USERFUNC_EXIT
9031 /* \\\ */
9033 /* /// "pEventHandlerTask()" */
9034 AROS_UFH0(void, pEventHandlerTask)
9036 AROS_USERFUNC_INIT
9037 LIBBASETYPEPTR ps;
9038 struct Task *thistask;
9039 struct timeval currtime;
9040 ULONG sigs;
9041 ULONG sigmask;
9042 struct PsdUsbClass *puc;
9043 struct PsdHandlerTask *ph;
9044 struct PsdEventNote *pen;
9045 ULONG counter;
9046 ULONG cfgchanged;
9048 thistask = FindTask(NULL);
9049 ps = thistask->tc_UserData;
9050 ph = &ps->ps_EventHandler;
9051 SetTaskPri(thistask, 0);
9053 if((ph->ph_MsgPort = CreateMsgPort()))
9055 if((ph->ph_TimerMsgPort = CreateMsgPort()))
9057 if((ph->ph_TimerIOReq = (struct timerequest *) CreateIORequest(ph->ph_TimerMsgPort, sizeof(struct timerequest))))
9059 if(!(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) ph->ph_TimerIOReq, 0)))
9061 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
9062 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "EventHandler";
9063 ph->ph_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
9065 ph->ph_EventHandler = psdAddEventHandler(ph->ph_MsgPort, EHMF_CONFIGCHG);
9066 if(ph->ph_EventHandler)
9068 ph->ph_Task = thistask;
9069 Forbid();
9070 if(ph->ph_ReadySigTask)
9072 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9074 Permit();
9076 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9077 SendIO(&ph->ph_TimerIOReq->tr_node);
9078 sigmask = (1UL<<ph->ph_MsgPort->mp_SigBit)|(1UL<<ph->ph_TimerMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
9079 counter = 0;
9080 cfgchanged = 0;
9083 if(ps->ps_CheckConfigReq)
9085 pCheckCfgChanged(ps);
9087 while((pen = (struct PsdEventNote *) GetMsg(ph->ph_MsgPort)))
9089 switch(pen->pen_Event)
9091 case EHMB_CONFIGCHG:
9092 if(!cfgchanged)
9094 cfgchanged = counter;
9096 break;
9099 ReplyMsg(&pen->pen_Msg);
9101 if(CheckIO(&ph->ph_TimerIOReq->tr_node))
9103 BOOL startpopo;
9104 WaitIO(&ph->ph_TimerIOReq->tr_node);
9105 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9106 SendIO(&ph->ph_TimerIOReq->tr_node);
9107 counter++;
9108 startpopo = !((counter & 3) || ps->ps_PoPo.po_Task);
9109 if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) &&
9110 (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) &&
9111 (!ps->ps_GlobalCfg->pgc_PopupDeviceGone))
9113 startpopo = FALSE; // no need to start popo, no windows wanted
9115 if(startpopo)
9117 struct PsdPoPo *po = &ps->ps_PoPo;
9119 po->po_ReadySignal = SIGB_SINGLE;
9120 po->po_ReadySigTask = FindTask(NULL);
9121 SetSignal(0, SIGF_SINGLE); // clear single bit
9122 if(psdSpawnSubTask("PoPo (Poseidon Popups)", pPoPoGUITask, ps))
9124 Wait(1UL<<po->po_ReadySignal);
9126 po->po_ReadySigTask = NULL;
9127 //FreeSignal(po->po_ReadySignal);
9128 if(po->po_Task)
9130 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "PoPo kicks ass.");
9133 if((cfgchanged + 2) == counter)
9135 KPRINTF(10, ("Sending information about config changed to all classes.\n"));
9136 /* Inform all classes */
9137 psdLockReadPBase();
9138 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
9139 while(puc->puc_Node.ln_Succ)
9141 usbDoMethod(UCM_ConfigChangedEvent);
9142 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
9144 psdUnlockPBase();
9145 cfgchanged = 0;
9147 // power saving stuff, check every second
9148 if((counter & 1) && ps->ps_GlobalCfg->pgc_PowerSaving)
9150 struct PsdDevice *pd = NULL;
9151 struct PsdInterface *pif;
9152 GetSysTime((APTR) &currtime);
9153 while((pd = psdGetNextDevice(pd)))
9155 if((pd->pd_DevClass != HUB_CLASSCODE) &&
9156 ((pd->pd_Flags & (PDFF_CONFIGURED|PDFF_DEAD|PDFF_SUSPENDED|PDFF_APPBINDING|PDFF_DELEXPUNGE)) == PDFF_CONFIGURED))
9158 if(pd->pd_LastActivity.tv_secs && ((currtime.tv_secs - pd->pd_LastActivity.tv_secs) > ps->ps_GlobalCfg->pgc_SuspendTimeout))
9160 BOOL doit = TRUE;
9161 IPTR suspendable;
9162 if(!((pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP) && ps->ps_GlobalCfg->pgc_ForceSuspend))
9164 if(pd->pd_DevBinding && ((puc = pd->pd_ClsBinding)))
9166 suspendable = 0;
9167 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9168 if(!suspendable)
9170 doit = FALSE;
9173 pif = (struct PsdInterface *) pd->pd_CurrentConfig->pc_Interfaces.lh_Head;
9174 while(pif->pif_Node.ln_Succ)
9176 if(pif->pif_IfBinding && ((puc = pif->pif_ClsBinding)))
9178 suspendable = 0;
9179 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9180 if(!suspendable)
9182 doit = FALSE;
9183 break;
9186 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
9189 if(doit)
9191 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Suspending '%s'.", pd->pd_ProductStr);
9192 psdSuspendDevice(pd);
9194 pd->pd_LastActivity.tv_secs = 0;
9200 sigs = Wait(sigmask);
9201 } while(!(sigs & SIGBREAKF_CTRL_C));
9202 psdRemEventHandler(ph->ph_EventHandler);
9203 ph->ph_EventHandler = NULL;
9204 AbortIO(&ph->ph_TimerIOReq->tr_node);
9205 WaitIO(&ph->ph_TimerIOReq->tr_node);
9207 CloseDevice((struct IORequest *) ph->ph_TimerIOReq);
9209 DeleteIORequest((struct IORequest *) ph->ph_TimerIOReq);
9211 DeleteMsgPort(ph->ph_TimerMsgPort);
9213 DeleteMsgPort(ph->ph_MsgPort);
9214 ph->ph_MsgPort = NULL;
9216 Forbid();
9217 ph->ph_Task = NULL;
9218 if(ph->ph_ReadySigTask)
9220 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9222 AROS_USERFUNC_EXIT
9224 /* \\\ */
9226 /*****************************************************************/
9228 /* /// "Packtables for psdGetAttrs() and psdSetAttrs() " */
9229 /* Pack table for PsdBase */
9230 static const ULONG PsdBasePT[] =
9232 PACK_STARTTABLE(PA_Dummy),
9233 PACK_ENTRY(PA_Dummy, PA_ConfigRead, PsdBase, ps_ConfigRead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9234 PACK_ENTRY(PA_Dummy, PA_GlobalConfig, PsdBase, ps_GlobalCfg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9235 PACK_ENTRY(PA_Dummy, PA_MemPoolUsage, PsdBase, ps_MemAllocated, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9236 PACK_ENTRY(PA_Dummy, PA_CurrConfigHash, PsdBase, ps_ConfigHash, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9237 PACK_ENTRY(PA_Dummy, PA_SavedConfigHash, PsdBase, ps_SavedConfigHash, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9238 PACK_ENTRY(PA_Dummy, PA_ReleaseVersion, PsdBase, ps_ReleaseVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9239 PACK_ENTRY(PA_Dummy, PA_OSVersion, PsdBase, ps_OSVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9240 PACK_ENDTABLE
9243 /* Pack table for PsdErrorMsg */
9244 static const ULONG PsdErrorMsgPT[] =
9246 PACK_STARTTABLE(EMA_Dummy),
9247 PACK_ENTRY(EMA_Dummy, EMA_Level, PsdErrorMsg, pem_Level, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9248 PACK_ENTRY(EMA_Dummy, EMA_Origin, PsdErrorMsg, pem_Origin, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9249 PACK_ENTRY(EMA_Dummy, EMA_Msg, PsdErrorMsg, pem_Msg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9250 PACK_ENDTABLE
9253 /* Pack table for PsdUsbClass */
9254 static const ULONG PsdUsbClassPT[] =
9256 PACK_STARTTABLE(UCA_Dummy),
9257 PACK_ENTRY(UCA_Dummy, UCA_ClassBase, PsdUsbClass, puc_ClassBase, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9258 PACK_ENTRY(UCA_Dummy, UCA_ClassName, PsdUsbClass, puc_ClassName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9259 PACK_ENTRY(UCA_Dummy, UCA_FullPath, PsdUsbClass, puc_FullPath, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9260 PACK_ENTRY(UCA_Dummy, UCA_UseCount, PsdUsbClass, puc_UseCnt, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9261 PACK_ENDTABLE
9264 /* Pack table for PsdHardware */
9265 static const ULONG PsdHardwarePT[] =
9267 PACK_STARTTABLE(HA_Dummy),
9268 PACK_ENTRY(HA_Dummy, HA_DeviceName, PsdHardware, phw_DevName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9269 PACK_ENTRY(HA_Dummy, HA_DeviceUnit, PsdHardware, phw_Unit, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9270 PACK_ENTRY(HA_Dummy, HA_ProductName, PsdHardware, phw_ProductName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9271 PACK_ENTRY(HA_Dummy, HA_Manufacturer, PsdHardware, phw_Manufacturer, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9272 PACK_ENTRY(HA_Dummy, HA_Description, PsdHardware, phw_Description, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9273 PACK_ENTRY(HA_Dummy, HA_Copyright, PsdHardware, phw_Copyright, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9274 PACK_ENTRY(HA_Dummy, HA_Version, PsdHardware, phw_Version, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9275 PACK_ENTRY(HA_Dummy, HA_Revision, PsdHardware, phw_Revision, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9276 PACK_ENTRY(HA_Dummy, HA_DriverVersion, PsdHardware, phw_DriverVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9277 PACK_ENDTABLE
9280 /* Pack table for PsdDevice */
9281 static const ULONG PsdDevicePT[] =
9283 PACK_STARTTABLE(DA_Dummy),
9284 PACK_ENTRY(DA_Dummy, DA_Address, PsdDevice, pd_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9285 PACK_ENTRY(DA_Dummy, DA_NumConfigs, PsdDevice, pd_NumCfgs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9286 PACK_ENTRY(DA_Dummy, DA_CurrConfig, PsdDevice, pd_CurrCfg, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9287 PACK_ENTRY(DA_Dummy, DA_Config, PsdDevice, pd_CurrentConfig, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9288 PACK_ENTRY(DA_Dummy, DA_HubDevice, PsdDevice, pd_Hub, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9289 PACK_ENTRY(DA_Dummy, DA_UsbVersion, PsdDevice, pd_USBVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9290 PACK_ENTRY(DA_Dummy, DA_Class, PsdDevice, pd_DevClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9291 PACK_ENTRY(DA_Dummy, DA_SubClass, PsdDevice, pd_DevSubClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9292 PACK_ENTRY(DA_Dummy, DA_Protocol, PsdDevice, pd_DevProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9293 PACK_ENTRY(DA_Dummy, DA_VendorID, PsdDevice, pd_VendorID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9294 PACK_ENTRY(DA_Dummy, DA_MaxPktSize0, PsdDevice, pd_MaxPktSize0, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9295 PACK_ENTRY(DA_Dummy, DA_ProductID, PsdDevice, pd_ProductID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9296 PACK_ENTRY(DA_Dummy, DA_Version, PsdDevice, pd_DevVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9297 PACK_ENTRY(DA_Dummy, DA_Manufacturer, PsdDevice, pd_MnfctrStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9298 PACK_ENTRY(DA_Dummy, DA_ProductName, PsdDevice, pd_ProductStr, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9299 PACK_ENTRY(DA_Dummy, DA_OrigProductName, PsdDevice, pd_OldProductStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9300 PACK_ENTRY(DA_Dummy, DA_SerialNumber, PsdDevice, pd_SerNumStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9301 PACK_ENTRY(DA_Dummy, DA_Hardware, PsdDevice, pd_Hardware, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9302 PACK_ENTRY(DA_Dummy, DA_Binding, PsdDevice, pd_DevBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9303 PACK_ENTRY(DA_Dummy, DA_BindingClass, PsdDevice, pd_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9304 PACK_ENTRY(DA_Dummy, DA_LangIDArray, PsdDevice, pd_LangIDArray, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9305 PACK_ENTRY(DA_Dummy, DA_CurrLangID, PsdDevice, pd_CurrLangID, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9306 PACK_ENTRY(DA_Dummy, DA_IDString, PsdDevice, pd_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9307 PACK_ENTRY(DA_Dummy, DA_CloneCount, PsdDevice, pd_CloneCount, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9308 PACK_ENTRY(DA_Dummy, DA_AtHubPortNumber, PsdDevice, pd_HubPort, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9309 PACK_ENTRY(DA_Dummy, DA_PowerDrained, PsdDevice, pd_PowerDrain, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9310 PACK_ENTRY(DA_Dummy, DA_PowerSupply, PsdDevice, pd_PowerSupply, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9311 PACK_ENTRY(DA_Dummy, DA_IsNewToMe, PsdDevice, pd_IsNewToMe, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9312 PACK_ENTRY(DA_Dummy, DA_InhibitPopup, PsdDevice, pd_PoPoCfg.poc_InhibitPopup, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9313 PACK_ENTRY(DA_Dummy, DA_InhibitClassBind, PsdDevice, pd_PoPoCfg.poc_NoClassBind, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9314 PACK_ENTRY(DA_Dummy, DA_OverridePowerInfo, PsdDevice, pd_PoPoCfg.poc_OverridePowerInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9315 PACK_ENTRY(DA_Dummy, DA_HubThinkTime, PsdDevice, pd_HubThinkTime, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9316 PACK_WORDBIT(DA_Dummy, DA_IsLowspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_LOWSPEED),
9317 PACK_WORDBIT(DA_Dummy, DA_IsHighspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HIGHSPEED),
9318 PACK_WORDBIT(DA_Dummy, DA_IsConnected, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONNECTED),
9319 PACK_WORDBIT(DA_Dummy, DA_HasAddress, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVADDR),
9320 PACK_WORDBIT(DA_Dummy, DA_HasDevDesc, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVDESC),
9321 PACK_WORDBIT(DA_Dummy, DA_IsConfigured, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONFIGURED),
9322 PACK_WORDBIT(DA_Dummy, DA_IsDead, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_DEAD),
9323 PACK_WORDBIT(DA_Dummy, DA_IsSuspended, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUSPENDED),
9324 PACK_WORDBIT(DA_Dummy, DA_HasAppBinding, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_APPBINDING),
9325 PACK_WORDBIT(DA_Dummy, DA_NeedsSplitTrans, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_NEEDSSPLIT),
9326 PACK_WORDBIT(DA_Dummy, DA_LowPower, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_LOWPOWER),
9327 #ifdef AROS_USB30_CODE
9328 PACK_WORDBIT(DA_Dummy, DA_IsSuperspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUPERSPEED),
9329 #endif
9330 PACK_ENDTABLE
9333 /* Pack table for PsdConfig */
9334 static const ULONG PsdConfigPT[] =
9336 PACK_STARTTABLE(CA_Dummy),
9337 PACK_ENTRY(CA_Dummy, CA_ConfigNum, PsdConfig, pc_CfgNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9338 PACK_ENTRY(CA_Dummy, CA_MaxPower, PsdConfig, pc_MaxPower, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9339 PACK_ENTRY(CA_Dummy, CA_ConfigName, PsdConfig, pc_CfgStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9340 PACK_ENTRY(CA_Dummy, CA_NumInterfaces, PsdConfig, pc_NumIfs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9341 PACK_ENTRY(CA_Dummy, CA_Attrs, PsdConfig, pc_Attr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9342 PACK_ENTRY(CA_Dummy, CA_Device, PsdConfig, pc_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9343 PACK_WORDBIT(CA_Dummy, CA_SelfPowered, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_PACKUNPACK, USCAF_SELF_POWERED),
9344 PACK_WORDBIT(CA_Dummy, CA_RemoteWakeup, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_UNPACKONLY, USCAF_REMOTE_WAKEUP),
9345 PACK_ENDTABLE
9348 /* Pack table for PsdDescriptor */
9349 static const ULONG PsdDescriptorPT[] =
9351 PACK_STARTTABLE(DDA_Dummy),
9352 PACK_ENTRY(DDA_Dummy, DDA_Device, PsdDescriptor, pdd_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9353 PACK_ENTRY(DDA_Dummy, DDA_Config, PsdDescriptor, pdd_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9354 PACK_ENTRY(DDA_Dummy, DDA_Interface, PsdDescriptor, pdd_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9355 PACK_ENTRY(DDA_Dummy, DDA_Endpoint, PsdDescriptor, pdd_Endpoint, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9356 PACK_ENTRY(DDA_Dummy, DDA_Name, PsdDescriptor, pdd_Name, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9357 PACK_ENTRY(DDA_Dummy, DDA_DescriptorType, PsdDescriptor, pdd_Type, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9358 PACK_ENTRY(DDA_Dummy, DDA_CS_SubType, PsdDescriptor, pdd_CSSubType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9359 PACK_ENTRY(DDA_Dummy, DDA_DescriptorData, PsdDescriptor, pdd_Data, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9360 PACK_ENTRY(DDA_Dummy, DDA_DescriptorLength, PsdDescriptor, pdd_Length, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9361 PACK_ENDTABLE
9364 /* Pack table for PsdInterface */
9365 static const ULONG PsdInterfacePT[] =
9367 PACK_STARTTABLE(IFA_Dummy),
9368 PACK_ENTRY(IFA_Dummy, IFA_InterfaceNum, PsdInterface, pif_IfNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9369 PACK_ENTRY(IFA_Dummy, IFA_AlternateNum, PsdInterface, pif_Alternate, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9370 PACK_ENTRY(IFA_Dummy, IFA_NumEndpoints, PsdInterface, pif_NumEPs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9371 PACK_ENTRY(IFA_Dummy, IFA_Class, PsdInterface, pif_IfClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9372 PACK_ENTRY(IFA_Dummy, IFA_SubClass, PsdInterface, pif_IfSubClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9373 PACK_ENTRY(IFA_Dummy, IFA_Protocol, PsdInterface, pif_IfProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9374 PACK_ENTRY(IFA_Dummy, IFA_InterfaceName, PsdInterface, pif_IfStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9375 PACK_ENTRY(IFA_Dummy, IFA_Config, PsdInterface, pif_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9376 PACK_ENTRY(IFA_Dummy, IFA_Binding, PsdInterface, pif_IfBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9377 PACK_ENTRY(IFA_Dummy, IFA_BindingClass, PsdInterface, pif_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9378 PACK_ENTRY(IFA_Dummy, IFA_IDString, PsdInterface, pif_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9379 PACK_ENDTABLE
9382 /* Pack table for PsdEndpoint */
9383 static const ULONG PsdEndpointPT[] =
9385 PACK_STARTTABLE(EA_Dummy),
9386 PACK_ENTRY(EA_Dummy, EA_EndpointNum, PsdEndpoint, pep_EPNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9387 PACK_ENTRY(EA_Dummy, EA_TransferType, PsdEndpoint, pep_TransType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9388 PACK_ENTRY(EA_Dummy, EA_MaxPktSize, PsdEndpoint, pep_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9389 PACK_ENTRY(EA_Dummy, EA_Interval, PsdEndpoint, pep_Interval, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9390 PACK_ENTRY(EA_Dummy, EA_NumTransMuFrame, PsdEndpoint, pep_NumTransMuFr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9391 PACK_ENTRY(EA_Dummy, EA_SyncType, PsdEndpoint, pep_SyncType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9392 PACK_ENTRY(EA_Dummy, EA_UsageType, PsdEndpoint, pep_UsageType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9393 PACK_ENTRY(EA_Dummy, EA_Interface, PsdEndpoint, pep_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9394 PACK_WORDBIT(EA_Dummy, EA_IsIn, PsdEndpoint, pep_Direction, PKCTRL_BIT|PKCTRL_UNPACKONLY, 1),
9395 PACK_ENDTABLE
9398 /* Pack table for PsdPipe */
9399 static const ULONG PsdPipePT[] =
9401 PACK_STARTTABLE(PPA_Dummy),
9402 PACK_ENTRY(PPA_Dummy, PPA_Endpoint, PsdPipe, pp_Endpoint, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9403 PACK_ENTRY(PPA_Dummy, PPA_Error, PsdPipe, pp_IOReq.iouh_Req.io_Error, PKCTRL_BYTE|PKCTRL_UNPACKONLY),
9404 PACK_ENTRY(PPA_Dummy, PPA_Actual, PsdPipe, pp_IOReq.iouh_Actual, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9405 PACK_ENTRY(PPA_Dummy, PPA_EndpointNum, PsdPipe, pp_IOReq.iouh_Endpoint, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9406 PACK_ENTRY(PPA_Dummy, PPA_DeviceAddress, PsdPipe, pp_IOReq.iouh_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9407 PACK_ENTRY(PPA_Dummy, PPA_MaxPktSize, PsdPipe, pp_IOReq.iouh_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9408 PACK_ENTRY(PPA_Dummy, PPA_NakTimeoutTime, PsdPipe, pp_IOReq.iouh_NakTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9409 PACK_ENTRY(PPA_Dummy, PPA_Interval, PsdPipe, pp_IOReq.iouh_Interval, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9410 PACK_WORDBIT(PPA_Dummy, PPA_NoShortPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NOSHORTPKT),
9411 PACK_WORDBIT(PPA_Dummy, PPA_NakTimeout, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NAKTIMEOUT),
9412 PACK_WORDBIT(PPA_Dummy, PPA_AllowRuntPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_ALLOWRUNTPKTS),
9413 PACK_ENDTABLE
9416 /* Pack table for PsdAppBinding */
9417 static const ULONG PsdAppBindingPT[] =
9419 PACK_STARTTABLE(ABA_Dummy),
9420 PACK_ENTRY(ABA_Dummy, ABA_ReleaseHook, PsdAppBinding, pab_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9421 PACK_ENTRY(ABA_Dummy, ABA_Device, PsdAppBinding, pab_Device, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9422 PACK_ENTRY(ABA_Dummy, ABA_UserData, PsdAppBinding, pab_UserData, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9423 PACK_ENTRY(ABA_Dummy, ABA_Task, PsdAppBinding, pab_Task, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9424 PACK_ENTRY(ABA_Dummy, ABA_ForceRelease, PsdAppBinding, pab_ForceRelease, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9425 PACK_ENDTABLE
9428 /* Pack table for PsdAppBinding */
9429 static const ULONG PsdEventNotePT[] =
9431 PACK_STARTTABLE(ENA_Dummy),
9432 PACK_ENTRY(ENA_Dummy, ENA_EventID, PsdEventNote, pen_Event, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9433 PACK_ENTRY(ENA_Dummy, ENA_Param1, PsdEventNote, pen_Param1, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9434 PACK_ENTRY(ENA_Dummy, ENA_Param2, PsdEventNote, pen_Param2, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9435 PACK_ENDTABLE
9438 /* Pack table for PsdGlobalCfg */
9439 static const ULONG PsdGlobalCfgPT[] =
9441 PACK_STARTTABLE(GCA_Dummy),
9442 PACK_ENTRY(GCA_Dummy, GCA_LogInfo, PsdGlobalCfg, pgc_LogInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9443 PACK_ENTRY(GCA_Dummy, GCA_LogWarning, PsdGlobalCfg, pgc_LogWarning, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9444 PACK_ENTRY(GCA_Dummy, GCA_LogError, PsdGlobalCfg, pgc_LogError, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9445 PACK_ENTRY(GCA_Dummy, GCA_LogFailure, PsdGlobalCfg, pgc_LogFailure, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9446 PACK_ENTRY(GCA_Dummy, GCA_BootDelay, PsdGlobalCfg, pgc_BootDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9447 PACK_ENTRY(GCA_Dummy, GCA_SubTaskPri, PsdGlobalCfg, pgc_SubTaskPri, PKCTRL_WORD|PKCTRL_PACKUNPACK),
9448 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceNew, PsdGlobalCfg, pgc_PopupDeviceNew, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9449 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceGone, PsdGlobalCfg, pgc_PopupDeviceGone, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9450 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceDeath, PsdGlobalCfg, pgc_PopupDeviceDeath, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9451 PACK_ENTRY(GCA_Dummy, GCA_PopupCloseDelay, PsdGlobalCfg, pgc_PopupCloseDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9452 PACK_ENTRY(GCA_Dummy, GCA_PopupActivateWin, PsdGlobalCfg, pgc_PopupActivateWin, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9453 PACK_ENTRY(GCA_Dummy, GCA_PopupWinToFront, PsdGlobalCfg, pgc_PopupWinToFront, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9454 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableLP, PsdGlobalCfg, pgc_AutoDisableLP, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9455 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableDead, PsdGlobalCfg, pgc_AutoDisableDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9456 PACK_ENTRY(GCA_Dummy, GCA_AutoRestartDead, PsdGlobalCfg, pgc_AutoRestartDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9457 PACK_ENTRY(GCA_Dummy, GCA_PowerSaving, PsdGlobalCfg, pgc_PowerSaving, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9458 PACK_ENTRY(GCA_Dummy, GCA_ForceSuspend, PsdGlobalCfg, pgc_ForceSuspend, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9459 PACK_ENTRY(GCA_Dummy, GCA_SuspendTimeout, PsdGlobalCfg, pgc_SuspendTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9460 PACK_ENTRY(GCA_Dummy, GCA_PrefsVersion, PsdGlobalCfg, pgc_PrefsVersion, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9461 PACK_ENDTABLE
9464 /* Pack table for PsdPipeStream */
9465 static const ULONG PsdPipeStreamPT[] =
9467 PACK_STARTTABLE(PSA_Dummy),
9468 PACK_ENTRY(PSA_Dummy, PSA_MessagePort, PsdPipeStream, pps_MsgPort, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9469 PACK_ENTRY(PSA_Dummy, PSA_NumPipes, PsdPipeStream, pps_NumPipes, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9470 PACK_ENTRY(PSA_Dummy, PSA_BufferSize, PsdPipeStream, pps_BufferSize, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9471 PACK_ENTRY(PSA_Dummy, PSA_NakTimeoutTime, PsdPipeStream, pps_NakTimeoutTime, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9472 PACK_ENTRY(PSA_Dummy, PSA_BytesPending, PsdPipeStream, pps_BytesPending, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9473 PACK_ENTRY(PSA_Dummy, PSA_Error, PsdPipeStream, pps_Error, PKCTRL_LONG|PKCTRL_PACKUNPACK),
9474 PACK_ENTRY(PSA_Dummy, PSA_TermArray, PsdPipeStream, pps_TermArray, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9475 PACK_ENTRY(PSA_Dummy, PSA_AbortSigMask, PsdPipeStream, pps_AbortSigMask, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9476 PACK_ENTRY(PSA_Dummy, PSA_ActivePipe, PsdPipeStream, pps_ActivePipe, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9477 PACK_WORDBIT(PSA_Dummy, PSA_AsyncIO, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ASYNCIO),
9478 PACK_WORDBIT(PSA_Dummy, PSA_ShortPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_SHORTTERM),
9479 PACK_WORDBIT(PSA_Dummy, PSA_ReadAhead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_READAHEAD),
9480 PACK_WORDBIT(PSA_Dummy, PSA_BufferedRead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERREAD),
9481 PACK_WORDBIT(PSA_Dummy, PSA_BufferedWrite, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERWRITE),
9482 PACK_WORDBIT(PSA_Dummy, PSA_NoZeroPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NOSHORTPKT),
9483 PACK_WORDBIT(PSA_Dummy, PSA_NakTimeout, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NAKTIMEOUT),
9484 PACK_WORDBIT(PSA_Dummy, PSA_AllowRuntPackets, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ALLOWRUNT),
9485 PACK_WORDBIT(PSA_Dummy, PSA_DoNotWait, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_DONOTWAIT),
9486 PACK_ENDTABLE
9489 /* Pack table for PsdRTIsoHandler */
9490 static const ULONG PsdRTIsoHandlerPT[] =
9492 PACK_STARTTABLE(RTA_Dummy),
9493 PACK_ENTRY(RTA_Dummy, RTA_InRequestHook, PsdRTIsoHandler, prt_RTIso.urti_InReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9494 PACK_ENTRY(RTA_Dummy, RTA_OutRequestHook, PsdRTIsoHandler, prt_RTIso.urti_OutReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9495 PACK_ENTRY(RTA_Dummy, RTA_InDoneHook, PsdRTIsoHandler, prt_RTIso.urti_InDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9496 PACK_ENTRY(RTA_Dummy, RTA_OutDoneHook, PsdRTIsoHandler, prt_RTIso.urti_OutDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9497 PACK_ENTRY(RTA_Dummy, RTA_ReleaseHook, PsdRTIsoHandler, prt_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9498 PACK_ENTRY(RTA_Dummy, RTA_OutPrefetchSize, PsdRTIsoHandler, prt_RTIso.urti_OutPrefetch, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9499 PACK_ENDTABLE
9502 /* PGA assignment table */
9503 static const ULONG *PsdPTArray[] =
9505 NULL,
9506 PsdBasePT,
9507 PsdUsbClassPT,
9508 PsdHardwarePT,
9509 PsdDevicePT,
9510 PsdConfigPT,
9511 PsdInterfacePT,
9512 PsdEndpointPT,
9513 PsdErrorMsgPT,
9514 PsdPipePT,
9515 PsdAppBindingPT,
9516 PsdEventNotePT,
9517 PsdGlobalCfgPT,
9518 PsdPipeStreamPT,
9519 PsdDescriptorPT,
9520 PsdRTIsoHandlerPT
9522 /* \\\ */