Minor fixes to comments.
[AROS.git] / rom / usb / poseidon / poseidon.library.c
blob1c857f9e06ed19a01bcca13c3a896806a3a5f9bb
1 /****************************************************************************
3 __ __ V/\V. /\
4 |" | |" | mMMnw, || []
5 | | | | (o o)W () || ||
6 |__|_|_"| | / |Mw || ||//
7 (" " \| \ -'_/mw \\||/
8 \______) ~%%/WM" \||
9 _____ ___ ______ _____ __ _____ ___ __ __/~~__ ~~\ _||
10 |"(" \()/\" \ ()/"_ )|"(___) ) )|"(" \ ()/\" \(__)/" ) /" ) " \ /_)O
11 | ) )/" \ \ (_/"\__/ | )_ ( ( | )_ ) /" \ \ / /|/ / ·\ \/ ,|O
12 | (___/( (_\__) _\ \_ | (__) ) )| (__) |( (_\__)/ /"/ / |\ '_|O
13 | | _ \ / / /" \_/ ) | ")__ ( ( | )" ) \ / // /|/ / . .|/\__/ ||
14 |__| (_) \/__/ (______/ |_(___) )_)|_(___/ . \/__/(__/ (__/ .:.:| ||
15 _____
16 |" __ \ Poseidon -- The divine USB stack for Amiga computers
17 | (__) )
18 | __ ( Designed and written by
19 |"(__) ) Chris Hodges <chrisly@platon42.de>
20 |_____/ Copyright ©2002-2009 Chris Hodges. All rights reserved.
22 ****************************************************************************/
25 *----------------------------------------------------------------------------
26 * Poseidon main library
27 *----------------------------------------------------------------------------
28 * By Chris Hodges <chrisly@platon42.de>
31 #include "debug.h"
33 #include "poseidon.library.h"
35 #include "numtostr.h"
37 #include <proto/exec.h>
38 #include <proto/dos.h>
39 #include <proto/utility.h>
40 #include <proto/usbclass.h>
41 #include <proto/timer.h>
43 #ifdef __AROS__
44 #include <aros/bootloader.h>
45 #include <proto/bootloader.h>
46 #endif
48 #define NewList(list) NEWLIST(list)
50 #define min(x,y) (((x) < (y)) ? (x) : (y))
51 #define max(x,y) (((x) > (y)) ? (x) : (y))
53 extern const struct PsdWStringMap usbclasscodestr[];
54 extern const struct PsdULStringMap usbcomboclasscodestr[];
55 extern const struct PsdULStringMap usbdesctypestr[];
56 extern const struct PsdWStringMap usbhwioerrstr[];
57 extern const struct PsdUWStringMap usblangids[];
58 extern const struct PsdUWStringMap usbvendorids[];
60 extern struct ExecBase *SysBase;
62 /* Static data */
63 const char GM_UNIQUENAME(libname)[] = MOD_NAME_STRING;
65 #define UsbClsBase puc->puc_ClassBase
66 #define DOSBase ps->ps_DosBase
67 #define TimerBase ps->ps_TimerIOReq.tr_node.io_Device
69 /* LibInit */
70 static int GM_UNIQUENAME(libInit)(LIBBASETYPEPTR ps)
72 KPRINTF(10, ("libInit ps: 0x%p SysBase: 0x%p\n",
73 ps, SysBase));
75 ps->ps_StackInit = FALSE;
76 ps->ps_UtilityBase = (struct UtilityBase *) OpenLibrary("utility.library", 39);
78 #define UtilityBase ps->ps_UtilityBase
80 if (UtilityBase)
82 #ifdef __AROS__
83 APTR BootLoaderBase = OpenResource("bootloader.resource");
85 if (BootLoaderBase)
87 struct List *args = GetBootInfo(BL_Args);
89 if (args)
91 struct Node *node;
93 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
95 if (stricmp(node->ln_Name, "usbdebug") == 0)
97 ps->ps_Flags = PSF_KLOG;
98 break;
103 #endif
105 NewList(&ps->ps_Hardware);
106 NewList(&ps->ps_Classes);
107 NewList(&ps->ps_ErrorMsgs);
108 NewList(&ps->ps_EventHooks);
109 ps->ps_EventReplyPort.mp_Flags = PA_IGNORE;
110 NewList(&ps->ps_EventReplyPort.mp_MsgList);
111 NewList(&ps->ps_ConfigRoot);
112 NewList(&ps->ps_AlienConfigs);
114 NewList(&ps->ps_DeadlockDebug);
116 InitSemaphore(&ps->ps_ReentrantLock);
117 InitSemaphore(&ps->ps_PoPoLock);
119 if((ps->ps_MemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC|MEMF_SEM_PROTECTED, 16384, 1024)))
121 if((ps->ps_SemaMemPool = CreatePool(MEMF_CLEAR|MEMF_PUBLIC, 16*sizeof(struct PsdReadLock), sizeof(struct PsdBorrowLock))))
123 pInitSem(ps, &ps->ps_Lock, "PBase");
124 pInitSem(ps, &ps->ps_ConfigLock, "ConfigLock");
125 KPRINTF(20, ("libInit: Done!\n"));
126 return TRUE;
128 DeletePool(ps->ps_MemPool);
129 } else {
130 KPRINTF(20, ("libInit: CreatePool() failed!\n"));
132 CloseLibrary((struct Library *) UtilityBase);
133 } else {
134 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
136 return FALSE;
139 /* LibOpen */
140 static int GM_UNIQUENAME(libOpen)(LIBBASETYPEPTR ps)
142 struct PsdIFFContext *pic;
144 KPRINTF(10, ("libOpen ps: 0x%p\n", ps));
145 ObtainSemaphore(&ps->ps_ReentrantLock);
146 if(!ps->ps_StackInit)
148 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
149 ps->ps_TimerIOReq.tr_node.io_Message.mn_ReplyPort = NULL;
150 ps->ps_TimerIOReq.tr_node.io_Message.mn_Length = sizeof(struct timerequest);
151 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) &ps->ps_TimerIOReq, 0))
153 ps->ps_TimerIOReq.tr_node.io_Message.mn_Node.ln_Name = "Poseidon";
154 ps->ps_TimerIOReq.tr_node.io_Command = TR_ADDREQUEST;
156 ps->ps_ReleaseVersion = RELEASEVERSION;
157 ps->ps_OSVersion = MAKE_ID('A','R','O','S');
159 pic = pAllocForm(ps, NULL, IFFFORM_PSDCFG);
160 if((ps->ps_GlobalCfg = psdAllocVec(sizeof(struct PsdGlobalCfg))))
162 ps->ps_GlobalCfg->pgc_ChunkID = AROS_LONG2BE(IFFCHNK_GLOBALCFG);
163 ps->ps_GlobalCfg->pgc_Length = AROS_LONG2BE(sizeof(struct PsdGlobalCfg)-8);
164 ps->ps_GlobalCfg->pgc_LogInfo = TRUE;
165 ps->ps_GlobalCfg->pgc_LogWarning = TRUE;
166 ps->ps_GlobalCfg->pgc_LogError = TRUE;
167 ps->ps_GlobalCfg->pgc_LogFailure = TRUE;
168 ps->ps_GlobalCfg->pgc_BootDelay = 2;
169 ps->ps_GlobalCfg->pgc_SubTaskPri = 5;
170 ps->ps_GlobalCfg->pgc_PopupDeviceNew = PGCP_ISNEW;
171 ps->ps_GlobalCfg->pgc_PopupDeviceGone = TRUE;
172 ps->ps_GlobalCfg->pgc_PopupDeviceDeath = TRUE;
173 ps->ps_GlobalCfg->pgc_PopupCloseDelay = 5;
174 ps->ps_GlobalCfg->pgc_PopupActivateWin = FALSE;
175 ps->ps_GlobalCfg->pgc_PopupWinToFront = TRUE;
176 ps->ps_GlobalCfg->pgc_AutoDisableLP = FALSE;
177 ps->ps_GlobalCfg->pgc_AutoDisableDead = FALSE;
178 ps->ps_GlobalCfg->pgc_AutoRestartDead = TRUE;
179 ps->ps_GlobalCfg->pgc_PowerSaving = FALSE;
180 ps->ps_GlobalCfg->pgc_ForceSuspend = FALSE;
181 ps->ps_GlobalCfg->pgc_SuspendTimeout = 30;
183 ps->ps_GlobalCfg->pgc_PrefsVersion = 0; // is updated on writing
184 ps->ps_ConfigRead = FALSE;
185 if(pic)
187 pic = pAllocForm(ps, pic, IFFFORM_STACKCFG);
188 if(pic)
190 pAddCfgChunk(ps, pic, ps->ps_GlobalCfg);
193 ps->ps_PoPo.po_InsertSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Connect.iff");
194 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr("SYS:Prefs/Presets/Poseidon/Disconnect.iff");
197 STRPTR tmpstr;
198 tmpstr = psdCopyStr((STRPTR) VERSION_STRING);
199 if(tmpstr)
201 tmpstr[strlen(tmpstr)-2] = 0;
202 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s (%p)!", tmpstr, ps->ps_ReleaseVersion);
203 psdFreeVec(tmpstr);
204 } else {
205 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Welcome to %s", VERSION_STRING);
209 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "This is the AROS port.");
211 KPRINTF(10, ("libOpen: Ok\n"));
212 ps->ps_StackInit = TRUE;
213 ReleaseSemaphore(&ps->ps_ReentrantLock);
214 pStartEventHandler(ps);
216 return TRUE;
217 } else {
218 KPRINTF(20, ("libOpen: No memory for cfg!\n"));
220 } else {
221 KPRINTF(20, ("libOpen: OpenDevice(timer.device) failed!\n"));
223 ReleaseSemaphore(&ps->ps_ReentrantLock);
224 return FALSE;
226 ReleaseSemaphore(&ps->ps_ReentrantLock);
227 KPRINTF(5, ("libOpen: openCnt = %ld\n", ps->ps_Library.lib_OpenCnt));
228 return TRUE;
231 int GM_UNIQUENAME(libExpunge)(LIBBASETYPEPTR ps)
233 struct PsdHardware *phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
234 struct PsdUsbClass *puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
235 struct PsdErrorMsg *pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
236 struct PsdIFFContext *pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
237 KPRINTF(10, ("libExpunge ps: 0x%p\n", ps));
238 while(phw->phw_Node.ln_Succ)
240 psdRemHardware(phw);
241 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
243 while(puc->puc_Node.ln_Succ)
245 psdRemClass(puc);
246 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
248 while(pem->pem_Node.ln_Succ)
250 psdRemErrorMsg(pem);
251 pem = (struct PsdErrorMsg *) ps->ps_ErrorMsgs.lh_Head;
254 while(pic->pic_Node.ln_Succ)
256 pFreeForm(ps, pic);
257 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
260 if(ps->ps_PoPo.po_Task)
262 ps->ps_PoPo.po_ReadySignal = SIGB_SINGLE;
263 ps->ps_PoPo.po_ReadySigTask = FindTask(NULL);
264 Signal(ps->ps_PoPo.po_Task, SIGBREAKF_CTRL_C);
265 while(ps->ps_PoPo.po_Task)
267 Wait(1L<<ps->ps_PoPo.po_ReadySignal);
269 ps->ps_PoPo.po_ReadySigTask = NULL;
270 //FreeSignal(ps->ps_PoPo.po_ReadySignal);
272 if(ps->ps_EventHandler.ph_Task)
274 ps->ps_EventHandler.ph_ReadySignal = SIGB_SINGLE;
275 ps->ps_EventHandler.ph_ReadySigTask = FindTask(NULL);
276 Signal(ps->ps_EventHandler.ph_Task, SIGBREAKF_CTRL_C);
277 while(ps->ps_EventHandler.ph_Task)
279 Wait(1L<<ps->ps_EventHandler.ph_ReadySignal);
281 ps->ps_EventHandler.ph_ReadySigTask = NULL;
282 //FreeSignal(ps->ps_EventHandler.ph_ReadySignal);
284 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
285 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
286 pGarbageCollectEvents(ps);
288 CloseDevice((struct IORequest *) &ps->ps_TimerIOReq);
289 DeletePool(ps->ps_SemaMemPool);
290 DeletePool(ps->ps_MemPool);
292 KPRINTF(1, ("libExpunge: closelibrary utilitybase 0x%p\n",
293 UtilityBase));
294 CloseLibrary((struct Library *) UtilityBase);
296 CloseLibrary(DOSBase);
298 KPRINTF(1, ("libExpunge: removing library node 0x%p\n",
299 &ps->ps_Library.lib_Node));
300 Remove(&ps->ps_Library.lib_Node);
302 return TRUE;
304 /* \\\ */
306 ADD2INITLIB(GM_UNIQUENAME(libInit), 0)
307 ADD2OPENLIB(GM_UNIQUENAME(libOpen), 0)
308 ADD2EXPUNGELIB(GM_UNIQUENAME(libExpunge), 0);
311 * ***********************************************************************
312 * * Library functions *
313 * ***********************************************************************
316 static const ULONG *PsdPTArray[PGA_LAST+1];
318 /* *** Memory *** */
320 /* /// "psdAllocVec()" */
321 AROS_LH1(APTR, psdAllocVec,
322 AROS_LHA(ULONG, size, D0),
323 LIBBASETYPEPTR, ps, 5, psd)
325 AROS_LIBFUNC_INIT
326 ULONG *pmem;
327 KPRINTF(1, ("psdAllocVec(%ld)\n", size));
328 #ifndef MEMDEBUG
329 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)))))
331 #else
332 if((pmem = AllocPooled(ps->ps_MemPool, size + (1*sizeof(ULONG)) + 1024)))
334 ULONG upos = size + (1*sizeof(ULONG));
335 UWORD unum = 1024;
336 UBYTE *dbptr = (UBYTE *) pmem;
337 while(unum--)
339 dbptr[upos] = upos;
340 upos++;
342 #endif
343 *pmem++ = size;
344 ps->ps_MemAllocated += size;
345 return((APTR) pmem);
347 return(NULL);
348 AROS_LIBFUNC_EXIT
350 /* \\\ */
352 /* /// "psdFreeVec()" */
353 AROS_LH1(void, psdFreeVec,
354 AROS_LHA(APTR, pmem, A1),
355 LIBBASETYPEPTR, ps, 6, psd)
357 AROS_LIBFUNC_INIT
358 ULONG size;
360 KPRINTF(1, ("psdFreeVec(%p)\n", pmem));
361 if(pmem)
363 size = ((ULONG *) pmem)[-1];
364 ps->ps_MemAllocated -= size;
366 #ifdef MEMDEBUG
367 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)) + 1024);
368 #else
369 FreePooled(ps->ps_MemPool, &((ULONG *) pmem)[-1], size + (1*sizeof(ULONG)));
370 #endif
372 AROS_LIBFUNC_EXIT
374 /* \\\ */
376 /* *** PBase *** */
378 /* /// "pDebugSemaInfo()" */
379 void pDebugSemaInfo(LIBBASETYPEPTR ps, struct PsdSemaInfo *psi)
381 struct PsdReadLock *prl;
382 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
383 "Semaphore %p %s (Excl/SharedLockCount %ld/%ld) (Owner: %s):",
384 psi->psi_LockSem,
385 psi->psi_LockSem->pls_Node.ln_Name,
386 psi->psi_LockSem->pls_ExclLockCount,
387 psi->psi_LockSem->pls_SharedLockCount,
388 psi->psi_LockSem->pls_Owner ? psi->psi_LockSem->pls_Owner->tc_Node.ln_Name : "None");
390 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_WaitQueue.lh_Head;
391 while(prl->prl_Node.ln_Succ)
393 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
394 " Waiting Task: %p (%s) %s",
395 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
396 prl->prl_IsExcl ? "Excl" : "Shared");
397 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
399 prl = (struct PsdReadLock *) psi->psi_LockSem->pls_ReadLocks.lh_Head;
400 while(prl->prl_Node.ln_Succ)
402 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
403 " Readlock Task: %p (%s), Count %ld",
404 prl->prl_Task, prl->prl_Task->tc_Node.ln_Name,
405 prl->prl_Count);
406 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
409 /* \\\ */
411 /* /// "pInitSem()" */
412 void pInitSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls, STRPTR name)
414 struct PsdSemaInfo *psi = NULL;
415 NewList(&pls->pls_WaitQueue);
416 NewList(&pls->pls_ReadLocks);
417 pls->pls_Node.ln_Name = name;
418 // struct should be nulled anyway
419 pls->pls_Owner = NULL;
420 pls->pls_ExclLockCount = 0;
421 pls->pls_SharedLockCount = 0;
422 pls->pls_Dead = FALSE;
424 Forbid();
425 psi = (struct PsdSemaInfo *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdSemaInfo));
426 if(!psi)
428 Permit();
429 return;
431 psi->psi_LockSem = pls;
432 AddTail(&ps->ps_DeadlockDebug, &psi->psi_Node);
433 Permit();
435 /* \\\ */
437 /* /// "pDeleteSem()" */
438 void pDeleteSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
440 struct PsdSemaInfo *psi;
441 Forbid();
442 pls->pls_Dead = TRUE;
443 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
444 while(psi->psi_Node.ln_Succ)
446 if(psi->psi_LockSem == pls)
448 if(pls->pls_SharedLockCount + pls->pls_ExclLockCount)
450 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Semaphore still locked when attempting to delete it!\n");
451 pDebugSemaInfo(ps, psi);
452 } else {
453 Remove(&psi->psi_Node);
454 FreePooled(ps->ps_SemaMemPool, psi, sizeof(struct PsdSemaInfo));
456 break;
458 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
460 Permit();
462 /* \\\ */
464 /* /// "pLockSemExcl()" */
465 void pLockSemExcl(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
467 struct PsdReadLock waitprl;
468 struct Task *thistask = FindTask(NULL);
470 waitprl.prl_Task = thistask;
471 waitprl.prl_IsExcl = TRUE;
473 Forbid();
476 // it's already mine!!
477 if(thistask == pls->pls_Owner)
479 break;
481 if(!pls->pls_ExclLockCount)
483 // easy case: no shared locks, no exclusive locker
484 if(!pls->pls_SharedLockCount)
486 break;
488 // sole readlock promotion case
489 if((pls->pls_SharedLockCount == 1) && ((struct PsdReadLock *) pls->pls_ReadLocks.lh_Head)->prl_Task == thistask)
491 KPRINTF(1, ("Promoting read lock (%p) to write lock!\n", thistask));
492 break;
496 // okay, bad luck, we've got to wait somehow
497 AddHead(&pls->pls_WaitQueue, &waitprl.prl_Node);
498 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
500 Wait(SIGF_SINGLE);
502 Remove(&waitprl.prl_Node);
503 } while(TRUE);
504 pls->pls_Owner = thistask;
505 pls->pls_ExclLockCount++;
506 Permit();
508 /* \\\ */
510 /* /// "pLockSemShared()" */
511 void pLockSemShared(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
513 struct PsdReadLock *prl;
514 struct Task *thistask = FindTask(NULL);
516 Forbid();
517 // is this already locked exclusively by me?
518 if(thistask == pls->pls_Owner)
520 // yes? then just increase exclusive lock count
521 pls->pls_ExclLockCount++;
522 Permit();
523 return;
526 // find existing readlock
527 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
528 while(prl->prl_Node.ln_Succ)
530 if(prl->prl_Task == thistask)
532 KPRINTF(1, ("Increasing ReadLock (%p) count to %ld\n", thistask, prl->prl_Count));
533 prl->prl_Count++;
534 Permit();
535 return;
537 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
540 // this is a new readlock, generate context
541 if(!(prl = (struct PsdReadLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdReadLock))))
543 KPRINTF(20, ("No mem for shared lock! context (%p) on %p\n", thistask, pls));
544 // try exclusive lock as fallback (needs no memory)
545 Permit();
546 pLockSemExcl(ps, pls);
547 return;
550 KPRINTF(1, ("New ReadLockShared context (%p) on %p\n", thistask, pls));
551 prl->prl_Task = thistask;
552 prl->prl_Count = 0;
553 prl->prl_IsExcl = FALSE;
555 // if it's exclusively locked, wait for this lock to vanish
556 while(pls->pls_Owner)
558 AddTail(&pls->pls_WaitQueue, &prl->prl_Node);
559 thistask->tc_SigRecvd &= ~SIGF_SINGLE;
561 Wait(SIGF_SINGLE);
563 Remove(&prl->prl_Node);
566 if(prl->prl_IsExcl)
568 // we got promoted by BorrowLocks during the process! So we don't need the shared stuff anymore
569 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
570 pls->pls_Owner = thistask;
571 pls->pls_ExclLockCount++;
572 } else {
573 // got the lock!
574 AddHead(&pls->pls_ReadLocks, &prl->prl_Node);
575 prl->prl_Count++;
576 pls->pls_SharedLockCount++;
578 Permit();
579 return;
581 /* \\\ */
583 /* /// "pUnlockSem()" */
584 void pUnlockSem(LIBBASETYPEPTR ps, struct PsdLockSem *pls)
586 struct PsdReadLock *prl;
587 struct Task *thistask = FindTask(NULL);
588 BOOL gotit = FALSE;
590 Forbid();
591 if(pls->pls_Owner)
593 // exclusively locked, this means unlocking task must be owner
594 if(pls->pls_Owner != thistask)
596 Permit();
597 psdDebugSemaphores();
598 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
599 "Attempt to unlock exclusive semaphore %p not owned by task %s!",
600 pls, thistask->tc_Node.ln_Name);
601 return;
604 if(--pls->pls_ExclLockCount)
606 // still locked
607 Permit();
608 return;
610 pls->pls_Owner = NULL;
611 // otherwise drop through and notify
612 } else {
613 if(!pls->pls_SharedLockCount)
615 Permit();
616 psdDebugSemaphores();
617 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
618 "Attempt to unlock (free) semaphore %p once too often by task %s!",
619 pls, thistask->tc_Node.ln_Name);
620 return;
622 // find readlock
623 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
624 while(prl->prl_Node.ln_Succ)
626 if(prl->prl_Task == thistask)
628 if(--prl->prl_Count)
630 // can't be the last lock, so just reduce count and return
631 Permit();
632 return;
634 // remove read lock, it's no longer needed
635 KPRINTF(1, ("Removing read lock context (%p) on %p!\n", thistask, pls));
636 Remove(&prl->prl_Node);
637 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
638 gotit = TRUE;
639 // losing a designated lock
640 pls->pls_SharedLockCount--;
641 break;
643 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
645 if(!gotit)
647 Permit();
648 psdDebugSemaphores();
649 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
650 "Attempt to unlock (shared) semaphore %p once too often by task %s!",
651 pls, thistask->tc_Node.ln_Name);
652 return;
655 // we need to notify anyway, because the waiter could already have a shared lock
656 // on the same semaphore, and if we only notified on LockCount reaching zero,
657 // the locker would wait forever.
660 // notify waiting tasks
661 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
662 while(prl->prl_Node.ln_Succ)
664 Signal(prl->prl_Task, SIGF_SINGLE);
665 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
667 Permit();
669 /* \\\ */
671 /* /// "psdDebugSemaphores()" */
672 AROS_LH0(void, psdDebugSemaphores,
673 LIBBASETYPEPTR, ps, 81, psd)
675 AROS_LIBFUNC_INIT
676 struct Task *thistask = FindTask(NULL);
677 struct PsdSemaInfo *psi;
679 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
680 "Debug Semaphores (%p)", thistask);
682 Forbid();
683 // search for context
684 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
685 while(psi->psi_Node.ln_Succ)
687 pDebugSemaInfo(ps, psi);
688 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
690 Permit();
691 AROS_LIBFUNC_EXIT
693 /* \\\ */
695 /* /// "psdLockReadPBase()" */
696 AROS_LH0(void, psdLockReadPBase,
697 LIBBASETYPEPTR, ps, 8, psd)
699 AROS_LIBFUNC_INIT
700 KPRINTF(2, ("psdLockReadPBase(%p)\n", FindTask(NULL)));
701 pLockSemShared(ps, &ps->ps_Lock);
702 AROS_LIBFUNC_EXIT
704 /* \\\ */
706 /* /// "psdLockWritePBase()" */
707 AROS_LH0(void, psdLockWritePBase,
708 LIBBASETYPEPTR, ps, 7, psd)
710 AROS_LIBFUNC_INIT
711 KPRINTF(2, ("psdLockWritePBase(%p)\n", FindTask(NULL)));
712 pLockSemExcl(ps, &ps->ps_Lock);
713 AROS_LIBFUNC_EXIT
715 /* \\\ */
717 /* /// "psdUnlockPBase()" */
718 AROS_LH0(void, psdUnlockPBase,
719 LIBBASETYPEPTR, ps, 9, psd)
721 AROS_LIBFUNC_INIT
722 KPRINTF(2, ("psdUnlockPBase(%p)\n", FindTask(NULL)));
723 pUnlockSem(ps, &ps->ps_Lock);
724 AROS_LIBFUNC_EXIT
726 /* \\\ */
728 /* /// "psdBorrowLocksWait()" */
729 AROS_LH2(ULONG, psdBorrowLocksWait,
730 AROS_LHA(struct Task *, task, A1),
731 AROS_LHA(ULONG, signals, D0),
732 LIBBASETYPEPTR, ps, 97, psd)
734 AROS_LIBFUNC_INIT
735 struct Task *thistask = FindTask(NULL);
736 ULONG cnt = 0;
737 ULONG sigmask;
738 struct PsdSemaInfo *psi;
739 struct PsdLockSem *pls;
740 struct PsdReadLock *prl;
741 struct PsdBorrowLock *pbl;
742 struct List borrows;
743 struct List reclaims;
744 BOOL moveowner;
746 XPRINTF(10, ("Borrowing locks from %p (%s) to %p (%s)!\n",
747 thistask, thistask->tc_Node.ln_Name, task, task->tc_Node.ln_Name));
749 Forbid();
750 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
751 while(psi->psi_Node.ln_Succ)
753 pls = psi->psi_LockSem;
754 if(pls->pls_Owner == thistask)
756 cnt++;
758 if(pls->pls_SharedLockCount)
760 struct PsdReadLock *prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
763 if(prl->prl_Task == thistask)
765 cnt++;
766 break;
768 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
770 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
772 if(!cnt)
774 Permit();
775 XPRINTF(10, ("Nothing to borrow!\n"));
776 return(Wait(signals));
779 NewList(&borrows);
780 NewList(&reclaims);
781 XPRINTF(10, ("Borrowing %ld locks\n", cnt));
783 psi = (struct PsdSemaInfo *) ps->ps_DeadlockDebug.lh_Head;
784 while(psi->psi_Node.ln_Succ)
786 moveowner = TRUE;
787 pls = psi->psi_LockSem;
788 if(pls->pls_Owner == thistask)
790 // check if the target task is already waiting for that lock
791 // in this case, we simply remove our exclusive lock and let
792 // the other task catch it
793 prl = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
794 while(prl->prl_Node.ln_Succ)
796 if(prl->prl_Task == task)
798 if(!prl->prl_IsExcl)
800 // if we hand over the excl lock, we have to make sure that the exclusiveness is kept
801 // and no other thread may catch it while it is shared.
802 // hence we will need set this lock exclusive aswell
803 // this no optimal solution, but it guarantees the same
804 // behaviour with pending lock and no pending lock
805 prl->prl_IsExcl = TRUE;
806 XPRINTF(10, ("Promo waiting lock to excl\n"));
808 // move shared lock to top of the list
809 Remove(&prl->prl_Node);
810 AddHead(&pls->pls_WaitQueue, &prl->prl_Node);
811 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
813 pbl->pbl_LockSem = pls;
814 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
815 AddTail(&reclaims, &pbl->pbl_Node);
817 // unlock exclusive lock
818 pls->pls_ExclLockCount = 0;
819 pls->pls_Owner = NULL;
820 Signal(task, SIGF_SINGLE);
821 XPRINTF(10, ("Waiting lock %p transfer\n", pls));
823 moveowner = FALSE;
824 break;
826 prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ;
828 if(moveowner)
830 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
832 pbl->pbl_LockSem = pls;
833 pbl->pbl_ExclLockCount = pls->pls_ExclLockCount;
834 AddTail(&borrows, &pbl->pbl_Node);
835 pls->pls_Owner = task;
836 XPRINTF(10, ("Lock %p transfer\n", pls));
840 if(pls->pls_SharedLockCount)
842 prl = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
845 if(prl->prl_Task == thistask)
847 // check if target task is waiting for this task
848 struct PsdReadLock *prl2 = (struct PsdReadLock *) pls->pls_WaitQueue.lh_Head;
849 while(prl2->prl_Node.ln_Succ)
851 if(prl2->prl_Task == task)
853 // move lock to top of the list
854 Remove(&prl2->prl_Node);
855 AddHead(&pls->pls_WaitQueue, &prl2->prl_Node);
856 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
858 pbl->pbl_LockSem = pls;
859 pbl->pbl_ReadLock = prl;
860 pbl->pbl_Count = prl->prl_Count;
861 AddHead(&reclaims, &pbl->pbl_Node);
863 // unlock shared lock
864 Remove(&prl->prl_Node);
865 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
866 pls->pls_SharedLockCount--;
867 Signal(task, SIGF_SINGLE);
869 moveowner = FALSE;
870 XPRINTF(10, ("Waiting shared lock %p transfer\n", pls));
871 break;
873 prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ;
875 if(moveowner)
877 // check if target task already has a shared lock on this
878 prl2 = (struct PsdReadLock *) pls->pls_ReadLocks.lh_Head;
881 if(prl2->prl_Task == task)
883 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
885 // we redirect to this other lock
886 pbl->pbl_LockSem = pls;
887 pbl->pbl_ReadLock = prl2;
888 pbl->pbl_Count = prl->prl_Count; // save the old lock count
889 AddTail(&borrows, &pbl->pbl_Node);
891 // unlock shared lock
892 Remove(&prl->prl_Node);
893 FreePooled(ps->ps_SemaMemPool, prl, sizeof(struct PsdReadLock));
894 pls->pls_SharedLockCount--;
895 // just increase lockcount, so a split occurs automatically
896 prl2->prl_Count += pbl->pbl_Count;
898 XPRINTF(10, ("Already locked %p transfer\n", pls));
899 moveowner = FALSE;
900 break;
902 } while((prl2 = (struct PsdReadLock *) prl2->prl_Node.ln_Succ)->prl_Node.ln_Succ);
904 if(moveowner)
906 if((pbl = (struct PsdBorrowLock *) AllocPooled(ps->ps_SemaMemPool, sizeof(struct PsdBorrowLock))))
908 pbl->pbl_LockSem = pls;
909 pbl->pbl_ReadLock = prl;
910 pbl->pbl_Count = prl->prl_Count;
911 AddTail(&borrows, &pbl->pbl_Node);
912 prl->prl_Task = task;
913 XPRINTF(10, ("Std lock %p transfer\n", pls));
916 break;
918 } while((prl = (struct PsdReadLock *) prl->prl_Node.ln_Succ)->prl_Node.ln_Succ);
920 psi = (struct PsdSemaInfo *) psi->psi_Node.ln_Succ;
923 sigmask = Wait(signals);
925 // try to get moved locks back first
926 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
927 while(pbl->pbl_Node.ln_Succ)
929 Remove(&pbl->pbl_Node);
930 pls = pbl->pbl_LockSem;
931 if(pbl->pbl_ExclLockCount)
933 if(pbl->pbl_ExclLockCount == pls->pls_ExclLockCount)
935 // all fine, other task didn't use the locks or returned them already
936 pls->pls_Owner = thistask;
937 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
938 } else {
939 // okay, bad thing, release lock and try to obtain it again -- eventually the other task should free the lock again
940 pls->pls_ExclLockCount -= pbl->pbl_ExclLockCount;
941 AddTail(&reclaims, &pbl->pbl_Node);
943 } else {
944 if(pls->pls_Owner == task)
946 // oh, damn. The other task converted our shared lock into an exclusive lock --
947 // we cannot claim this back right now. This gets tricky now.
948 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
950 // luckily, the count didn't change, so we just release the shared lock and requeue us into the reclaim list
951 Remove(&pbl->pbl_ReadLock->prl_Node);
952 FreePooled(ps->ps_SemaMemPool, pbl->pbl_ReadLock, sizeof(struct PsdReadLock));
953 pbl->pbl_ReadLock = NULL;
954 pls->pls_SharedLockCount--; // should turn to 0
955 } else {
956 // can it get worse? obviously, the alien task also has added some read locks
957 // this means we need to split up!
958 // therefore we leave a few lock counts and requeue
959 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
960 pbl->pbl_ReadLock = NULL;
962 AddHead(&reclaims, &pbl->pbl_Node);
963 } else {
964 if(pbl->pbl_Count == pbl->pbl_ReadLock->prl_Count)
966 // the count didn't change, just so just change owner
967 pbl->pbl_ReadLock->prl_Task = thistask;
968 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
969 } else {
970 // the alien task still has some read locks
971 // this means we need to split up!
972 // therefore we leave a few lock counts and requeue
973 pbl->pbl_ReadLock->prl_Count -= pbl->pbl_Count;
974 pbl->pbl_ReadLock = NULL;
975 AddHead(&reclaims, &pbl->pbl_Node);
979 pbl = (struct PsdBorrowLock *) borrows.lh_Head;
982 // try to reclaim released locks
983 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
984 while(pbl->pbl_Node.ln_Succ)
986 Remove(&pbl->pbl_Node);
987 pls = pbl->pbl_LockSem;
988 while(pbl->pbl_Count)
990 pLockSemShared(ps, pls);
991 --pbl->pbl_Count;
993 while(pbl->pbl_ExclLockCount)
995 pLockSemExcl(ps, pls);
996 --pbl->pbl_ExclLockCount;
998 FreePooled(ps->ps_SemaMemPool, pbl, sizeof(struct PsdBorrowLock));
999 pbl = (struct PsdBorrowLock *) reclaims.lh_Head;
1001 Permit();
1003 return(sigmask);
1004 AROS_LIBFUNC_EXIT
1006 /* \\\ */
1008 /* *** Support *** */
1010 /* /// "psdCopyStr()" */
1011 AROS_LH1(STRPTR, psdCopyStr,
1012 AROS_LHA(CONST_STRPTR, name, A0),
1013 LIBBASETYPEPTR, ps, 10, psd)
1015 AROS_LIBFUNC_INIT
1016 STRPTR rs = psdAllocVec((ULONG) strlen(name)+1);
1017 KPRINTF(1, ("psdCopyStr(%s)\n", name));
1018 if(rs)
1020 strcpy(rs, name);
1022 return(rs);
1023 AROS_LIBFUNC_EXIT
1025 /* \\\ */
1027 /* /// "psdSafeRawDoFmtA()" */
1028 AROS_LH4(void, psdSafeRawDoFmtA,
1029 AROS_LHA(STRPTR, buf, A0),
1030 AROS_LHA(ULONG, len, D0),
1031 AROS_LHA(CONST_STRPTR, fmtstr, A1),
1032 AROS_LHA(IPTR *, fmtdata, A2),
1033 LIBBASETYPEPTR, ps, 42, psd)
1035 AROS_LIBFUNC_INIT
1036 struct PsdRawDoFmt rdf;
1038 if(len > 0)
1040 rdf.rdf_Len = len;
1041 rdf.rdf_Buf = buf;
1042 RawDoFmt(fmtstr, fmtdata, (void (*)()) pPutChar, &rdf);
1043 buf[len-1] = 0;
1045 AROS_LIBFUNC_EXIT
1047 /* \\\ */
1049 /* /// "pPutChar()" */
1050 AROS_UFH2(void, pPutChar,
1051 AROS_UFHA(char, ch, D0),
1052 AROS_UFHA(struct PsdRawDoFmt *, rdf, A3))
1054 AROS_USERFUNC_INIT
1055 if(rdf->rdf_Len)
1057 rdf->rdf_Len--;
1058 *rdf->rdf_Buf++ = ch;
1060 AROS_USERFUNC_EXIT
1062 /* \\\ */
1064 /* /// "psdCopyStrFmtA()" */
1065 AROS_LH2(STRPTR, psdCopyStrFmtA,
1066 AROS_LHA(CONST_STRPTR, fmtstr, A0),
1067 AROS_LHA(IPTR *, fmtdata, A1),
1068 LIBBASETYPEPTR, ps, 68, psd)
1070 AROS_LIBFUNC_INIT
1071 ULONG len = 0;
1072 STRPTR buf;
1074 RawDoFmt(fmtstr, fmtdata, (void (*)()) pRawFmtLength, &len);
1075 buf = psdAllocVec(len+1);
1076 if(buf)
1078 psdSafeRawDoFmtA(buf, len+1, fmtstr, fmtdata);
1080 return(buf);
1081 AROS_LIBFUNC_EXIT
1083 /* \\\ */
1085 /* /// "pRawFmtLength()" */
1086 AROS_UFH2(void, pRawFmtLength,
1087 AROS_UFHA(char, ch, D0),
1088 AROS_UFHA(ULONG *, len, A3))
1090 AROS_USERFUNC_INIT
1091 (*len)++;
1092 AROS_USERFUNC_EXIT
1094 /* \\\ */
1096 /* /// "psdDelayMS()" */
1097 AROS_LH1(void, psdDelayMS,
1098 AROS_LHA(ULONG, milli, D0),
1099 LIBBASETYPEPTR, ps, 11, psd)
1101 AROS_LIBFUNC_INIT
1102 struct MsgPort mp;
1103 struct timerequest tr;
1105 KPRINTF(1, ("psdDelayMS(%ld)\n", milli));
1106 mp.mp_Flags = PA_SIGNAL;
1107 mp.mp_SigBit = SIGB_SINGLE;
1108 mp.mp_SigTask = FindTask(NULL);
1109 NewList(&mp.mp_MsgList);
1110 CopyMem(&ps->ps_TimerIOReq, &tr, sizeof(tr));
1111 tr.tr_node.io_Message.mn_ReplyPort = &mp;
1112 tr.tr_time.tv_secs = 0;
1113 tr.tr_time.tv_micro = milli * 1000;
1114 DoIO((struct IORequest *) &tr);
1115 AROS_LIBFUNC_EXIT
1117 /* \\\ */
1119 /* /// "psdGetAttrsA()" */
1120 AROS_LH3(LONG, psdGetAttrsA,
1121 AROS_LHA(ULONG, type, D0),
1122 AROS_LHA(APTR, psdstruct, A0),
1123 AROS_LHA(struct TagItem *, tags, A1),
1124 LIBBASETYPEPTR, ps, 22, psd)
1126 AROS_LIBFUNC_INIT
1127 struct TagItem *ti;
1128 ULONG count = 0;
1129 ULONG *packtab = NULL;
1131 KPRINTF(1, ("psdGetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1133 if(type <= PGA_LAST)
1135 packtab = (ULONG *) PsdPTArray[type];
1138 switch(type)
1140 case PGA_STACK:
1141 psdstruct = ps;
1142 if((ti = FindTagItem(PA_HardwareList, tags)))
1144 *((struct List **) ti->ti_Data) = &ps->ps_Hardware;
1145 count++;
1147 if((ti = FindTagItem(PA_ClassList, tags)))
1149 *((struct List **) ti->ti_Data) = &ps->ps_Classes;
1150 count++;
1152 if((ti = FindTagItem(PA_ErrorMsgList, tags)))
1154 *((struct List **) ti->ti_Data) = &ps->ps_ErrorMsgs;
1155 count++;
1157 break;
1159 case PGA_HARDWARE:
1160 if((ti = FindTagItem(HA_DeviceList, tags)))
1162 *((struct List **) ti->ti_Data) = &(((struct PsdHardware *) psdstruct)->phw_Devices);
1163 count++;
1165 break;
1167 case PGA_DEVICE:
1168 if((ti = FindTagItem(DA_ConfigList, tags)))
1170 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Configs);
1171 count++;
1173 if((ti = FindTagItem(DA_DescriptorList, tags)))
1175 *((struct List **) ti->ti_Data) = &(((struct PsdDevice *) psdstruct)->pd_Descriptors);
1176 count++;
1178 break;
1180 case PGA_CONFIG:
1181 if((ti = FindTagItem(CA_InterfaceList, tags)))
1183 *((struct List **) ti->ti_Data) = &(((struct PsdConfig *) psdstruct)->pc_Interfaces);
1184 count++;
1186 break;
1188 case PGA_INTERFACE:
1189 if((ti = FindTagItem(IFA_EndpointList, tags)))
1191 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_EPs);
1192 count++;
1194 if((ti = FindTagItem(IFA_AlternateIfList, tags)))
1196 *((struct List **) ti->ti_Data) = &(((struct PsdInterface *) psdstruct)->pif_AlterIfs);
1197 count++;
1199 break;
1201 case PGA_ERRORMSG:
1202 if((ti = FindTagItem(EMA_DateStamp, tags)))
1204 *((struct DateStamp **) ti->ti_Data) = &(((struct PsdErrorMsg *) psdstruct)->pem_DateStamp);
1205 count++;
1207 break;
1209 case PGA_PIPE:
1210 if((ti = FindTagItem(PPA_IORequest, tags)))
1212 *((struct IOUsbHWReq **) ti->ti_Data) = &(((struct PsdPipe *) psdstruct)->pp_IOReq);
1213 count++;
1215 break;
1217 case PGA_STACKCFG:
1218 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1220 count++;
1221 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_InsertSndFile;
1223 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1225 count++;
1226 *((STRPTR *) ti->ti_Data) = ps->ps_PoPo.po_RemoveSndFile;
1228 break;
1230 if(packtab)
1232 return((LONG) (UnpackStructureTags(psdstruct, (ULONG *) packtab, tags)+count));
1233 } else {
1234 return(-1);
1236 AROS_LIBFUNC_EXIT
1238 /* \\\ */
1240 /* /// "psdSetAttrsA()" */
1241 AROS_LH3(LONG, psdSetAttrsA,
1242 AROS_LHA(ULONG, type, D0),
1243 AROS_LHA(APTR, psdstruct, A0),
1244 AROS_LHA(struct TagItem *, tags, A1),
1245 LIBBASETYPEPTR, ps, 23, psd)
1247 AROS_LIBFUNC_INIT
1248 struct TagItem *ti;
1249 ULONG count = 0;
1250 ULONG *packtab = NULL;
1251 BOOL savepopocfg = FALSE;
1252 BOOL checkcfgupdate = FALSE;
1253 BOOL powercalc = FALSE;
1254 LONG res;
1256 KPRINTF(1, ("psdSetAttrsA(%ld, %p, %p)\n", type, psdstruct, tags));
1258 if(type <= PGA_LAST)
1260 packtab = (ULONG *) PsdPTArray[type];
1263 switch(type)
1265 case PGA_DEVICE:
1266 if(FindTagItem(DA_InhibitPopup, tags) || FindTagItem(DA_InhibitClassBind, tags))
1268 savepopocfg = TRUE;
1270 if(FindTagItem(DA_OverridePowerInfo, tags))
1272 savepopocfg = TRUE;
1273 powercalc = TRUE;
1275 break;
1277 case PGA_STACK:
1278 psdstruct = ps;
1279 break;
1281 case PGA_STACKCFG:
1282 if((ti = FindTagItem(GCA_InsertionSound, tags)))
1284 count++;
1285 if(strcmp(ps->ps_PoPo.po_InsertSndFile, (STRPTR) ti->ti_Data))
1287 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
1288 ps->ps_PoPo.po_InsertSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1291 if((ti = FindTagItem(GCA_RemovalSound, tags)))
1293 count++;
1294 if(strcmp(ps->ps_PoPo.po_RemoveSndFile, (STRPTR) ti->ti_Data))
1296 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
1297 ps->ps_PoPo.po_RemoveSndFile = psdCopyStr((STRPTR) ti->ti_Data);
1300 checkcfgupdate = TRUE;
1301 break;
1303 case PGA_PIPESTREAM:
1305 struct PsdPipeStream *pps = (struct PsdPipeStream *) psdstruct;
1306 struct PsdPipe *pp;
1307 ULONG oldbufsize = pps->pps_BufferSize;
1308 ULONG oldnumpipes = pps->pps_NumPipes;
1309 ULONG cnt;
1311 KPRINTF(1, ("SetAttrs PIPESTREAM\n"));
1312 ObtainSemaphore(&pps->pps_AccessLock);
1313 if((ti = FindTagItem(PSA_MessagePort, tags)))
1315 count++;
1316 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
1318 KPRINTF(1, ("Deleting old MsgPort\n"));
1319 DeleteMsgPort(pps->pps_MsgPort);
1320 pps->pps_MsgPort = NULL;
1322 pps->pps_Flags &= ~PSFF_OWNMSGPORT;
1324 count += PackStructureTags(psdstruct, packtab, tags);
1325 KPRINTF(1, ("Pipes = %ld (old: %ld), BufferSize = %ld (old: %ld)\n",
1326 pps->pps_NumPipes, oldnumpipes, pps->pps_BufferSize, oldbufsize));
1327 if(pps->pps_NumPipes < 1)
1329 pps->pps_NumPipes = 1; /* minimal */
1331 if(pps->pps_BufferSize < pps->pps_Endpoint->pep_MaxPktSize)
1333 pps->pps_BufferSize = pps->pps_Endpoint->pep_MaxPktSize; /* minimal */
1335 if(!pps->pps_MsgPort)
1337 if((pps->pps_MsgPort = CreateMsgPort()))
1339 KPRINTF(1, ("Creating MsgPort\n"));
1340 pps->pps_Flags |= PSFF_OWNMSGPORT;
1343 /* do we need to reallocate? */
1344 if((oldbufsize != pps->pps_BufferSize) ||
1345 (oldnumpipes != pps->pps_NumPipes) ||
1346 (!pps->pps_Pipes) ||
1347 (!pps->pps_Buffer))
1349 if(pps->pps_Pipes)
1351 KPRINTF(1, ("freeing %ld old pipes\n", oldnumpipes));
1352 for(cnt = 0; cnt < oldnumpipes; cnt++)
1354 pp = pps->pps_Pipes[cnt];
1355 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
1357 KPRINTF(1, ("Abort %ld\n", cnt));
1358 psdAbortPipe(pp);
1359 KPRINTF(1, ("Wait %ld\n", cnt));
1360 psdWaitPipe(pp);
1362 KPRINTF(1, ("Free %ld\n", cnt));
1363 psdFreePipe(pp);
1365 psdFreeVec(pps->pps_Pipes);
1367 psdFreeVec(pps->pps_Buffer);
1368 /* reset stuff */
1369 NewList(&pps->pps_FreePipes);
1370 NewList(&pps->pps_ReadyPipes);
1371 pps->pps_Offset = 0;
1372 pps->pps_BytesPending = 0;
1373 pps->pps_ReqBytes = 0;
1374 pps->pps_ActivePipe = NULL;
1375 pps->pps_Buffer = psdAllocVec(pps->pps_NumPipes * pps->pps_BufferSize);
1376 pps->pps_Pipes = psdAllocVec(pps->pps_NumPipes * sizeof(struct PsdPipe *));
1377 if(pps->pps_Pipes && pps->pps_Buffer)
1379 KPRINTF(1, ("allocating %ld new pipes\n", pps->pps_NumPipes));
1380 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
1382 pp = psdAllocPipe(pps->pps_Device, pps->pps_MsgPort, pps->pps_Endpoint);
1383 if((pps->pps_Pipes[cnt] = pp))
1385 pp->pp_Num = cnt;
1386 if(pps->pps_Flags & PSFF_NOSHORTPKT) pp->pp_IOReq.iouh_Flags |= UHFF_NOSHORTPKT;
1387 if(pps->pps_Flags & PSFF_NAKTIMEOUT) pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
1388 if(pps->pps_Flags & PSFF_ALLOWRUNT) pp->pp_IOReq.iouh_Flags |= UHFF_ALLOWRUNTPKTS;
1389 pp->pp_IOReq.iouh_NakTimeout = pps->pps_NakTimeoutTime;
1390 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
1391 } else {
1392 KPRINTF(1, ("Allocating Pipe %ld failed!\n", cnt));
1395 } else {
1396 KPRINTF(1, ("Allocating Pipe array failed!\n"));
1397 psdFreeVec(pps->pps_Buffer);
1398 pps->pps_Buffer = NULL;
1399 psdFreeVec(pps->pps_Pipes);
1400 pps->pps_Pipes = NULL;
1403 ReleaseSemaphore(&pps->pps_AccessLock);
1404 return((LONG) count);
1408 if(packtab)
1410 res = (LONG) PackStructureTags(psdstruct, packtab, tags);
1411 } else {
1412 res = -1;
1414 if(savepopocfg)
1416 struct PsdDevice *pd = (struct PsdDevice *) psdstruct;
1417 struct PsdIFFContext *pic;
1419 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1420 if(!pic)
1422 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
1423 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
1425 if(pic)
1427 pAddCfgChunk(ps, pic, &pd->pd_PoPoCfg);
1428 checkcfgupdate = TRUE;
1431 if(checkcfgupdate)
1433 pUpdateGlobalCfg(ps, (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head);
1434 pCheckCfgChanged(ps);
1436 if(powercalc)
1438 psdCalculatePower(((struct PsdDevice *) psdstruct)->pd_Hardware);
1440 return(res);
1441 AROS_LIBFUNC_EXIT
1443 /* \\\ */
1445 /* /// "psdSpawnSubTask()" */
1446 AROS_LH3(struct Task *, psdSpawnSubTask,
1447 AROS_LHA(STRPTR, name, A0),
1448 AROS_LHA(APTR, initpc, A1),
1449 AROS_LHA(APTR, userdata, A2),
1450 LIBBASETYPEPTR, ps, 39, psd)
1452 AROS_LIBFUNC_INIT
1453 #define SUBTASKSTACKSIZE 8192
1454 struct
1456 struct MemList mrm_ml;
1457 struct MemEntry mtm_me[2];
1458 } memlist;
1460 struct MemList *newmemlist;
1461 struct MemEntry *me;
1462 struct Task *nt;
1463 struct Process *subtask;
1465 if(!(name && initpc))
1467 return(NULL);
1470 /* If there's dos available, create a process instead of a task */
1471 if(pOpenDOS(ps))
1473 subtask = CreateNewProcTags(NP_Entry, initpc,
1474 NP_StackSize, SUBTASKSTACKSIZE,
1475 NP_Priority, ps->ps_GlobalCfg->pgc_SubTaskPri,
1476 NP_Name, name,
1477 NP_CopyVars, FALSE,
1478 NP_UserData, userdata,
1479 TAG_END);
1480 return((struct Task *) subtask);
1483 /* Allocate memory of memlist */
1485 memlist.mrm_ml.ml_Node.ln_Type = NT_MEMORY;
1486 memlist.mrm_ml.ml_Node.ln_Pri = 0;
1487 memlist.mrm_ml.ml_Node.ln_Name = NULL;
1488 memlist.mrm_ml.ml_NumEntries = 3;
1489 me = &memlist.mrm_ml.ml_ME[0];
1490 me[1].me_Un.meu_Reqs = memlist.mrm_ml.ml_ME[0].me_Un.meu_Reqs = MEMF_CLEAR|MEMF_PUBLIC;
1491 me[0].me_Length = sizeof(struct Task);
1492 me[1].me_Length = SUBTASKSTACKSIZE;
1493 me[2].me_Un.meu_Reqs = MEMF_PUBLIC;
1494 me[2].me_Length = strlen(name) + 1;
1496 #ifdef __AROS__
1497 newmemlist = NewAllocEntry(&memlist.mrm_ml, NULL);
1498 if (!newmemlist)
1499 #else
1500 newmemlist = AllocEntry(&memlist.mrm_ml);
1501 if((IPTR) newmemlist & 0x80000000)
1502 #endif
1504 return(NULL);
1506 me = &newmemlist->ml_ME[0];
1507 nt = me[0].me_Un.meu_Addr;
1508 nt->tc_Node.ln_Name = me[2].me_Un.meu_Addr;
1509 strcpy(nt->tc_Node.ln_Name, name);
1510 nt->tc_Node.ln_Type = NT_TASK;
1511 nt->tc_Node.ln_Pri = ps->ps_GlobalCfg->pgc_SubTaskPri;
1512 nt->tc_SPLower = me[1].me_Un.meu_Addr;
1513 nt->tc_SPUpper = nt->tc_SPReg = (APTR) ((IPTR) nt->tc_SPLower + SUBTASKSTACKSIZE);
1514 nt->tc_UserData = userdata;
1515 NewList(&nt->tc_MemEntry);
1516 AddTail(&nt->tc_MemEntry, (struct Node *) newmemlist);
1517 KPRINTF(1, ("TDNestCnt=%ld\n", SysBase->TDNestCnt));
1518 if((nt = AddTask(nt, initpc, NULL)))
1520 XPRINTF(10, ("Started task %p (%s)\n", nt, name));
1521 return(nt);
1523 FreeEntry(newmemlist);
1524 return(NULL);
1525 AROS_LIBFUNC_EXIT
1527 /* \\\ */
1529 /* /// "psdNumToStr()" */
1530 AROS_LH3(STRPTR, psdNumToStr,
1531 AROS_LHA(UWORD, type, D0),
1532 AROS_LHA(LONG, idx, D1),
1533 AROS_LHA(STRPTR, defstr, A0),
1534 LIBBASETYPEPTR, ps, 38, psd)
1536 AROS_LIBFUNC_INIT
1537 switch(type)
1539 case NTS_IOERR:
1541 const struct PsdWStringMap *psm = usbhwioerrstr;
1542 while(psm->psm_ID)
1544 if(psm->psm_ID == idx)
1546 return(psm->psm_String);
1548 psm++;
1550 break;
1553 case NTS_LANGID:
1555 const struct PsdUWStringMap *psm = usblangids;
1556 while(psm->psm_ID)
1558 if(psm->psm_ID == idx)
1560 return(psm->psm_String);
1562 psm++;
1564 break;
1567 case NTS_TRANSTYPE:
1568 switch(idx)
1570 case USEAF_CONTROL:
1571 return("control");
1572 case USEAF_ISOCHRONOUS:
1573 return("isochronous");
1574 case USEAF_BULK:
1575 return("bulk");
1576 case USEAF_INTERRUPT:
1577 return("interrupt");
1579 break;
1581 case NTS_SYNCTYPE:
1582 switch(idx)
1584 case USEAF_NOSYNC:
1585 return("no synchronization");
1586 case USEAF_ASYNC:
1587 return("asynchronous");
1588 case USEAF_ADAPTIVE:
1589 return("adaptive");
1590 case USEAF_SYNC:
1591 return("synchronous");
1593 break;
1595 case NTS_USAGETYPE:
1596 switch(idx)
1598 case USEAF_DATA:
1599 return("data");
1600 case USEAF_FEEDBACK:
1601 return("feedback");
1602 case USEAF_IMPLFEEDBACK:
1603 return("implicit feedback data");
1605 break;
1607 case NTS_VENDORID:
1609 const struct PsdUWStringMap *psm = usbvendorids;
1610 while(psm->psm_ID)
1612 if(psm->psm_ID == idx)
1614 return(psm->psm_String);
1616 psm++;
1618 break;
1621 case NTS_CLASSCODE:
1623 const struct PsdWStringMap *psm = usbclasscodestr;
1624 while(psm->psm_ID)
1626 if(psm->psm_ID == idx)
1628 return(psm->psm_String);
1630 psm++;
1632 break;
1635 case NTS_DESCRIPTOR:
1637 const struct PsdULStringMap *psm = usbdesctypestr;
1638 while(psm->psm_ID)
1640 if(psm->psm_ID == idx)
1642 return(psm->psm_String);
1644 psm++;
1646 break;
1649 case NTS_COMBOCLASS:
1651 const struct PsdULStringMap *psm = usbcomboclasscodestr;
1652 if(idx & (NTSCCF_CLASS|NTSCCF_SUBCLASS|NTSCCF_PROTO))
1654 while(psm->psm_ID)
1656 BOOL take;
1657 take = TRUE;
1658 if(psm->psm_ID & NTSCCF_CLASS)
1660 if((!(idx & NTSCCF_CLASS)) || ((idx & 0x0000ff) != (psm->psm_ID & 0x0000ff)))
1662 take = FALSE;
1665 if(psm->psm_ID & NTSCCF_SUBCLASS)
1667 if((!(idx & NTSCCF_SUBCLASS)) || ((idx & 0x00ff00) != (psm->psm_ID & 0x00ff00)))
1669 take = FALSE;
1672 if(psm->psm_ID & NTSCCF_PROTO)
1674 if((!(idx & NTSCCF_PROTO)) || ((idx & 0xff0000) != (psm->psm_ID & 0xff0000)))
1676 take = FALSE;
1679 if(take)
1681 return(psm->psm_String);
1683 psm++;
1686 break;
1689 return(defstr);
1690 AROS_LIBFUNC_EXIT
1692 /* \\\ */
1694 /* *** Endpoint *** */
1696 /* /// "pFreeEndpoint()" */
1697 void pFreeEndpoint(struct PsdEndpoint *pep)
1699 LIBBASETYPEPTR ps = pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Base;
1700 KPRINTF(2, (" FreeEndpoint()\n"));
1701 Remove(&pep->pep_Node);
1702 psdFreeVec(pep);
1704 /* \\\ */
1706 /* /// "pAllocEndpoint()" */
1707 struct PsdEndpoint * pAllocEndpoint(struct PsdInterface *pif)
1709 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1710 struct PsdEndpoint *pep;
1711 if((pep = psdAllocVec(sizeof(struct PsdEndpoint))))
1713 pep->pep_Interface = pif;
1714 AddTail(&pif->pif_EPs, &pep->pep_Node);
1715 return(pep);
1717 return(NULL);
1719 /* \\\ */
1721 /* /// "psdFindEndpointA()" */
1722 AROS_LH3(struct PsdEndpoint *, psdFindEndpointA,
1723 AROS_LHA(struct PsdInterface *, pif, A0),
1724 AROS_LHA(struct PsdEndpoint *, pep, A2),
1725 AROS_LHA(struct TagItem *, tags, A1),
1726 LIBBASETYPEPTR, ps, 67, psd)
1728 AROS_LIBFUNC_INIT
1729 struct TagItem *ti;
1730 BOOL takeit;
1732 KPRINTF(2, ("psdFindEndpointA(%p, %p, %p)\n", pif, pep, tags));
1733 if(!pep)
1735 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1736 } else {
1737 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1739 while(pep->pep_Node.ln_Succ)
1741 takeit = TRUE;
1742 if((ti = FindTagItem(EA_IsIn, tags)))
1744 if((ti->ti_Data && !pep->pep_Direction) || (!ti->ti_Data && pep->pep_Direction))
1746 takeit = FALSE;
1749 if((ti = FindTagItem(EA_EndpointNum, tags)))
1751 if(ti->ti_Data != pep->pep_EPNum)
1753 takeit = FALSE;
1756 if((ti = FindTagItem(EA_TransferType, tags)))
1758 if(ti->ti_Data != pep->pep_TransType)
1760 takeit = FALSE;
1763 if((ti = FindTagItem(EA_MaxPktSize, tags)))
1765 if(ti->ti_Data != pep->pep_MaxPktSize)
1767 takeit = FALSE;
1770 if((ti = FindTagItem(EA_Interval, tags)))
1772 if(ti->ti_Data != pep->pep_Interval)
1774 takeit = FALSE;
1778 if(takeit)
1780 return(pep);
1782 pep = (struct PsdEndpoint *) pep->pep_Node.ln_Succ;
1784 return(NULL);
1785 AROS_LIBFUNC_EXIT
1787 /* \\\ */
1789 /* *** Interface *** */
1791 /* /// "pFreeInterface()" */
1792 void pFreeInterface(struct PsdInterface *pif)
1794 LIBBASETYPEPTR ps = pif->pif_Config->pc_Device->pd_Hardware->phw_Base;
1795 struct PsdEndpoint *pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1796 struct PsdInterface *altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1797 KPRINTF(2, (" FreeInterface()\n"));
1798 /* Remove alternate interfaces */
1799 while(altif->pif_Node.ln_Succ)
1801 pFreeInterface(altif);
1802 altif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1804 /* Remove endpoints */
1805 while(pep->pep_Node.ln_Succ)
1807 pFreeEndpoint(pep);
1808 pep = (struct PsdEndpoint *) pif->pif_EPs.lh_Head;
1810 psdFreeVec(pif->pif_IfStr);
1811 psdFreeVec(pif->pif_IDString);
1812 Remove(&pif->pif_Node);
1813 psdFreeVec(pif);
1815 /* \\\ */
1817 /* /// "pAllocInterface()" */
1818 struct PsdInterface * pAllocInterface(struct PsdConfig *pc)
1820 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
1821 struct PsdInterface *pif;
1822 if((pif = psdAllocVec(sizeof(struct PsdInterface))))
1824 pif->pif_Config = pc;
1825 NewList(&pif->pif_EPs);
1826 NewList(&pif->pif_AlterIfs);
1827 AddTail(&pc->pc_Interfaces, &pif->pif_Node);
1828 return(pif);
1830 return(NULL);
1832 /* \\\ */
1834 /* /// "psdFindInterfaceA()" */
1835 AROS_LH3(struct PsdInterface *, psdFindInterfaceA,
1836 AROS_LHA(struct PsdDevice *, pd, A0),
1837 AROS_LHA(struct PsdInterface *, pif, A2),
1838 AROS_LHA(struct TagItem *, tags, A1),
1839 LIBBASETYPEPTR, ps, 66, psd)
1841 AROS_LIBFUNC_INIT
1842 struct PsdConfig *pc;
1843 struct TagItem *ti;
1844 BOOL takeit;
1845 BOOL searchalt = FALSE;
1846 BOOL isalt = FALSE;
1847 struct PsdInterface *oldpif = NULL;
1849 KPRINTF(2, ("psdFindInterfaceA(%p, %p, %p)\n", pd, pif, tags));
1850 if(!pif)
1852 pc = pd->pd_CurrentConfig;
1853 if(pc)
1855 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
1857 if(!pif)
1859 return(NULL);
1861 } else {
1862 if(FindTagItem(IFA_AlternateNum, tags))
1864 searchalt = TRUE;
1866 if(pif->pif_ParentIf)
1868 // special case: we are in an alternate interface right now
1869 searchalt = TRUE;
1870 if(pif->pif_Node.ln_Succ)
1872 isalt = TRUE;
1873 oldpif = pif->pif_ParentIf;
1874 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1875 } else {
1876 pif = (struct PsdInterface *) pif->pif_ParentIf->pif_Node.ln_Succ;
1878 } else {
1879 // go into alt interfaces
1880 if(searchalt && pif->pif_AlterIfs.lh_Head->ln_Succ)
1882 isalt = TRUE;
1883 oldpif = pif;
1884 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1885 } else {
1886 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1891 while(pif->pif_Node.ln_Succ)
1893 takeit = TRUE;
1894 if((ti = FindTagItem(IFA_InterfaceNum, tags)))
1896 if(ti->ti_Data != pif->pif_IfNum)
1898 takeit = FALSE;
1901 if((ti = FindTagItem(IFA_AlternateNum, tags)))
1903 searchalt = TRUE;
1904 if(ti->ti_Data <= 0xff) // if alternate number is greater than 0xff, don't check compliance, but just enable alternate interface searching
1906 if(ti->ti_Data != pif->pif_Alternate)
1908 takeit = FALSE;
1912 if((ti = FindTagItem(IFA_NumEndpoints, tags)))
1914 if(ti->ti_Data != pif->pif_NumEPs)
1916 takeit = FALSE;
1919 if((ti = FindTagItem(IFA_Class, tags)))
1921 if(ti->ti_Data != pif->pif_IfClass)
1923 takeit = FALSE;
1926 if((ti = FindTagItem(IFA_SubClass, tags)))
1928 if(ti->ti_Data != pif->pif_IfSubClass)
1930 takeit = FALSE;
1933 if((ti = FindTagItem(IFA_Protocol, tags)))
1935 if(ti->ti_Data != pif->pif_IfProto)
1937 takeit = FALSE;
1940 if((ti = FindTagItem(IFA_Binding, tags)))
1942 if((APTR) ti->ti_Data != pif->pif_IfBinding)
1944 takeit = FALSE;
1947 if((ti = FindTagItem(IFA_InterfaceName, tags)))
1949 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IfStr))
1951 takeit = FALSE;
1954 if((ti = FindTagItem(IFA_IDString, tags)))
1956 if(strcmp((STRPTR) ti->ti_Data, pif->pif_IDString))
1958 takeit = FALSE;
1962 if(takeit)
1964 return(pif);
1966 if(searchalt)
1968 if(isalt)
1970 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1971 if(!pif->pif_Node.ln_Succ)
1973 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1974 isalt = FALSE;
1976 } else {
1977 oldpif = pif;
1978 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
1979 if(!pif->pif_Node.ln_Succ)
1981 pif = (struct PsdInterface *) oldpif->pif_Node.ln_Succ;
1982 } else {
1983 isalt = TRUE;
1986 } else {
1987 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
1990 return(NULL);
1991 AROS_LIBFUNC_EXIT
1993 /* \\\ */
1995 /* *** Config *** */
1997 /* /// "pFreeConfig()" */
1998 void pFreeConfig(struct PsdConfig *pc)
2000 LIBBASETYPEPTR ps = pc->pc_Device->pd_Hardware->phw_Base;
2001 struct PsdInterface *pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2002 KPRINTF(2, (" FreeConfig()\n"));
2003 while(pif->pif_Node.ln_Succ)
2005 psdReleaseIfBinding(pif);
2006 pFreeInterface(pif);
2007 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2009 psdFreeVec(pc->pc_CfgStr);
2010 Remove(&pc->pc_Node);
2011 psdFreeVec(pc);
2013 /* \\\ */
2015 /* /// "pAllocConfig()" */
2016 struct PsdConfig * pAllocConfig(struct PsdDevice *pd)
2018 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2019 struct PsdConfig *pc;
2020 KPRINTF(2, (" AllocConfig()\n"));
2021 if((pc = psdAllocVec(sizeof(struct PsdConfig))))
2023 pc->pc_Device = pd;
2024 NewList(&pc->pc_Interfaces);
2025 AddTail(&pd->pd_Configs, &pc->pc_Node);
2026 return(pc);
2028 return(NULL);
2030 /* \\\ */
2032 /* *** Descriptors *** */
2034 /* /// "pFreeDescriptor()" */
2035 void pFreeDescriptor(struct PsdDescriptor *pdd)
2037 LIBBASETYPEPTR ps = pdd->pdd_Device->pd_Hardware->phw_Base;
2038 KPRINTF(2, (" FreeDescriptor()\n"));
2039 //psdFreeVec(pdd->pdd_Data); // part of the structure alloc
2040 Remove(&pdd->pdd_Node);
2041 psdFreeVec(pdd);
2043 /* \\\ */
2045 /* /// "pAllocDescriptor()" */
2046 struct PsdDescriptor * pAllocDescriptor(struct PsdDevice *pd, UBYTE *buf)
2048 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
2049 struct PsdDescriptor *pdd;
2051 KPRINTF(2, (" AllocDescriptor()\n"));
2052 if((pdd = psdAllocVec(sizeof(struct PsdDescriptor) + (ULONG) buf[0])))
2054 pdd->pdd_Device = pd;
2055 pdd->pdd_Data = ((UBYTE *) pdd) + sizeof(struct PsdDescriptor);
2056 pdd->pdd_Length = buf[0];
2057 pdd->pdd_Type = buf[1];
2058 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
2060 pdd->pdd_CSSubType = buf[2];
2062 pdd->pdd_Name = psdNumToStr(NTS_DESCRIPTOR, (LONG) pdd->pdd_Type, "<unknown>");
2063 CopyMem(buf, pdd->pdd_Data, (ULONG) buf[0]);
2064 AddTail(&pd->pd_Descriptors, &pdd->pdd_Node);
2065 return(pdd);
2067 return(NULL);
2069 /* \\\ */
2071 /* /// "psdFindDescriptorA()" */
2072 AROS_LH3(struct PsdDescriptor *, psdFindDescriptorA,
2073 AROS_LHA(struct PsdDevice *, pd, A0),
2074 AROS_LHA(struct PsdDescriptor *, pdd, A2),
2075 AROS_LHA(struct TagItem *, tags, A1),
2076 LIBBASETYPEPTR, ps, 91, psd)
2078 AROS_LIBFUNC_INIT
2079 struct PsdConfig *pc = pd->pd_CurrentConfig;
2080 struct TagItem *ti;
2081 BOOL takeit;
2083 KPRINTF(2, ("psdFindDescriptorA(%p, %p, %p)\n", pd, pdd, tags));
2084 if(!pdd)
2086 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2087 } else {
2088 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2091 while(pdd->pdd_Node.ln_Succ)
2093 takeit = TRUE;
2095 if((ti = FindTagItem(DDA_Config, tags)))
2097 // special case to workaround default: with NULL given, all configs are matched
2098 if(ti->ti_Data && (((struct PsdConfig *) ti->ti_Data) != pdd->pdd_Config))
2100 takeit = FALSE;
2102 } else {
2103 // only take descriptors from the current configuration by default
2104 if(pc != pdd->pdd_Config)
2106 takeit = FALSE;
2109 if((ti = FindTagItem(DDA_Interface, tags)))
2111 if(((struct PsdInterface *) ti->ti_Data) != pdd->pdd_Interface)
2113 takeit = FALSE;
2116 if((ti = FindTagItem(DDA_Endpoint, tags)))
2118 if(((struct PsdEndpoint *) ti->ti_Data) != pdd->pdd_Endpoint)
2120 takeit = FALSE;
2123 if((ti = FindTagItem(DDA_DescriptorType, tags)))
2125 if(ti->ti_Data != pdd->pdd_Type)
2127 takeit = FALSE;
2130 if((ti = FindTagItem(DDA_CS_SubType, tags)))
2132 if(ti->ti_Data != pdd->pdd_CSSubType)
2134 takeit = FALSE;
2137 if((ti = FindTagItem(DDA_DescriptorLength, tags)))
2139 if(ti->ti_Data != pdd->pdd_Length)
2141 takeit = FALSE;
2145 if(takeit)
2147 return(pdd);
2149 pdd = (struct PsdDescriptor *) pdd->pdd_Node.ln_Succ;
2151 return(NULL);
2152 AROS_LIBFUNC_EXIT
2154 /* \\\ */
2156 /* *** Device *** */
2158 /* /// "pFreeBindings()" */
2159 void pFreeBindings(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2161 struct PsdHardware *phw = pd->pd_Hardware;
2162 struct PsdConfig *pc;
2163 struct PsdInterface *pif;
2164 KPRINTF(3, (" FreeBindings(%p)\n", pd));
2166 /* move device to list of dead devices first
2167 This caused a lot of trouble as it could
2168 happen that a device got into class scan
2169 right after the bindings had been released. */
2170 psdLockWritePBase();
2171 Remove(&pd->pd_Node);
2172 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2173 psdUnlockPBase();
2175 /* If there are bindings, get rid of them. */
2176 psdLockWriteDevice(pd);
2177 psdReleaseDevBinding(pd);
2179 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2180 while(pc->pc_Node.ln_Succ)
2182 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2183 while(pif->pif_Node.ln_Succ)
2185 psdReleaseIfBinding(pif);
2186 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2188 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2190 psdUnlockDevice(pd);
2192 /* \\\ */
2194 /* /// "pFreeDevice()" */
2195 void pFreeDevice(LIBBASETYPEPTR ps, struct PsdDevice *pd)
2197 struct PsdHardware *phw = pd->pd_Hardware;
2198 struct PsdConfig *pc;
2199 struct PsdDescriptor *pdd;
2201 psdCalculatePower(phw);
2202 psdLockWriteDevice(pd);
2203 if(pd->pd_UseCnt)
2205 KPRINTF(20, ("Couldn't free device, use cnt %ld\n", pd->pd_UseCnt));
2206 pd->pd_Flags &= ~PDFF_CONNECTED;
2207 pd->pd_Flags |= PDFF_DELEXPUNGE;
2208 psdUnlockDevice(pd);
2209 } else {
2210 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2211 while(pc->pc_Node.ln_Succ)
2213 pFreeConfig(pc);
2214 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2217 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2218 while(pdd->pdd_Node.ln_Succ)
2220 pFreeDescriptor(pdd);
2221 pdd = (struct PsdDescriptor *) pd->pd_Descriptors.lh_Head;
2224 psdFreeVec(pd->pd_LangIDArray);
2225 pd->pd_LangIDArray = NULL;
2226 psdFreeVec(pd->pd_MnfctrStr);
2227 pd->pd_MnfctrStr = NULL;
2228 /*if(!ps->ps_PoPo.po_Task) // keep name at least
2230 psdFreeVec(pd->pd_ProductStr);
2231 pd->pd_ProductStr = NULL;
2233 psdFreeVec(pd->pd_OldProductStr);
2234 pd->pd_OldProductStr = NULL;
2235 psdFreeVec(pd->pd_SerNumStr);
2236 pd->pd_SerNumStr = NULL;
2237 psdFreeVec(pd->pd_IDString);
2238 pd->pd_IDString = NULL;
2239 if(pd->pd_DevAddr)
2241 KPRINTF(5,("Released DevAddr %ld\n", pd->pd_DevAddr));
2242 phw->phw_DevArray[pd->pd_DevAddr] = NULL;
2244 psdUnlockDevice(pd);
2245 psdLockWritePBase();
2246 Remove(&pd->pd_Node);
2247 psdUnlockPBase();
2248 pDeleteSem(ps, &pd->pd_Lock);
2249 /* cannot free this vector -- tasks might still call LockDevice */
2250 //psdFreeVec(pd);
2252 KPRINTF(3, ("FreeDevice done\n"));
2254 /* \\\ */
2256 /* /// "psdFreeDevice()" */
2257 AROS_LH1(void, psdFreeDevice,
2258 AROS_LHA(struct PsdDevice *, pd, A0),
2259 LIBBASETYPEPTR, ps, 16, psd)
2261 AROS_LIBFUNC_INIT
2262 struct PsdHardware *phw = pd->pd_Hardware;
2263 struct PsdConfig *pc;
2264 struct PsdInterface *pif;
2265 struct PsdRTIsoHandler *prt;
2266 struct PsdRTIsoHandler *nextprt;
2268 KPRINTF(3, (" FreeDevice(%p)\n", pd));
2270 /* move device to list of dead devices first
2271 This caused a lot of trouble as it could
2272 happen that a device got into class scan
2273 right after the bindings had been released. */
2274 psdLockWritePBase();
2275 Remove(&pd->pd_Node);
2276 AddTail(&phw->phw_DeadDevices, &pd->pd_Node);
2277 pd->pd_Flags &= ~PDFF_DELEXPUNGE;
2278 psdUnlockPBase();
2280 psdLockWriteDevice(pd);
2282 /* Inform all ISO handlers about the device going offline */
2283 prt = (struct PsdRTIsoHandler *) pd->pd_RTIsoHandlers.lh_Head;
2284 while((nextprt = (struct PsdRTIsoHandler *) prt->prt_Node.ln_Succ))
2286 if(prt->prt_ReleaseHook)
2288 CallHookPkt(prt->prt_ReleaseHook, prt, NULL);
2290 prt = nextprt;
2293 /* If there are bindings, get rid of them. */
2294 psdHubReleaseDevBinding(pd);
2296 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2297 while(pc->pc_Node.ln_Succ)
2299 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2300 while(pif->pif_Node.ln_Succ)
2302 psdHubReleaseIfBinding(pif);
2303 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
2305 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2307 psdUnlockDevice(pd);
2309 pFreeDevice(ps, pd);
2310 AROS_LIBFUNC_EXIT
2312 /* \\\ */
2314 /* /// "psdAllocDevice()" */
2315 AROS_LH1(struct PsdDevice *, psdAllocDevice,
2316 AROS_LHA(struct PsdHardware *, phw, A0),
2317 LIBBASETYPEPTR, ps, 15, psd)
2319 AROS_LIBFUNC_INIT
2320 struct PsdDevice *pd;
2321 KPRINTF(2, ("psdAllocDevice(%p)\n", phw));
2322 if((pd = psdAllocVec(sizeof(struct PsdDevice))))
2324 pd->pd_Hardware = phw;
2325 pd->pd_Hub = NULL;
2326 pd->pd_MaxPktSize0 = 8;
2328 pInitSem(ps, &pd->pd_Lock, "Device");
2330 NewList(&pd->pd_Configs);
2331 NewList(&pd->pd_Descriptors);
2332 NewList(&pd->pd_RTIsoHandlers);
2334 // init prefs
2335 pd->pd_PoPoCfg.poc_ChunkID = AROS_LONG2BE(IFFCHNK_POPUP);
2336 pd->pd_PoPoCfg.poc_Length = AROS_LONG2BE(sizeof(struct PsdPoPoCfg) - 8);
2337 pd->pd_PoPoCfg.poc_InhibitPopup = FALSE;
2338 pd->pd_PoPoCfg.poc_NoClassBind = FALSE;
2339 pd->pd_PoPoCfg.poc_OverridePowerInfo = POCP_TRUST_DEVICE;
2341 psdLockWritePBase();
2342 AddTail(&phw->phw_Devices, &pd->pd_Node);
2343 psdUnlockPBase();
2344 return(pd);
2345 } else {
2346 KPRINTF(20, ("psdAllocDevice(): out of memory!\n"));
2348 return(NULL);
2349 AROS_LIBFUNC_EXIT
2351 /* \\\ */
2353 /* /// "psdLockReadDevice()" */
2354 AROS_LH1(void, psdLockReadDevice,
2355 AROS_LHA(struct PsdDevice *, pd, A0),
2356 LIBBASETYPEPTR, ps, 17, psd)
2358 AROS_LIBFUNC_INIT
2359 KPRINTF(2, ("psdLockReadDevice(%p, %p)\n", pd, FindTask(NULL)));
2360 pLockSemShared(ps, &pd->pd_Lock);
2361 AROS_LIBFUNC_EXIT
2363 /* \\\ */
2365 /* /// "psdLockWriteDevice()" */
2366 AROS_LH1(void, psdLockWriteDevice,
2367 AROS_LHA(struct PsdDevice *, pd, A0),
2368 LIBBASETYPEPTR, ps, 18, psd)
2370 AROS_LIBFUNC_INIT
2371 KPRINTF(2, ("psdLockWriteDevice(%p, %p)\n", pd, FindTask(NULL)));
2372 pLockSemExcl(ps, &pd->pd_Lock);
2373 AROS_LIBFUNC_EXIT
2375 /* \\\ */
2377 /* /// "psdUnlockDevice()" */
2378 AROS_LH1(void, psdUnlockDevice,
2379 AROS_LHA(struct PsdDevice *, pd, A0),
2380 LIBBASETYPEPTR, ps, 19, psd)
2382 AROS_LIBFUNC_INIT
2383 KPRINTF(2, ("psdUnlockDevice(%p, %p)\n", pd, FindTask(NULL)));
2384 pUnlockSem(ps, &pd->pd_Lock);
2385 AROS_LIBFUNC_EXIT
2387 /* \\\ */
2389 /* /// "pAllocDevAddr()" */
2390 UWORD pAllocDevAddr(struct PsdDevice *pd)
2392 struct PsdHardware *phw = pd->pd_Hardware;
2393 UWORD da;
2394 if(pd->pd_DevAddr)
2396 return(pd->pd_DevAddr);
2398 for(da = 1; da < 128; da++)
2400 if(!phw->phw_DevArray[da])
2402 phw->phw_DevArray[da] = pd;
2403 pd->pd_DevAddr = da;
2404 return(da);
2407 return(0);
2409 /* \\\ */
2411 /* /// "psdGetStringDescriptor()" */
2412 AROS_LH2(STRPTR, psdGetStringDescriptor,
2413 AROS_LHA(struct PsdPipe *, pp, A1),
2414 AROS_LHA(UWORD, idx, D0),
2415 LIBBASETYPEPTR, ps, 33, psd)
2417 AROS_LIBFUNC_INIT
2418 struct PsdDevice *pd = pp->pp_Device;
2419 ULONG len;
2420 UBYTE buf[256];
2421 UWORD *tmpptr;
2422 UWORD *tmpbuf;
2423 STRPTR rs;
2424 STRPTR cbuf;
2425 LONG ioerr;
2426 UWORD widechar;
2427 KPRINTF(1, ("psdGetStringDescriptor(%p, %ld)\n", pp, idx));
2429 buf[0] = 0;
2430 if(!pd->pd_LangIDArray)
2432 KPRINTF(10,("Trying to get language array...\n"));
2433 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2434 USR_GET_DESCRIPTOR, UDT_STRING<<8, 0);
2435 ioerr = psdDoPipe(pp, buf, 2);
2436 if(ioerr == UHIOERR_OVERFLOW)
2438 ioerr = 0;
2439 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Language array overflow.");
2441 if(ioerr)
2443 ioerr = psdDoPipe(pp, buf, 256);
2444 if(ioerr == UHIOERR_RUNTPACKET)
2446 ioerr = 0;
2449 if(!ioerr)
2451 len = buf[0];
2452 if((pd->pd_LangIDArray = psdAllocVec(max(len, 4))))
2454 tmpbuf = tmpptr = pd->pd_LangIDArray;
2455 KPRINTF(1, ("Getting LangID Array length %ld\n", len));
2456 // generate minimal sized array
2457 if(len < 4)
2459 len = 4;
2460 *tmpbuf++ = 0;
2461 *tmpbuf = AROS_WORD2LE(0x0409);
2462 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2463 "Language array descriptor too small (len %ld), using dummy.",
2464 len);*/
2465 ioerr = 0;
2466 } else {
2467 ioerr = psdDoPipe(pp, tmpbuf++, len);
2469 if(!ioerr)
2471 len >>= 1;
2472 while(--len)
2474 KPRINTF(1, ("LangID: %04lx\n", AROS_WORD2LE(*tmpbuf)));
2475 *tmpptr++ = AROS_WORD2LE(*tmpbuf);
2476 tmpbuf++;
2478 *tmpptr = 0;
2479 tmpptr = pd->pd_LangIDArray;
2480 pd->pd_CurrLangID = *tmpptr;
2481 while(*tmpptr)
2483 if(*tmpptr == 0x0409)
2485 pd->pd_CurrLangID = *tmpptr;
2486 break;
2488 tmpptr++;
2490 } else {
2491 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2492 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2493 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2494 KPRINTF(15, ("Error reading lang array descriptor (%ld) failed %ld\n", len, ioerr));
2495 *tmpptr = 0;
2497 } else {
2498 KPRINTF(20, ("No langid array memory!\n"));
2500 } else {
2501 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2502 "Reading language array descriptor (len %ld) failed: %s (%ld)",
2503 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2504 KPRINTF(15, ("Error reading lang array descriptor (2) failed %ld\n", ioerr));
2505 /* Create empty array */
2506 if((pd->pd_LangIDArray = psdAllocVec(2)))
2508 *pd->pd_LangIDArray = 0;
2512 buf[0] = 0;
2513 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2514 USR_GET_DESCRIPTOR, (UDT_STRING<<8)|idx, pd->pd_CurrLangID);
2515 ioerr = psdDoPipe(pp, buf, 2);
2516 if(ioerr == UHIOERR_OVERFLOW)
2518 ioerr = 0;
2519 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "String %ld overflow.", idx);
2521 if(ioerr)
2523 ioerr = psdDoPipe(pp, buf, 256);
2525 if(!ioerr)
2527 len = buf[0];
2528 if(len > 2)
2530 tmpptr = (UWORD *) buf;
2531 KPRINTF(1, ("Getting String Descriptor %ld, length %ld\n", idx, len));
2532 ioerr = psdDoPipe(pp, tmpptr++, len);
2533 if(ioerr == UHIOERR_RUNTPACKET)
2535 len = pp->pp_IOReq.iouh_Actual;
2536 if(len > 3)
2538 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2539 "String descriptor %ld truncated to %ld, requested %ld",
2540 idx, len, buf[0]);
2541 ioerr = 0;
2544 else if(ioerr)
2546 ioerr = psdDoPipe(pp, buf, 256);
2548 if(!ioerr)
2550 if((cbuf = rs = psdAllocVec(len>>1)))
2552 len >>= 1;
2553 while(--len)
2555 widechar = *tmpptr++;
2556 widechar = AROS_LE2WORD(widechar);
2557 if(widechar == 0)
2559 break;
2561 if((widechar < 0x20) || (widechar > 255))
2563 *cbuf++ = '?';
2564 } else {
2565 *cbuf++ = widechar;
2568 *cbuf = 0;
2569 KPRINTF(1, ("String \"%s\"\n", rs));
2570 if(*rs)
2572 return(rs);
2573 } else {
2574 psdFreeVec(rs);
2575 return(NULL);
2577 } else {
2578 KPRINTF(20, ("No memory for string!\n"));
2580 } else {
2581 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2582 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2583 idx, len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2584 KPRINTF(15, ("Error reading string descriptor %ld (%ld) failed %ld\n",
2585 idx, len, ioerr));
2587 } else {
2588 KPRINTF(5, ("Empty string\n"));
2589 return(psdCopyStr(""));
2591 } else {
2592 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2593 "Reading string descriptor %ld (len %ld) failed: %s (%ld)",
2594 idx, 2, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2595 KPRINTF(15, ("Error reading string descriptor %ld (2) failed %ld\n", idx, ioerr));
2597 return(NULL);
2598 AROS_LIBFUNC_EXIT
2600 /* \\\ */
2602 /* /// "psdSetDeviceConfig()" */
2603 AROS_LH2(BOOL, psdSetDeviceConfig,
2604 AROS_LHA(struct PsdPipe *, pp, A1),
2605 AROS_LHA(UWORD, cfgnum, D0),
2606 LIBBASETYPEPTR, ps, 34, psd)
2608 AROS_LIBFUNC_INIT
2609 struct PsdConfig *pc;
2610 struct PsdDevice *pd = pp->pp_Device;
2611 //UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2612 LONG ioerr;
2613 BOOL res = FALSE;
2615 KPRINTF(2, ("Setting configuration to %ld...\n", cfgnum));
2616 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2617 USR_SET_CONFIGURATION, cfgnum, 0);
2618 ioerr = psdDoPipe(pp, NULL, 0);
2619 if(!ioerr)
2621 #if 0 // MacOS X does not verify the configuration set. And as we don't check the results anyway, don't obtain current configuration to avoid bad devices breaking down
2622 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2623 USR_GET_CONFIGURATION, 0, 0);
2624 ioerr = psdDoPipe(pp, buf, 1);
2625 if(!ioerr)
2627 pd->pd_CurrCfg = buf[0];
2628 if(cfgnum != buf[0])
2630 pd->pd_CurrCfg = cfgnum;
2631 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2632 "Broken: SetConfig/GetConfig mismatch (%ld != %ld) for %s!",
2633 cfgnum, buf[0], pp->pp_Device->pd_ProductStr);
2635 res = TRUE;
2636 } else {
2637 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2638 "GET_CONFIGURATION failed: %s (%ld)",
2639 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2640 pd->pd_CurrCfg = cfgnum;
2641 KPRINTF(15, ("GET_CONFIGURATION failed %ld!\n", ioerr));
2643 #else
2644 pd->pd_CurrCfg = cfgnum;
2645 res = TRUE;
2646 #endif
2647 } else {
2648 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2649 "SET_CONFIGURATION failed: %s (%ld)",
2650 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2651 KPRINTF(15, ("SET_CONFIGURATION failed %ld!\n", ioerr));
2653 // update direct link
2654 Forbid();
2655 pd->pd_CurrentConfig = NULL;
2656 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
2657 while(pc->pc_Node.ln_Succ)
2659 if(pc->pc_CfgNum == pd->pd_CurrCfg)
2661 pd->pd_CurrentConfig = pc;
2662 break;
2664 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
2666 Permit();
2667 if(!pd->pd_CurrentConfig)
2669 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "No current configuration, huh?");
2670 } else {
2671 UWORD status = 0;
2672 // power saving stuff
2673 if(ps->ps_GlobalCfg->pgc_PowerSaving && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
2675 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2676 USR_SET_FEATURE, UFS_DEVICE_REMOTE_WAKEUP, 0);
2677 ioerr = psdDoPipe(pp, NULL, 0);
2678 if(ioerr)
2680 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2681 "SET_DEVICE_REMOTE_WAKEUP failed: %s (%ld)",
2682 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2683 KPRINTF(15, ("SET_DEVICE_REMOTE_WAKEUP failed %ld!\n", ioerr));
2685 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2686 ioerr = psdDoPipe(pp, &status, 2);
2687 if(!ioerr)
2689 if(status & U_GSF_REMOTE_WAKEUP)
2691 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2692 "Enabled remote wakeup feature for '%s'.",
2693 pd->pd_ProductStr);
2694 } else {
2695 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_REMOTE_WAKEUP;
2696 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2697 "Remote wakeup feature for '%s' could not be enabled.",
2698 pd->pd_ProductStr);
2700 } else {
2701 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2702 "GET_STATUS failed: %s (%ld)",
2703 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2704 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2706 } else {
2707 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_STATUS, 0, 0);
2708 ioerr = psdDoPipe(pp, &status, 2);
2710 if(!ioerr)
2712 if((status & U_GSF_SELF_POWERED) && (!(pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED)))
2714 pd->pd_CurrentConfig->pc_Attr |= USCAF_SELF_POWERED;
2715 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2716 "Device '%s' says it is currently self-powered. Fixing config.",
2717 pd->pd_ProductStr);
2719 else if((!(status & U_GSF_SELF_POWERED)) && (pd->pd_CurrentConfig->pc_Attr & USCAF_SELF_POWERED))
2721 pd->pd_CurrentConfig->pc_Attr &= ~USCAF_SELF_POWERED;
2722 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2723 "Device '%s' says it is currently bus-powered. Fixing config.",
2724 pd->pd_ProductStr);
2726 } else {
2727 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2728 "GET_STATUS failed: %s (%ld)",
2729 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
2730 KPRINTF(15, ("GET_STATUS failed %ld!\n", ioerr));
2734 return(res);
2735 AROS_LIBFUNC_EXIT
2737 /* \\\ */
2739 /* /// "psdSetAltInterface()" */
2740 AROS_LH2(BOOL, psdSetAltInterface,
2741 AROS_LHA(struct PsdPipe *, pp, A1),
2742 AROS_LHA(struct PsdInterface *, pif, A0),
2743 LIBBASETYPEPTR, ps, 43, psd)
2745 AROS_LIBFUNC_INIT
2746 struct PsdConfig *pc = pif->pif_Config;
2747 struct PsdInterface *curif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
2748 struct PsdInterface *tmpif;
2749 struct PsdDevice *pd = pc->pc_Device;
2750 UBYTE buf[8]; // VIA babble bug safety buffer (8 instead of 2)
2751 LONG ioerr;
2752 UWORD ifnum = pif->pif_IfNum;
2753 UWORD altnum = pif->pif_Alternate;
2755 KPRINTF(2, ("Setting interface %ld to alt %ld...\n", ifnum, altnum));
2756 psdLockWriteDevice(pd);
2758 /* Find root config structure */
2759 while(curif->pif_Node.ln_Succ)
2761 if(curif->pif_IfNum == ifnum)
2763 break;
2765 curif = (struct PsdInterface *) curif->pif_Node.ln_Succ;
2767 if(!curif->pif_Node.ln_Succ)
2769 KPRINTF(20, ("Where did you get that fucking interface from?!?"));
2770 psdUnlockDevice(pd);
2771 return(FALSE);
2773 if(curif == pif) /* Is already the current alternate setting */
2775 psdUnlockDevice(pd);
2776 return(TRUE);
2778 KPRINTF(1, ("really setting interface...\n"));
2779 if(pp)
2781 psdPipeSetup(pp, URTF_STANDARD|URTF_INTERFACE,
2782 USR_SET_INTERFACE, altnum, ifnum);
2783 ioerr = psdDoPipe(pp, NULL, 0);
2784 } else {
2785 ioerr = 0;
2787 if((!ioerr) || (ioerr == UHIOERR_STALL))
2789 if(pp)
2791 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_INTERFACE,
2792 USR_GET_INTERFACE, 0, ifnum);
2793 ioerr = psdDoPipe(pp, buf, 1);
2794 } else {
2795 buf[0] = altnum;
2797 if(!ioerr)
2799 if(altnum == buf[0])
2801 KPRINTF(1, ("resorting list..."));
2802 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
2803 "Changed to alt %ld",
2804 altnum);*/
2805 Forbid();
2806 /* Remove pif from alt list */
2807 Remove(&pif->pif_Node);
2808 pif->pif_ParentIf = NULL;
2809 /* Now move bindings */
2810 pif->pif_ClsBinding = curif->pif_ClsBinding;
2811 pif->pif_IfBinding = curif->pif_IfBinding;
2812 curif->pif_IfBinding = NULL;
2813 curif->pif_ClsBinding = NULL;
2814 /* Insert it after root interface */
2815 Insert(&pc->pc_Interfaces, (struct Node *) &pif->pif_Node, (struct Node *) &curif->pif_Node);
2816 /* Unlink root interface */
2817 Remove(&curif->pif_Node);
2818 /* Now move all remaining alt interfaces to the new root interface */
2819 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2820 while(tmpif->pif_Node.ln_Succ)
2822 Remove(&tmpif->pif_Node);
2823 AddTail(&pif->pif_AlterIfs, &tmpif->pif_Node);
2824 tmpif->pif_ParentIf = pif;
2825 tmpif = (struct PsdInterface *) curif->pif_AlterIfs.lh_Head;
2827 /* Add old root to the end of the alt list */
2828 AddTail(&pif->pif_AlterIfs, &curif->pif_Node);
2829 curif->pif_ParentIf = pif;
2830 Permit();
2831 psdUnlockDevice(pd);
2832 return(TRUE);
2833 } else {
2834 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2835 "Attempt to change interface %ld to alt %ld remained at alt %ld.",
2836 ifnum, altnum, buf[0]);
2838 } else {
2839 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2840 "GET_INTERFACE(%ld) failed: %s (%ld)",
2841 ifnum, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2842 KPRINTF(15, ("GET_INTERFACE failed %ld!\n", ioerr));
2844 } else {
2845 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2846 "SET_INTERFACE(%ld)=%ld failed: %s (%ld)",
2847 ifnum, altnum,
2848 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2849 KPRINTF(15, ("SET_INTERFACE failed %ld!\n", ioerr));
2851 psdUnlockDevice(pd);
2852 return(FALSE);
2853 AROS_LIBFUNC_EXIT
2855 /* \\\ */
2857 /* /// "psdEnumerateDevice()" */
2858 AROS_LH1(struct PsdDevice *, psdEnumerateDevice,
2859 AROS_LHA(struct PsdPipe *, pp, A1),
2860 LIBBASETYPEPTR, ps, 20, psd)
2862 AROS_LIBFUNC_INIT
2863 struct PsdDevice *pd = pp->pp_Device;
2864 struct PsdDevice *itpd = pp->pp_Device;
2865 struct PsdConfig *pc;
2866 struct PsdInterface *pif;
2867 struct UsbStdDevDesc usdd;
2868 UWORD oldflags;
2869 ULONG oldnaktimeout;
2870 LONG ioerr;
2871 STRPTR classname;
2872 STRPTR vendorname;
2873 ULONG devclass;
2874 BOOL hasprodname;
2875 BOOL haspopupinhibit;
2876 UWORD cfgnum;
2877 struct PsdIFFContext *pic;
2878 ULONG *chnk;
2879 UBYTE dummybuf[8];
2881 KPRINTF(2, ("psdEnumerateDevice(%p)\n", pp));
2883 psdLockWriteDevice(pd);
2884 if(pAllocDevAddr(pd))
2886 oldflags = pp->pp_IOReq.iouh_Flags;
2887 oldnaktimeout = pp->pp_IOReq.iouh_NakTimeout;
2888 pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
2889 pp->pp_IOReq.iouh_NakTimeout = 1000;
2890 pp->pp_IOReq.iouh_DevAddr = 0;
2892 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2893 USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2894 ioerr = psdDoPipe(pp, dummybuf, 8);
2895 if(ioerr && (ioerr != UHIOERR_RUNTPACKET))
2897 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
2898 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
2899 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2900 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
2902 KPRINTF(1, ("Setting DevAddr %ld...\n", pd->pd_DevAddr));
2903 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE,
2904 USR_SET_ADDRESS, pd->pd_DevAddr, 0);
2905 ioerr = psdDoPipe(pp, NULL, 0);
2906 /* This is tricky: Maybe the device has accepted the command,
2907 but failed to send an ACK. Now, every resend trial will
2908 go to the wrong address! */
2909 if((ioerr == UHIOERR_TIMEOUT) || (ioerr == UHIOERR_STALL))
2911 KPRINTF(1, ("First attempt failed, retrying new address\n"));
2912 /*pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;*/
2913 psdDelayMS(250);
2914 ioerr = psdDoPipe(pp, NULL, 0);
2915 /*pp->pp_IOReq.iouh_DevAddr = 0;*/
2917 if(!ioerr)
2919 pd->pd_Flags |= PDFF_HASDEVADDR|PDFF_CONNECTED;
2920 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
2922 psdDelayMS(50); /* Allowed time to settle */
2924 KPRINTF(1, ("Getting MaxPktSize0...\n"));
2925 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
2926 USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2927 ioerr = psdDoPipe(pp, &usdd, 8);
2928 if(!ioerr)
2930 switch(usdd.bMaxPacketSize0)
2932 case 8:
2933 case 16:
2934 case 32:
2935 case 64:
2936 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = usdd.bMaxPacketSize0;
2937 break;
2938 default:
2939 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
2940 "Illegal MaxPktSize0=%ld for endpoint 0",
2941 (ULONG) usdd.bMaxPacketSize0);
2942 KPRINTF(2, ("Illegal MaxPktSize0=%ld!\n", usdd.bMaxPacketSize0));
2943 //pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = 8;
2944 ioerr = UHIOERR_CRCERROR;
2945 break;
2948 if(!ioerr)
2950 KPRINTF(1, (" MaxPktSize0 = %ld\n", pd->pd_MaxPktSize0));
2951 KPRINTF(1, ("Getting full descriptor...\n"));
2952 ioerr = psdDoPipe(pp, &usdd, sizeof(struct UsbStdDevDesc));
2953 if(!ioerr)
2955 pAllocDescriptor(pd, (UBYTE *) &usdd);
2956 pd->pd_Flags |= PDFF_HASDEVDESC;
2957 pd->pd_USBVers = AROS_WORD2LE(usdd.bcdUSB);
2958 pd->pd_DevClass = usdd.bDeviceClass;
2959 pd->pd_DevSubClass = usdd.bDeviceSubClass;
2960 pd->pd_DevProto = usdd.bDeviceProtocol;
2961 pd->pd_VendorID = AROS_WORD2LE(usdd.idVendor);
2962 pd->pd_ProductID = AROS_WORD2LE(usdd.idProduct);
2963 pd->pd_DevVers = AROS_WORD2LE(usdd.bcdDevice);
2964 vendorname = psdNumToStr(NTS_VENDORID, (LONG) pd->pd_VendorID, NULL);
2966 // patch to early determine highspeed roothubs
2967 if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x200) && (pd->pd_USBVers < 0x300))
2969 pd->pd_Flags |= PDFF_HIGHSPEED;
2971 #ifdef AROS_USB30_CODE
2972 if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x300))
2974 pd->pd_Flags |= PDFF_SUPERSPEED;
2976 #endif
2978 if(usdd.iManufacturer)
2980 pd->pd_MnfctrStr = psdGetStringDescriptor(pp, usdd.iManufacturer);
2982 if(usdd.iProduct)
2984 pd->pd_ProductStr = psdGetStringDescriptor(pp, usdd.iProduct);
2986 if(usdd.iSerialNumber)
2988 pd->pd_SerNumStr = psdGetStringDescriptor(pp, usdd.iSerialNumber);
2990 if(!pd->pd_MnfctrStr)
2992 pd->pd_MnfctrStr = psdCopyStr(vendorname ? vendorname : (STRPTR) "n/a");
2994 if(!pd->pd_ProductStr)
2996 hasprodname = FALSE;
2997 classname = psdNumToStr(NTS_CLASSCODE, (LONG) pd->pd_DevClass, NULL);
2998 if(classname)
3000 pd->pd_ProductStr = psdCopyStrFmt("%s: Vdr=%04lx/PID=%04lx",
3001 classname, pd->pd_VendorID, pd->pd_ProductID);
3002 } else {
3003 pd->pd_ProductStr = psdCopyStrFmt("Cls=%ld/Vdr=%04lx/PID=%04lx",
3004 pd->pd_DevClass, pd->pd_VendorID, pd->pd_ProductID);
3006 } else {
3007 hasprodname = TRUE;
3009 if(!pd->pd_SerNumStr)
3011 pd->pd_SerNumStr = psdCopyStr("n/a");
3014 KPRINTF(2, ("Product : %s\n"
3015 "Manufacturer: %s\n"
3016 "SerialNumber: %s\n",
3017 pd->pd_ProductStr, pd->pd_MnfctrStr, pd->pd_SerNumStr));
3018 KPRINTF(2, ("USBVersion: %04lx\n"
3019 "Class : %ld\n"
3020 "SubClass : %ld\n"
3021 "DevProto : %ld\n"
3022 "VendorID : %ld\n"
3023 "ProductID : %ld\n"
3024 "DevVers : %04lx\n",
3025 pd->pd_USBVers, pd->pd_DevClass, pd->pd_DevSubClass, pd->pd_DevProto,
3026 pd->pd_VendorID, pd->pd_ProductID, pd->pd_DevVers));
3028 /* check for clones */
3029 itpd = NULL;
3030 while((itpd = psdGetNextDevice(itpd)))
3032 if(itpd != pd)
3034 if((itpd->pd_ProductID == pd->pd_ProductID) &&
3035 (itpd->pd_VendorID == pd->pd_VendorID) &&
3036 (!strcmp(itpd->pd_SerNumStr, pd->pd_SerNumStr)) &&
3037 (itpd->pd_CloneCount == pd->pd_CloneCount))
3039 pd->pd_CloneCount++;
3040 itpd = NULL;
3045 pd->pd_IDString = psdCopyStrFmt("%s-%04lx-%04lx-%s-%02lx", pd->pd_ProductStr, pd->pd_VendorID, pd->pd_ProductID, pd->pd_SerNumStr, pd->pd_CloneCount);
3047 pStripString(ps, pd->pd_MnfctrStr);
3048 pStripString(ps, pd->pd_ProductStr);
3049 pStripString(ps, pd->pd_SerNumStr);
3051 /* get custom name of device */
3052 pLockSemExcl(ps, &ps->ps_ConfigLock); // Exclusive lock to avoid deadlock situation when promoting read to write
3053 pd->pd_OldProductStr = pd->pd_ProductStr;
3054 pd->pd_ProductStr = NULL;
3055 haspopupinhibit = FALSE;
3056 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
3057 if(pic)
3059 pd->pd_IsNewToMe = FALSE;
3060 if((pd->pd_ProductStr = pGetStringChunk(ps, pic, IFFCHNK_NAME)))
3062 hasprodname = TRUE;
3064 if((chnk = pFindCfgChunk(ps, pic, IFFCHNK_POPUP)))
3066 struct PsdPoPoCfg *poc = (struct PsdPoPoCfg *) chnk;
3067 CopyMem(((UBYTE *) poc) + 8, ((UBYTE *) &pd->pd_PoPoCfg) + 8, min(AROS_LONG2BE(poc->poc_Length), AROS_LONG2BE(pd->pd_PoPoCfg.poc_Length)));
3068 haspopupinhibit = TRUE;
3070 } else {
3071 pd->pd_IsNewToMe = TRUE;
3072 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
3074 if(!pd->pd_ProductStr)
3076 pd->pd_ProductStr = psdCopyStr(pd->pd_OldProductStr);
3078 if(!haspopupinhibit)
3080 if(pd->pd_DevClass == HUB_CLASSCODE) // hubs default to true
3082 pd->pd_PoPoCfg.poc_InhibitPopup = TRUE;
3085 pUnlockSem(ps, &ps->ps_ConfigLock);
3087 pd->pd_NumCfgs = usdd.bNumConfigurations;
3088 KPRINTF(10, ("Device has %ld different configurations\n", pd->pd_NumCfgs));
3090 if(pGetDevConfig(pp))
3092 cfgnum = 1;
3093 if(pd->pd_Configs.lh_Head->ln_Succ)
3095 cfgnum = ((struct PsdConfig *) pd->pd_Configs.lh_Head)->pc_CfgNum;
3097 psdSetDeviceConfig(pp, cfgnum); /* *** FIXME *** Workaround for USB2.0 devices */
3099 if(!hasprodname)
3101 devclass = pd->pd_DevClass;
3102 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
3103 while(pc->pc_Node.ln_Succ)
3105 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3106 while(pif->pif_Node.ln_Succ)
3108 if(pif->pif_IfClass)
3110 if(!devclass)
3112 devclass = pif->pif_IfClass;
3113 } else {
3114 if(devclass != pif->pif_IfClass)
3116 devclass = 0;
3117 break;
3121 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3123 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
3125 if(devclass)
3127 classname = psdNumToStr(NTS_CLASSCODE, (LONG) devclass, NULL);
3128 if(classname)
3130 psdFreeVec(pd->pd_ProductStr);
3131 if(vendorname)
3133 pd->pd_ProductStr = psdCopyStrFmt("%s (%s/%04lx)",
3134 classname, vendorname, pd->pd_ProductID);
3135 } else {
3136 pd->pd_ProductStr = psdCopyStrFmt("%s (%04lx/%04lx)",
3137 classname, pd->pd_VendorID, pd->pd_ProductID);
3142 pFixBrokenConfig(pp);
3143 pp->pp_IOReq.iouh_Flags = oldflags;
3144 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3145 psdUnlockDevice(pd);
3146 psdCalculatePower(pd->pd_Hardware);
3147 return(pd);
3148 } /*else {
3149 KPRINTF(15, ("SetDeviceConfig(1) failed\n"));
3151 } else {
3152 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3153 "Could not acquire device configuration for %s",
3154 pd->pd_ProductStr ? pd->pd_ProductStr : (STRPTR) "new device");
3155 KPRINTF(15, ("GetDevConfig() failed\n"));
3157 /* Although the device failed to configure fully, maybe
3158 some firmware will able to use this device anyway? */
3159 pp->pp_IOReq.iouh_Flags = oldflags;
3160 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3162 psdUnlockDevice(pd);
3163 return(pd);
3164 } else {
3165 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3166 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
3167 18, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3168 KPRINTF(15, ("GET_DESCRIPTOR (18) failed %ld!\n", ioerr));
3170 } else {
3171 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3172 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
3173 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3174 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
3176 } else {
3177 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
3178 "SET_ADDRESS failed: %s (%ld)",
3179 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3180 KPRINTF(15, ("SET_ADDRESS failed %ld!\n", ioerr));
3183 pp->pp_IOReq.iouh_Flags = oldflags;
3184 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3185 } else {
3186 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "This cannot happen! More than 127 devices on the bus???");
3187 KPRINTF(20, ("out of addresses???\n"));
3189 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Device enumeration failed, sorry.");
3190 psdUnlockDevice(pd);
3191 return(NULL);
3192 AROS_LIBFUNC_EXIT
3194 /* \\\ */
3196 /* /// "psdGetNextDevice()" */
3197 AROS_LH1(struct PsdDevice *, psdGetNextDevice,
3198 AROS_LHA(struct PsdDevice *, pd, A0),
3199 LIBBASETYPEPTR, ps, 21, psd)
3201 AROS_LIBFUNC_INIT
3202 struct PsdHardware *phw;
3204 KPRINTF(1, ("psdGetNextDevice(%p)\n", pd));
3205 if(pd)
3207 /* Is there another device node in the current hardware? */
3208 if(pd->pd_Node.ln_Succ->ln_Succ)
3210 return((struct PsdDevice *) pd->pd_Node.ln_Succ);
3212 /* No, then check if there's another hardware to scan */
3213 phw = (struct PsdHardware *) pd->pd_Hardware->phw_Node.ln_Succ;
3214 } else {
3215 /* No context, start with first hardware */
3216 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3218 while(phw->phw_Node.ln_Succ)
3220 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3221 /* Is this an valid entry, or is the list empty? */
3222 if(pd->pd_Node.ln_Succ)
3224 return(pd);
3226 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3228 /* End of list reached */
3229 return(NULL);
3230 AROS_LIBFUNC_EXIT
3232 /* \\\ */
3234 /* /// "psdSuspendBindings()" */
3235 AROS_LH1(BOOL, psdSuspendBindings,
3236 AROS_LHA(struct PsdDevice *, pd, A0),
3237 LIBBASETYPEPTR, ps, 100, psd)
3239 AROS_LIBFUNC_INIT
3240 struct PsdUsbClass *puc;
3241 struct PsdConfig *pc;
3242 struct PsdInterface *pif;
3243 BOOL res = FALSE;
3244 IPTR suspendable;
3245 BOOL force = FALSE;
3247 KPRINTF(5, ("psdSuspendBindings(%p)\n", pd));
3248 if(pd)
3250 if(ps->ps_GlobalCfg->pgc_ForceSuspend && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
3252 force = TRUE;
3254 // ask existing bindings to go to suspend first -- if they don't support it, break off
3255 if(pd->pd_DevBinding)
3257 if(pd->pd_Flags & PDFF_APPBINDING)
3259 if(!force)
3261 // can't suspend application binding devices
3262 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3263 "Cannot suspend with application binding on '%s'.",
3264 pd->pd_ProductStr);
3265 return FALSE;
3267 psdReleaseDevBinding(pd);
3269 if((puc = pd->pd_ClsBinding))
3271 suspendable = 0;
3272 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3273 if(suspendable)
3275 res = usbDoMethod(UCM_AttemptSuspendDevice, pd->pd_DevBinding);
3276 if(!res)
3278 // didn't want to suspend
3279 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3280 "Class '%s' failed to suspend device '%s'.",
3281 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3282 return FALSE;
3284 } else {
3285 if(pd->pd_IOBusyCount)
3287 if(!force)
3289 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3290 "Class '%s' does not support suspending.",
3291 puc->puc_Node.ln_Name);
3292 return FALSE;
3293 } else {
3294 psdReleaseDevBinding(pd);
3296 } else {
3297 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3298 "Class '%s' does not support suspending, but has no active IO. Suspending anyway.",
3299 puc->puc_Node.ln_Name);
3304 pc = pd->pd_CurrentConfig;
3305 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3306 while(pif->pif_Node.ln_Succ)
3308 if(pif->pif_IfBinding)
3310 if((puc = pif->pif_ClsBinding))
3312 suspendable = 0;
3313 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3314 if(suspendable)
3316 res = usbDoMethod(UCM_AttemptSuspendDevice, pif->pif_IfBinding);
3317 if(!res)
3319 // didn't want to suspend
3320 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3321 "%s failed to suspend device '%s'.",
3322 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3323 return FALSE;
3325 } else {
3326 if(pd->pd_IOBusyCount)
3328 if(!force)
3331 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3332 "%s does not support suspending.",
3333 puc->puc_Node.ln_Name);
3334 return FALSE;
3335 } else {
3336 psdReleaseIfBinding(pif);
3338 } else {
3339 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3340 "%s does not support suspending, but has no active IO. Suspending anyway.",
3341 puc->puc_Node.ln_Name);
3346 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3348 return TRUE;
3350 return FALSE;
3351 AROS_LIBFUNC_EXIT
3353 /* \\\ */
3355 /* /// "psdSuspendDevice()" */
3356 AROS_LH1(BOOL, psdSuspendDevice,
3357 AROS_LHA(struct PsdDevice *, pd, A0),
3358 LIBBASETYPEPTR, ps, 98, psd)
3360 AROS_LIBFUNC_INIT
3361 struct PsdUsbClass *puc;
3362 struct PsdDevice *hubpd;
3363 APTR binding;
3364 BOOL res = FALSE;
3366 KPRINTF(5, ("psdSuspendDevice(%p)\n", pd));
3367 if(pd)
3369 if(pd->pd_Flags & PDFF_SUSPENDED)
3371 return TRUE;
3373 hubpd = pd->pd_Hub;
3374 if(!hubpd) // suspend root hub
3376 // suspend whole USB, using the HCI UHCMD_USBSUSPEND command
3377 // FIXME currently unsupported!
3378 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Suspending of root hub currently not supported.");
3379 return FALSE;
3382 psdLockWriteDevice(pd);
3383 res = psdSuspendBindings(pd);
3384 psdUnlockDevice(pd);
3385 if(res)
3387 psdLockReadDevice(pd);
3388 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3390 res = usbDoMethod(UCM_HubSuspendDevice, binding, pd);
3392 psdUnlockDevice(pd);
3395 if(!res)
3397 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3398 "Suspending of device '%s' failed.",
3399 pd->pd_ProductStr);
3401 return(res);
3402 AROS_LIBFUNC_EXIT
3404 /* \\\ */
3406 /* /// "psdResumeBindings()" */
3407 AROS_LH1(BOOL, psdResumeBindings,
3408 AROS_LHA(struct PsdDevice *, pd, A0),
3409 LIBBASETYPEPTR, ps, 101, psd)
3411 AROS_LIBFUNC_INIT
3412 struct PsdUsbClass *puc;
3413 struct PsdConfig *pc;
3414 struct PsdInterface *pif;
3415 BOOL res = FALSE;
3416 BOOL rescan = FALSE;
3418 KPRINTF(5, ("psdResumeBindings(%p)\n", pd));
3419 if(pd)
3421 // ask existing bindings to resume -- if they don't support it, rebind
3422 if(pd->pd_DevBinding)
3424 if(!(pd->pd_Flags & PDFF_APPBINDING))
3426 if((puc = pd->pd_ClsBinding))
3428 res = usbDoMethod(UCM_AttemptResumeDevice, pd->pd_DevBinding);
3429 if(!res)
3431 // if the device couldn't resume, better get rid of the binding
3432 psdReleaseDevBinding(pd);
3433 rescan = TRUE;
3438 pc = pd->pd_CurrentConfig;
3439 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3440 while(pif->pif_Node.ln_Succ)
3442 if(pif->pif_IfBinding)
3444 if((puc = pif->pif_ClsBinding))
3446 res = usbDoMethod(UCM_AttemptResumeDevice, pif->pif_IfBinding);
3447 if(!res)
3449 // didn't want to suspend
3450 psdReleaseIfBinding(pif);
3451 rescan = TRUE;
3454 break;
3456 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3458 if(rescan)
3460 psdClassScan();
3463 return(TRUE);
3464 AROS_LIBFUNC_EXIT
3466 /* \\\ */
3468 /* /// "psdResumeDevice()" */
3469 AROS_LH1(BOOL, psdResumeDevice,
3470 AROS_LHA(struct PsdDevice *, pd, A0),
3471 LIBBASETYPEPTR, ps, 99, psd)
3473 AROS_LIBFUNC_INIT
3474 struct PsdUsbClass *puc;
3475 struct PsdDevice *hubpd;
3476 APTR binding;
3477 BOOL res = FALSE;
3479 KPRINTF(5, ("psdResumeDevice(%p)\n", pd));
3480 if(pd)
3482 if(!(pd->pd_Flags & PDFF_SUSPENDED))
3484 return(TRUE);
3486 hubpd = pd->pd_Hub;
3487 if(!hubpd) // resume root hub
3489 // resume whole USB, using the HCI UHCMD_USBRESUME command
3490 // FIXME currently unsupported!
3491 return(FALSE);
3493 psdLockWriteDevice(pd);
3494 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3496 res = usbDoMethod(UCM_HubResumeDevice, binding, pd);
3498 psdUnlockDevice(pd);
3500 if(res)
3502 psdResumeBindings(pd);
3506 return(res);
3507 AROS_LIBFUNC_EXIT
3509 /* \\\ */
3511 /* /// "psdFindDeviceA()" */
3512 AROS_LH2(struct PsdDevice *, psdFindDeviceA,
3513 AROS_LHA(struct PsdDevice *, pd, A0),
3514 AROS_LHA(struct TagItem *, tags, A1),
3515 LIBBASETYPEPTR, ps, 44, psd)
3517 AROS_LIBFUNC_INIT
3518 struct TagItem *ti;
3519 BOOL takeit;
3520 KPRINTF(2, ("psdFindDeviceA(%p, %p)\n", pd, tags));
3521 while((pd = psdGetNextDevice(pd)))
3523 takeit = TRUE;
3524 if((ti = FindTagItem(DA_ProductID, tags)))
3526 if(ti->ti_Data != pd->pd_ProductID)
3528 takeit = FALSE;
3531 if((ti = FindTagItem(DA_VendorID, tags)))
3533 if(ti->ti_Data != pd->pd_VendorID)
3535 takeit = FALSE;
3538 if((ti = FindTagItem(DA_Class, tags)))
3540 if(ti->ti_Data != pd->pd_DevClass)
3542 takeit = FALSE;
3545 if((ti = FindTagItem(DA_SubClass, tags)))
3547 if(ti->ti_Data != pd->pd_DevSubClass)
3549 takeit = FALSE;
3552 if((ti = FindTagItem(DA_Protocol, tags)))
3554 if(ti->ti_Data != pd->pd_DevProto)
3556 takeit = FALSE;
3559 if((ti = FindTagItem(DA_Version, tags)))
3561 if(ti->ti_Data != pd->pd_DevVers)
3563 takeit = FALSE;
3566 if((ti = FindTagItem(DA_SerialNumber, tags)))
3568 if(strcmp((STRPTR) ti->ti_Data, pd->pd_SerNumStr))
3570 takeit = FALSE;
3573 if((ti = FindTagItem(DA_ProductName, tags)))
3575 if(strcmp((STRPTR) ti->ti_Data, pd->pd_ProductStr))
3577 takeit = FALSE;
3580 if((ti = FindTagItem(DA_Manufacturer, tags)))
3582 if(strcmp((STRPTR) ti->ti_Data, pd->pd_MnfctrStr))
3584 takeit = FALSE;
3587 if((ti = FindTagItem(DA_IDString, tags)))
3589 if(strcmp((STRPTR) ti->ti_Data, pd->pd_IDString))
3591 takeit = FALSE;
3594 if((ti = FindTagItem(DA_Binding, tags)))
3596 if(ti->ti_Data != (IPTR) pd->pd_DevBinding)
3598 takeit = FALSE;
3601 if((ti = FindTagItem(DA_HubDevice, tags)))
3603 if(ti->ti_Data != (IPTR) pd->pd_Hub)
3605 takeit = FALSE;
3609 if(takeit)
3611 return(pd);
3614 return(NULL);
3615 AROS_LIBFUNC_EXIT
3617 /* \\\ */
3619 /* *** Hardware *** */
3621 /* /// "pFindHardware()" */
3622 struct PsdHardware * pFindHardware(LIBBASETYPEPTR ps, STRPTR name, ULONG unit)
3624 struct PsdHardware *phw;
3625 Forbid();
3626 while(*name)
3628 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3629 while(phw->phw_Node.ln_Succ)
3631 if((phw->phw_Unit == unit) && (!strcmp(phw->phw_DevName, name)))
3633 Permit();
3634 return(phw);
3636 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3640 if((*name == '/') || (*name == ':'))
3642 ++name;
3643 break;
3645 } while(*(++name));
3647 Permit();
3648 return(NULL);
3650 /* \\\ */
3652 /* /// "psdEnumerateHardware()" */
3653 AROS_LH1(struct PsdDevice *, psdEnumerateHardware,
3654 AROS_LHA(struct PsdHardware *, phw, A0),
3655 LIBBASETYPEPTR, ps, 14, psd)
3657 AROS_LIBFUNC_INIT
3658 struct PsdDevice *pd = NULL;
3659 struct PsdPipe *pp;
3660 struct MsgPort *mp;
3661 KPRINTF(2, ("psdEnumerateHardware(%p)\n", phw));
3663 if((mp = CreateMsgPort()))
3665 Forbid();
3666 if((pd = psdAllocDevice(phw)))
3668 Permit();
3669 if((pp = psdAllocPipe(pd, mp, NULL)))
3671 //pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
3672 //pp->pp_IOReq.iouh_NakTimeout = 1000;
3673 pd->pd_Flags |= PDFF_CONNECTED;
3674 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_USBRESET;
3675 psdDoPipe(pp, NULL, 0);
3676 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3677 psdDelayMS(100); // wait for root hub to settle
3678 if(psdEnumerateDevice(pp))
3680 KPRINTF(1, ("Enumeration finished!\n"));
3681 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Root hub has been enumerated.");
3682 psdFreePipe(pp);
3683 DeleteMsgPort(mp);
3684 phw->phw_RootDevice = pd;
3685 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
3686 return(pd);
3688 psdFreePipe(pp);
3690 pFreeBindings(ps, pd);
3691 pFreeDevice(ps, pd);
3692 } else {
3693 Permit();
3695 DeleteMsgPort(mp);
3697 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Root hub enumeration failed. Blame your hardware driver programmer.");
3698 return(NULL);
3699 AROS_LIBFUNC_EXIT
3701 /* \\\ */
3703 /* /// "psdRemHardware()" */
3704 AROS_LH1(void, psdRemHardware,
3705 AROS_LHA(struct PsdHardware *, phw, A0),
3706 LIBBASETYPEPTR, ps, 13, psd)
3708 AROS_LIBFUNC_INIT
3709 struct PsdDevice *pd;
3710 ULONG cnt;
3712 KPRINTF(5, ("FreeHardware(%p)\n", phw));
3714 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3715 while(pd->pd_Node.ln_Succ)
3717 pFreeBindings(ps, pd);
3718 pFreeDevice(ps, pd);
3719 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3720 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3722 cnt = 0;
3723 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3724 while(pd->pd_Node.ln_Succ)
3726 if(pd->pd_UseCnt)
3728 KPRINTF(20, ("Can't remove device, usecnt %ld\n", pd->pd_UseCnt));
3729 if(++cnt == 5)
3731 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3732 "Can't remove device '%s', there are still %ld pipes in use...",
3733 pd->pd_ProductStr, pd->pd_UseCnt);
3735 if(++cnt == 30)
3737 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3738 "Okay, going down with device '%s' anyway, maybe the driver crashed?",
3739 pd->pd_ProductStr);
3740 pd->pd_UseCnt = 0;
3741 cnt--;
3742 } else {
3743 psdDelayMS(1000);
3745 } else {
3746 pFreeDevice(ps, pd);
3747 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3749 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3752 Forbid();
3753 /* Note that the subtask unlinks the hardware! */
3754 phw->phw_ReadySignal = SIGB_SINGLE;
3755 phw->phw_ReadySigTask = FindTask(NULL);
3756 if(phw->phw_Task)
3758 Signal(phw->phw_Task, SIGBREAKF_CTRL_C);
3760 Permit();
3761 while(phw->phw_Task)
3763 Wait(1L<<phw->phw_ReadySignal);
3765 //FreeSignal(phw->phw_ReadySignal);
3766 KPRINTF(1, ("FreeHardware(%p) freevec name\n", phw));
3767 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3768 "Removed hardware %s/%ld. Bye bye!",
3769 phw->phw_DevName, phw->phw_Unit);
3770 psdFreeVec(phw->phw_DevName);
3771 psdFreeVec(phw->phw_ProductName);
3772 psdFreeVec(phw->phw_Manufacturer);
3773 psdFreeVec(phw->phw_Description);
3774 psdFreeVec(phw->phw_Copyright);
3775 psdFreeVec(phw);
3776 psdSendEvent(EHMB_REMHARDWARE, phw, NULL);
3777 KPRINTF(1, ("FreeHardware(%p) done\n", phw));
3778 AROS_LIBFUNC_EXIT
3780 /* \\\ */
3782 /* /// "psdAddHardware()" */
3783 AROS_LH2(struct PsdHardware *,psdAddHardware,
3784 AROS_LHA(STRPTR, name, A0),
3785 AROS_LHA(ULONG, unit, D0),
3786 LIBBASETYPEPTR, ps, 12, psd)
3788 AROS_LIBFUNC_INIT
3789 struct PsdHardware *phw;
3790 char buf[64];
3791 struct Task *tmptask;
3792 KPRINTF(5, ("psdAddHardware(%s, %ld)\n", name, unit));
3794 if((phw = psdAllocVec(sizeof(struct PsdHardware))))
3796 NewList(&phw->phw_Devices);
3797 NewList(&phw->phw_DeadDevices);
3798 phw->phw_Unit = unit;
3799 phw->phw_Base = ps;
3800 if((phw->phw_Node.ln_Name = phw->phw_DevName = psdCopyStr(name)))
3802 psdSafeRawDoFmt(buf, 64, "usbhw<%s/%ld>", name, unit);
3803 phw->phw_ReadySignal = SIGB_SINGLE;
3804 phw->phw_ReadySigTask = FindTask(NULL);
3805 SetSignal(0, SIGF_SINGLE); // clear single bit
3806 if((tmptask = psdSpawnSubTask(buf, pDeviceTask, phw)))
3808 psdBorrowLocksWait(tmptask, 1UL<<phw->phw_ReadySignal);
3809 if(phw->phw_Task)
3811 phw->phw_ReadySigTask = NULL;
3812 //FreeSignal(phw->phw_ReadySignal);
3813 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3814 "New hardware %s/%ld added (%s).",
3815 phw->phw_DevName,
3816 phw->phw_Unit,
3817 phw->phw_ProductName);
3818 psdSendEvent(EHMB_ADDHARDWARE, phw, NULL);
3819 return(phw);
3822 phw->phw_ReadySigTask = NULL;
3823 //FreeSignal(phw->phw_ReadySignal);
3824 psdFreeVec(phw->phw_DevName);
3826 psdFreeVec(phw);
3828 return(NULL);
3829 AROS_LIBFUNC_EXIT
3831 /* \\\ */
3833 /* /// "psdCalculatePower()" */
3834 AROS_LH1(void, psdCalculatePower,
3835 AROS_LHA(struct PsdHardware *, phw, A0),
3836 LIBBASETYPEPTR, ps, 78, psd)
3838 AROS_LIBFUNC_INIT
3839 struct PsdDevice *roothub = NULL;
3840 struct PsdDevice *pd;
3842 psdLockReadPBase();
3843 /* goto root */
3844 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3845 while(pd->pd_Node.ln_Succ)
3847 if(!pd->pd_Hub)
3849 roothub = pd;
3850 break;
3852 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
3854 if(!roothub)
3856 psdUnlockPBase();
3857 return;
3859 roothub->pd_PowerDrain = 0;
3860 roothub->pd_PowerSupply = 500;
3862 /* calculate drain */
3863 pPowerRecurseDrain(ps, roothub);
3865 /* calculate supply */
3866 pPowerRecurseSupply(ps, roothub);
3867 psdUnlockPBase();
3868 AROS_LIBFUNC_EXIT
3870 /* \\\ */
3872 /* *** Pipes *** */
3874 /* /// "psdAllocPipe()" */
3875 AROS_LH3(struct PsdPipe *, psdAllocPipe,
3876 AROS_LHA(struct PsdDevice *, pd, A0),
3877 AROS_LHA(struct MsgPort *, mp, A1),
3878 AROS_LHA(struct PsdEndpoint *, pep, A2),
3879 LIBBASETYPEPTR, ps, 24, psd)
3881 AROS_LIBFUNC_INIT
3882 struct PsdPipe *pp;
3883 struct PsdDevice *hubpd;
3885 KPRINTF(2, ("psdAllocPipe(%p, %p, %p)\n", pd, mp, pep));
3886 if(!mp || !pd)
3888 return(NULL);
3890 if(pep && (pep->pep_TransType == USEAF_ISOCHRONOUS) && (!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_ISO)))
3892 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support iso transfers. Sorry.");
3893 return(NULL);
3896 if((pp = psdAllocVec(sizeof(struct PsdPipe))))
3898 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
3899 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = mp;
3900 pp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
3901 pp->pp_Device = pd;
3902 pp->pp_Endpoint = pep;
3903 pp->pp_IOReq = *(pd->pd_Hardware->phw_RootIOReq);
3904 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
3905 if(pd->pd_Flags & PDFF_LOWSPEED)
3907 pp->pp_IOReq.iouh_Flags |= UHFF_LOWSPEED;
3909 if(pd->pd_Flags & PDFF_HIGHSPEED)
3911 pp->pp_IOReq.iouh_Flags |= UHFF_HIGHSPEED;
3912 if(pep)
3914 switch(pep->pep_NumTransMuFr)
3916 case 2:
3917 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_2;
3918 break;
3919 case 3:
3920 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_3;
3921 break;
3923 default:
3924 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3926 } else {
3927 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3930 #ifdef AROS_USB30_CODE
3931 if(pd->pd_Flags & PDFF_SUPERSPEED)
3933 pp->pp_IOReq.iouh_Flags |= UHFF_SUPERSPEED;
3935 #endif
3936 if(pd->pd_Flags & PDFF_NEEDSSPLIT)
3938 /* USB1.1 device connected to a USB2.0 hub */
3939 pp->pp_IOReq.iouh_Flags |= UHFF_SPLITTRANS;
3940 hubpd = pd->pd_Hub;
3941 pp->pp_IOReq.iouh_SplitHubPort = pd->pd_HubPort;
3942 // find the root USB 2.0 hub in the tree
3943 while(hubpd && !(hubpd->pd_Flags & PDFF_HIGHSPEED))
3945 pp->pp_IOReq.iouh_SplitHubPort = hubpd->pd_HubPort;
3946 hubpd = hubpd->pd_Hub;
3948 if(!hubpd)
3950 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Internal error obtaining split transaction hub!");
3951 psdFreeVec(pp);
3952 return(NULL);
3954 pp->pp_IOReq.iouh_Flags |= (hubpd->pd_HubThinkTime<<UHFS_THINKTIME);
3955 pp->pp_IOReq.iouh_SplitHubAddr = hubpd->pd_DevAddr;
3957 if(pep)
3959 switch(pep->pep_TransType)
3961 case USEAF_CONTROL:
3962 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3963 break;
3964 case USEAF_ISOCHRONOUS:
3965 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ISOXFER;
3966 break;
3967 case USEAF_BULK:
3968 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_BULKXFER;
3969 break;
3970 case USEAF_INTERRUPT:
3971 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_INTXFER;
3972 break;
3973 default:
3974 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3975 "AllocPipe(): Illegal transfer type %ld",
3976 pep->pep_TransType);
3977 KPRINTF(20, ("Illegal transfer type for endpoint!"));
3978 psdFreeVec(pp);
3979 return(NULL);
3982 pp->pp_IOReq.iouh_Dir = (pep->pep_Direction ? UHDIR_IN : UHDIR_OUT);
3983 pp->pp_IOReq.iouh_Endpoint = pep->pep_EPNum;
3984 pp->pp_IOReq.iouh_MaxPktSize = pep->pep_MaxPktSize;
3985 pp->pp_IOReq.iouh_Interval = pep->pep_Interval;
3986 } else {
3987 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3988 pp->pp_IOReq.iouh_Dir = UHDIR_SETUP;
3989 pp->pp_IOReq.iouh_Endpoint = 0;
3990 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0;
3992 pd->pd_UseCnt++;
3993 return(pp);
3995 return(NULL);
3996 AROS_LIBFUNC_EXIT
3998 /* \\\ */
4000 /* /// "psdFreePipe()" */
4001 AROS_LH1(void, psdFreePipe,
4002 AROS_LHA(struct PsdPipe *, pp, A1),
4003 LIBBASETYPEPTR, ps, 25, psd)
4005 AROS_LIBFUNC_INIT
4006 struct PsdDevice *pd;
4007 if(!pp)
4009 return;
4011 KPRINTF(2, ("psdFreePipe(%p)\n", pp));
4012 pd = pp->pp_Device;
4014 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4016 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4017 "Tried to free pipe on %s that was still pending!", pd->pd_ProductStr);
4018 psdAbortPipe(pp);
4019 psdWaitPipe(pp);
4022 if(!(--pd->pd_UseCnt) && (pd->pd_Flags & PDFF_DELEXPUNGE))
4024 KPRINTF(20, ("Finally getting rid of device %s\n", pd->pd_ProductStr));
4025 pFreeDevice(ps, pd);
4026 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
4029 psdFreeVec(pp);
4030 AROS_LIBFUNC_EXIT
4032 /* \\\ */
4034 /* /// "psdPipeSetup()" */
4035 AROS_LH5(void, psdPipeSetup,
4036 AROS_LHA(struct PsdPipe *, pp, A1),
4037 AROS_LHA(UWORD, rt, D0),
4038 AROS_LHA(UWORD, rq, D1),
4039 AROS_LHA(UWORD, val, D2),
4040 AROS_LHA(UWORD, idx, D3),
4041 LIBBASETYPEPTR, ps, 26, psd)
4043 AROS_LIBFUNC_INIT
4044 struct UsbSetupData *usd = &pp->pp_IOReq.iouh_SetupData;
4046 KPRINTF(1, ("psdSetupPipe(%p, (%02lx %02lx %04lx %04lx))\n",
4047 pp, rt, rq, val, idx));
4048 usd->bmRequestType = rt;
4049 usd->bRequest = rq;
4050 usd->wValue = AROS_WORD2LE(val);
4051 usd->wIndex = AROS_WORD2LE(idx);
4052 AROS_LIBFUNC_EXIT
4054 /* \\\ */
4056 /* /// "psdDoPipe()" */
4057 AROS_LH3(LONG, psdDoPipe,
4058 AROS_LHA(struct PsdPipe *, pp, A1),
4059 AROS_LHA(APTR, data, A0),
4060 AROS_LHA(ULONG, len, D0),
4061 LIBBASETYPEPTR, ps, 27, psd)
4063 AROS_LIBFUNC_INIT
4064 struct PsdDevice *pd = pp->pp_Device;
4065 KPRINTF(200, ("psdDoPipe(%p, %p, %ld)\n", pp, data, len));
4067 if(pd->pd_Flags & PDFF_CONNECTED)
4069 if(pd->pd_Flags & PDFF_SUSPENDED)
4071 // make sure the device is up and running before trying to send a new pipe
4072 psdResumeDevice(pd);
4075 pp->pp_IOReq.iouh_Data = data;
4076 pp->pp_IOReq.iouh_Length = len;
4077 if(!pp->pp_Endpoint)
4079 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4081 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4082 ++pd->pd_IOBusyCount;
4083 GetSysTime((APTR) &pd->pd_LastActivity);
4084 return(psdWaitPipe(pp));
4085 } else {
4086 psdDelayMS(50);
4087 pp->pp_IOReq.iouh_Actual = 0;
4088 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4089 return(pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT);
4091 AROS_LIBFUNC_EXIT
4093 /* \\\ */
4095 /* /// "psdSendPipe()" */
4096 AROS_LH3(void, psdSendPipe,
4097 AROS_LHA(struct PsdPipe *, pp, A1),
4098 AROS_LHA(APTR, data, A0),
4099 AROS_LHA(ULONG, len, D0),
4100 LIBBASETYPEPTR, ps, 28, psd)
4102 AROS_LIBFUNC_INIT
4103 struct PsdDevice *pd = pp->pp_Device;
4104 KPRINTF(200, ("psdSendPipe(%p, %p, %ld)\n", pp, data, len));
4105 if(pd->pd_Flags & PDFF_CONNECTED)
4107 if(pd->pd_Flags & PDFF_SUSPENDED)
4109 // make sure the device is up and running before trying to send a new pipe
4110 psdResumeDevice(pd);
4113 pp->pp_IOReq.iouh_Data = data;
4114 pp->pp_IOReq.iouh_Length = len;
4115 if(!pp->pp_Endpoint)
4117 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4119 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4120 GetSysTime((APTR) &pd->pd_LastActivity);
4121 ++pd->pd_IOBusyCount;
4122 } else {
4123 psdDelayMS(50);
4124 pp->pp_IOReq.iouh_Actual = 0;
4125 //pp->pp_Msg.mn_Node.ln_Type = NT_REPLYMSG;
4126 pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT;
4127 ReplyMsg(&pp->pp_Msg);
4128 ++pd->pd_IOBusyCount;
4130 AROS_LIBFUNC_EXIT
4132 /* \\\ */
4134 /* /// "psdAbortPipe()" */
4135 AROS_LH1(void, psdAbortPipe,
4136 AROS_LHA(struct PsdPipe *, pp, A1),
4137 LIBBASETYPEPTR, ps, 29, psd)
4139 AROS_LIBFUNC_INIT
4140 struct PsdPipe *npp;
4142 KPRINTF(5, ("psdAbortPipe(%p)\n", pp));
4143 if(pp->pp_Msg.mn_Node.ln_Type != NT_MESSAGE)
4145 KPRINTF(5, ("Nothing to abort %02lx\n", pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type));
4146 return;
4148 if((npp = psdAllocVec(sizeof(struct PsdPipe))))
4150 //npp->pp_Msg.mn_Node.ln_Type = NT_MESSAGE;
4151 npp->pp_Device = pp->pp_Device;
4152 npp->pp_MsgPort = npp->pp_Msg.mn_ReplyPort = pp->pp_MsgPort;
4153 npp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
4155 npp->pp_AbortPipe = pp;
4156 PutMsg(&pp->pp_Device->pd_Hardware->phw_TaskMsgPort, &npp->pp_Msg);
4157 psdWaitPipe(npp);
4158 psdFreeVec(npp);
4160 AROS_LIBFUNC_EXIT
4162 /* \\\ */
4164 /* /// "psdWaitPipe()" */
4165 AROS_LH1(LONG, psdWaitPipe,
4166 AROS_LHA(struct PsdPipe *, pp, A1),
4167 LIBBASETYPEPTR, ps, 30, psd)
4169 AROS_LIBFUNC_INIT
4170 ULONG sigs = 0;
4171 struct PsdDevice *pd = pp->pp_Device;
4172 LONG ioerr;
4173 KPRINTF(5, ("psdWaitPipe(%p)\n", pp));
4174 while(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4176 KPRINTF(5, ("ln_Type = %02lx\n", pp->pp_Msg.mn_Node.ln_Type));
4177 sigs |= Wait(1L<<pp->pp_MsgPort->mp_SigBit);
4178 KPRINTF(5, ("sigs = %p\n", sigs));
4180 #if 1 // broken?
4181 Forbid();
4182 if(pp->pp_Msg.mn_Node.ln_Type == NT_REPLYMSG)
4184 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4185 Remove(&pp->pp_Msg.mn_Node);
4187 //if(pp->pp_MsgPort->mp_MsgList.lh_Head->ln_Succ)
4189 // avoid signals getting lost for other messages arriving.
4190 SetSignal(sigs, sigs);
4192 Permit();
4193 #else
4194 Forbid();
4195 Remove(&pp->pp_Msg.mn_Node);
4196 Permit();
4197 #endif
4198 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4199 switch(ioerr)
4201 case UHIOERR_TIMEOUT:
4202 pd->pd_DeadCount++;
4203 // fall through
4204 case UHIOERR_NAKTIMEOUT:
4205 pd->pd_DeadCount++;
4206 case UHIOERR_CRCERROR:
4207 pd->pd_DeadCount++;
4208 break;
4209 case UHIOERR_RUNTPACKET:
4210 default:
4211 if(pd->pd_DeadCount)
4213 pd->pd_DeadCount >>= 1;
4214 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4215 "Device %s starts recovering with %s (%ld)!",
4216 pd->pd_ProductStr,
4217 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
4220 KPRINTF(200, ("psdWaitPipe(%p)=%ld\n", pp, ioerr));
4221 --pd->pd_IOBusyCount;
4222 GetSysTime((APTR) &pd->pd_LastActivity);
4224 if((pd->pd_DeadCount > 19) || ((pd->pd_DeadCount > 14) && (pd->pd_Flags & (PDFF_HASDEVADDR|PDFF_HASDEVDESC))))
4226 if(!(pd->pd_Flags & PDFF_DEAD))
4228 pd->pd_Flags |= PDFF_DEAD;
4229 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4230 "Device %s probably dropped dead!", pd->pd_ProductStr);
4232 psdSendEvent(EHMB_DEVICEDEAD, pp->pp_Device, NULL);
4234 } else {
4235 if((!pd->pd_DeadCount) && ((pd->pd_Flags & (PDFF_DEAD|PDFF_CONNECTED)) == (PDFF_DEAD|PDFF_CONNECTED)))
4237 pd->pd_Flags &= ~PDFF_DEAD;
4238 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4239 "Uuuhuuuhh, the zombie %s returned from the dead!", pd->pd_ProductStr);
4242 return(ioerr);
4243 AROS_LIBFUNC_EXIT
4245 /* \\\ */
4247 /* /// "psdCheckPipe()" */
4248 AROS_LH1(struct PsdPipe *, psdCheckPipe,
4249 AROS_LHA(struct PsdPipe *, pp, A1),
4250 LIBBASETYPEPTR, ps, 71, psd)
4252 AROS_LIBFUNC_INIT
4253 KPRINTF(5, ("psdCheckPipe(%p)\n", pp));
4254 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4256 return(NULL);
4258 return(pp);
4259 AROS_LIBFUNC_EXIT
4261 /* \\\ */
4263 /* /// "psdGetPipeActual()" */
4264 AROS_LH1(ULONG, psdGetPipeActual,
4265 AROS_LHA(struct PsdPipe *, pp, A1),
4266 LIBBASETYPEPTR, ps, 31, psd)
4268 AROS_LIBFUNC_INIT
4269 KPRINTF(1, ("psdGetPipeActual(%p)\n", pp));
4270 return(pp->pp_IOReq.iouh_Actual);
4271 AROS_LIBFUNC_EXIT
4273 /* \\\ */
4275 /* /// "psdGetPipeError()" */
4276 AROS_LH1(LONG, psdGetPipeError,
4277 AROS_LHA(struct PsdPipe *, pp, A1),
4278 LIBBASETYPEPTR, ps, 32, psd)
4280 AROS_LIBFUNC_INIT
4281 KPRINTF(1, ("psdGetPipeError(%p)\n", pp));
4282 return((LONG) pp->pp_IOReq.iouh_Req.io_Error);
4283 AROS_LIBFUNC_EXIT
4285 /* \\\ */
4287 /* *** Streams *** */
4289 /* /// "psdOpenStreamA()" */
4290 AROS_LH2(struct PsdPipeStream *, psdOpenStreamA,
4291 AROS_LHA(struct PsdEndpoint *, pep, A0),
4292 AROS_LHA(struct TagItem *, tags, A1),
4293 LIBBASETYPEPTR, ps, 72, psd)
4295 AROS_LIBFUNC_INIT
4296 struct PsdPipeStream *pps;
4298 KPRINTF(2, ("psdOpenStream(%p, %p)\n", pep, tags));
4299 if(!pep)
4301 return(NULL);
4303 if((pps = psdAllocVec(sizeof(struct PsdPipeStream))))
4305 pps->pps_Device = pep->pep_Interface->pif_Config->pc_Device;
4306 pps->pps_Endpoint = pep;
4307 NewList(&pps->pps_FreePipes);
4308 NewList(&pps->pps_ReadyPipes);
4309 InitSemaphore(&pps->pps_AccessLock);
4310 pps->pps_NakTimeoutTime = 5000;
4311 if(pep->pep_Direction)
4313 /* Defaults for IN */
4314 pps->pps_NumPipes = 4;
4315 pps->pps_Flags = PSFF_READAHEAD|PSFF_BUFFERREAD|PSFF_ALLOWRUNT;
4316 pps->pps_BufferSize = 32*pps->pps_Endpoint->pep_MaxPktSize;
4317 } else {
4318 /* Defaults for OUT */
4319 pps->pps_NumPipes = 4;
4320 pps->pps_Flags = PSFF_NOSHORTPKT;
4321 pps->pps_BufferSize = 4*pps->pps_Endpoint->pep_MaxPktSize;
4324 psdSetAttrsA(PGA_PIPESTREAM, pps, tags);
4325 if(!pps->pps_Pipes)
4327 psdCloseStream(pps);
4328 pps = NULL;
4330 return(pps);
4332 return(NULL);
4333 AROS_LIBFUNC_EXIT
4335 /* \\\ */
4337 /* /// "psdCloseStream()" */
4338 AROS_LH1(void, psdCloseStream,
4339 AROS_LHA(struct PsdPipeStream *, pps, A1),
4340 LIBBASETYPEPTR, ps, 73, psd)
4342 AROS_LIBFUNC_INIT
4343 struct PsdPipe *pp;
4344 ULONG cnt;
4346 KPRINTF(2, ("psdCloseStream(%p)\n", pps));
4347 if(!pps)
4349 return;
4351 psdStreamFlush(pps);
4352 ObtainSemaphore(&pps->pps_AccessLock);
4353 if(pps->pps_Pipes)
4355 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4357 pp = pps->pps_Pipes[cnt];
4358 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
4360 KPRINTF(1, ("Abort %ld\n", cnt));
4361 psdAbortPipe(pp);
4362 KPRINTF(1, ("Wait %ld\n", cnt));
4363 psdWaitPipe(pp);
4365 KPRINTF(1, ("Free %ld\n", cnt));
4366 psdFreePipe(pp);
4368 psdFreeVec(pps->pps_Pipes);
4369 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
4371 DeleteMsgPort(pps->pps_MsgPort);
4374 psdFreeVec(pps->pps_Buffer);
4375 ReleaseSemaphore(&pps->pps_AccessLock);
4376 psdFreeVec(pps);
4377 AROS_LIBFUNC_EXIT
4379 /* \\\ */
4381 /* /// "psdStreamRead()" */
4382 AROS_LH3(LONG, psdStreamRead,
4383 AROS_LHA(struct PsdPipeStream *, pps, A1),
4384 AROS_LHA(UBYTE *, buffer, A0),
4385 AROS_LHA(LONG, length, D0),
4386 LIBBASETYPEPTR, ps, 74, psd)
4388 AROS_LIBFUNC_INIT
4389 struct PsdPipe *pp;
4390 ULONG cnt;
4391 LONG ioerr;
4392 LONG remlen;
4393 BOOL term = FALSE;
4394 LONG actual = 0;
4395 ULONG sigmask;
4397 UBYTE *bufptr;
4398 UBYTE *srcptr;
4399 UBYTE *tarrptr;
4400 ULONG tcnt;
4401 UBYTE cchar;
4403 KPRINTF(2, ("psdStreamRead(%p, %p, %ld)\n", pps, buffer, length));
4404 if(!pps)
4406 return(-1);
4408 ObtainSemaphore(&pps->pps_AccessLock);
4409 KPRINTF(2, ("Sema\n"));
4410 pps->pps_Error = 0;
4411 if((!pps->pps_Pipes) || (!pps->pps_Endpoint->pep_Direction))
4413 KPRINTF(2, ("Wrong direction!\n"));
4414 pps->pps_Error = UHIOERR_BADPARAMS;
4415 ReleaseSemaphore(&pps->pps_AccessLock);
4416 return(-1);
4418 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4420 if(pps->pps_Flags & PSFF_BUFFERREAD)
4422 /* buffered reading */
4425 /* check for incoming packets */
4426 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4428 KPRINTF(1, ("PktBack(%p, %p, %ld/%ld)=%ld\n",
4429 pp, pp->pp_IOReq.iouh_Data, pp->pp_IOReq.iouh_Actual,
4430 pp->pp_IOReq.iouh_Length, pp->pp_IOReq.iouh_Req.io_Error));
4432 pps->pps_ReqBytes -= pp->pp_IOReq.iouh_Length;
4433 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4434 if((ioerr == UHIOERR_NAKTIMEOUT) && pp->pp_IOReq.iouh_Actual)
4436 ioerr = 0;
4439 if(ioerr)
4441 pps->pps_Error = ioerr;
4442 term = TRUE;
4443 if(ioerr != UHIOERR_TIMEOUT)
4445 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4446 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4447 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4449 /* stop automatic queueing */
4450 pps->pps_Flags &= ~PSFF_READAHEAD;
4451 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4452 } else {
4453 /* successfully received packet */
4454 pps->pps_BytesPending += pp->pp_IOReq.iouh_Actual;
4455 AddTail(&pps->pps_ReadyPipes, &pp->pp_Msg.mn_Node);
4458 if(length == -1) /* get all that's there (STRONGLY DISCOURAGED! Might cause buffer overflows) */
4460 length = pps->pps_BytesPending;
4462 /* check for buffered data */
4463 while(length && pps->pps_BytesPending)
4465 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4466 if(!pp->pp_Msg.mn_Node.ln_Succ) /* debug */
4468 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) "StreamRead", "Readqueue empty!");
4469 ReleaseSemaphore(&pps->pps_AccessLock);
4470 return(-1);
4472 if(pp->pp_IOReq.iouh_Actual < pps->pps_Offset)
4474 psdAddErrorMsg(RETURN_FAIL, (STRPTR) "StreamRead",
4475 "Actual %ld < offset %ld!", pp->pp_IOReq.iouh_Actual, pps->pps_Offset);
4476 ReleaseSemaphore(&pps->pps_AccessLock);
4477 return(-1);
4479 remlen = pp->pp_IOReq.iouh_Actual - pps->pps_Offset;
4480 if(length < remlen)
4482 KPRINTF(1, ("PktBit(%p, %p, %ld)\n", pp, buffer, length));
4483 remlen = length;
4484 } else {
4485 KPRINTF(1, ("PktRem(%p, %p, %ld)\n", pp, buffer, remlen));
4487 /* copy packet */
4488 if(pp->pp_Flags & PFF_INPLACE)
4490 KPRINTF(1, ("PktRemIP(%p, %p, %ld)\n", pp, buffer, remlen));
4491 } else {
4492 if(pps->pps_TermArray)
4494 /* EOF Mode */
4495 KPRINTF(1, ("PktCpyEOF(%p, %p, %ld)\n", pp, buffer, remlen));
4496 bufptr = buffer;
4497 srcptr = &(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]);
4498 tarrptr = pps->pps_TermArray;
4499 cnt = remlen;
4500 remlen = 0;
4501 if(cnt)
4505 cchar = *bufptr++ = *srcptr++;
4506 remlen++;
4507 tcnt = 0;
4510 if(cchar < tarrptr[tcnt])
4512 break;
4514 else if(cchar == tarrptr[tcnt])
4516 cnt = 1;
4517 term = TRUE;
4518 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, remlen));
4519 break;
4521 if(tcnt < 7)
4523 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4525 break;
4528 } while(++tcnt < 8);
4529 } while(--cnt);
4531 } else {
4532 KPRINTF(1, ("PktCpy(%p, %p, %ld)\n", pp, buffer, remlen));
4533 /* quick non-eof mode */
4534 CopyMem(&(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]), buffer, remlen);
4537 actual += remlen;
4538 length -= remlen;
4539 buffer += remlen;
4540 pps->pps_BytesPending -= remlen;
4541 pps->pps_Offset += remlen;
4542 /* end of packet reached? */
4543 if(pps->pps_Offset == pp->pp_IOReq.iouh_Actual)
4545 pps->pps_Offset = 0;
4546 Remove(&pp->pp_Msg.mn_Node);
4547 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4548 /* check for short packet */
4549 if((pps->pps_Flags & PSFF_SHORTTERM) && (pp->pp_IOReq.iouh_Actual % pp->pp_IOReq.iouh_MaxPktSize))
4551 term = TRUE;
4554 if(term)
4556 break;
4559 /* start sending out requests */
4560 remlen = length;
4561 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4562 if(!(pps->pps_BytesPending || pps->pps_ReqBytes || pps->pps_TermArray || (length < pps->pps_BufferSize)))
4564 /* faster non-buffered mode */
4565 if(pp->pp_Msg.mn_Node.ln_Succ)
4567 pp->pp_Flags |= PFF_INPLACE;
4568 Remove(&pp->pp_Msg.mn_Node);
4569 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4570 KPRINTF(1, ("OutFast(%p, %p, %ld/%ld)\n",
4571 pp, buffer, remlen, length));
4572 psdSendPipe(pp, buffer, remlen);
4573 pps->pps_ReqBytes += remlen;
4574 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4577 /* slower buffered mode */
4578 while(pp->pp_Msg.mn_Node.ln_Succ && ((remlen > pps->pps_ReqBytes) || (pps->pps_Flags & PSFF_READAHEAD)))
4580 pp->pp_Flags &= ~PFF_INPLACE;
4581 Remove(&pp->pp_Msg.mn_Node);
4582 if((pps->pps_Flags & PSFF_READAHEAD) || (remlen % pp->pp_IOReq.iouh_MaxPktSize))
4584 KPRINTF(1, ("OutSlow(%p, %p, %ld)\n",
4585 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], pps->pps_BufferSize));
4586 remlen = pps->pps_BufferSize;
4587 } else {
4588 KPRINTF(1, ("OutExact(%p, %p, %ld)\n",
4589 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen));
4591 psdSendPipe(pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen);
4592 pps->pps_ReqBytes += remlen;
4593 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4595 if((!length) || (pps->pps_Flags & PSFF_DONOTWAIT))
4597 term = TRUE;
4599 if(!term)
4601 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4602 KPRINTF(1, ("WaitPort (%p)\n", sigmask));
4603 sigmask = Wait(sigmask);
4604 KPRINTF(1, ("Wait back (%p)\n", sigmask));
4605 if(sigmask & pps->pps_AbortSigMask)
4607 KPRINTF(1, ("Aborted!\n"));
4608 term = TRUE;
4609 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4612 } while(!term);
4613 } else {
4614 /* plain reading (might lose data) */
4615 if(pps->pps_TermArray || (pps->pps_Flags & PSFF_READAHEAD))
4617 psdAddErrorMsg0(RETURN_WARN, (STRPTR) "StreamRead", "This mode combination for the stream is not supported!");
4619 /* start sending out requests */
4620 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4621 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4623 ioerr = psdDoPipe(pp, buffer, length);
4624 if(ioerr)
4626 pps->pps_Error = ioerr;
4627 if(ioerr != UHIOERR_TIMEOUT)
4629 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4630 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4631 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4634 actual = pp->pp_IOReq.iouh_Actual;
4638 ReleaseSemaphore(&pps->pps_AccessLock);
4639 return(actual);
4640 AROS_LIBFUNC_EXIT
4642 /* \\\ */
4644 /* /// "psdStreamWrite()" */
4645 AROS_LH3(LONG, psdStreamWrite,
4646 AROS_LHA(struct PsdPipeStream *, pps, A1),
4647 AROS_LHA(UBYTE *, buffer, A0),
4648 AROS_LHA(LONG, length, D0),
4649 LIBBASETYPEPTR, ps, 75, psd)
4651 AROS_LIBFUNC_INIT
4652 struct PsdPipe *pp;
4653 struct PsdPipe *newpp;
4654 ULONG cnt;
4655 LONG ioerr;
4656 LONG remlen;
4657 LONG actual = 0;
4658 ULONG sigmask;
4660 UBYTE *bufptr;
4661 UBYTE *srcptr;
4662 UBYTE *tarrptr;
4663 ULONG tcnt;
4664 UBYTE cchar;
4666 KPRINTF(2, ("psdStreamWrite(%p, %p, %ld)\n", pps, buffer, length));
4667 if(!pps)
4669 return(-1);
4671 ObtainSemaphore(&pps->pps_AccessLock);
4672 pps->pps_Error = 0;
4673 if((!pps->pps_Pipes) || pps->pps_Endpoint->pep_Direction)
4675 KPRINTF(2, ("Wrong direction!\n"));
4676 pps->pps_Error = UHIOERR_BADPARAMS;
4677 ReleaseSemaphore(&pps->pps_AccessLock);
4678 return(-1);
4680 if(length == -1) /* null terminated string mode */
4682 KPRINTF(2, ("EOL mode!\n"));
4683 length = strlen(buffer);
4685 if((tarrptr = pps->pps_TermArray)) /* EOF Mode */
4687 KPRINTF(1, ("EOFSearch(%p, %ld)\n", buffer, length));
4688 srcptr = buffer;
4689 cnt = length;
4690 length = 0;
4691 if(cnt)
4695 cchar = *srcptr++;
4696 length++;
4697 tcnt = 0;
4700 if(cchar < tarrptr[tcnt])
4702 break;
4704 else if(cchar == tarrptr[tcnt])
4706 cnt = 1;
4707 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, length));
4708 break;
4710 if(tcnt)
4712 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4714 break;
4717 } while(++tcnt < 8);
4718 } while(--cnt);
4721 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4723 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4724 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4726 if(pps->pps_Flags & PSFF_BUFFERWRITE)
4728 /* buffered writing */
4729 if(pps->pps_BytesPending)
4731 remlen = pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize;
4732 /* align to packet boundary */
4733 if(remlen + length >= pp->pp_IOReq.iouh_MaxPktSize)
4735 /* new data crosses at least on packet size */
4736 if(pps->pps_BytesPending + length <= pps->pps_BufferSize)
4738 /* copy everything up to the last (!) boundary */
4739 remlen = pps->pps_BytesPending + length;
4740 remlen = remlen - (remlen % pp->pp_IOReq.iouh_MaxPktSize);
4741 remlen -= pps->pps_BytesPending;
4742 KPRINTF(1, ("PendOptCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4743 } else {
4744 /* just calculate amount to copy to the next boundary */
4745 remlen = pp->pp_IOReq.iouh_MaxPktSize - remlen;
4746 KPRINTF(1, ("PendOneCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4748 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], remlen);
4749 pps->pps_BytesPending += remlen;
4750 actual += remlen;
4751 buffer += remlen;
4752 length -= remlen;
4753 } else {
4754 KPRINTF(1, ("PendAdd(%p, %ld+%ld)\n", buffer, pps->pps_BytesPending, length));
4755 /* only a few bytes, see if we can fit them */
4756 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4757 pps->pps_BytesPending += length;
4758 actual += length;
4759 //buffer += length; /* not needed */
4760 length = 0;
4762 /* flush some buffers */
4763 if((length >= pp->pp_IOReq.iouh_MaxPktSize) ||
4764 ((pps->pps_BytesPending >= (pps->pps_BufferSize>>1)) && (pps->pps_BytesPending >= pp->pp_IOReq.iouh_MaxPktSize)))
4766 remlen = pps->pps_BytesPending - (pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize);
4767 KPRINTF(1, ("PendFlush(%ld/%ld)\n", remlen, pps->pps_BytesPending));
4768 Remove(&pp->pp_Msg.mn_Node);
4769 psdSendPipe(pp, pps->pps_Buffer, remlen);
4770 pps->pps_ActivePipe = pp;
4771 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4773 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4774 sigmask = Wait(sigmask);
4775 if(sigmask & pps->pps_AbortSigMask)
4777 KPRINTF(1, ("Kill signal detected!\n"));
4778 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4779 break;
4782 if(!newpp)
4784 psdAbortPipe(pp);
4786 ioerr = psdWaitPipe(pp);
4787 pps->pps_ActivePipe = NULL;
4788 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4790 /* move end of buffer */
4791 cnt = pps->pps_BytesPending;
4792 tcnt = pp->pp_IOReq.iouh_Actual;
4793 pps->pps_BytesPending -= tcnt;
4794 bufptr = pps->pps_Buffer;
4795 srcptr = bufptr + tcnt;
4796 cnt -= tcnt;
4797 if(cnt)
4801 *bufptr++ = *srcptr++;
4802 } while(--cnt);
4804 if(ioerr)
4806 pps->pps_Error = ioerr;
4807 if(ioerr != UHIOERR_TIMEOUT)
4809 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4810 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4811 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4813 ReleaseSemaphore(&pps->pps_AccessLock);
4814 return(actual);
4818 /* send out large chunk (avoid copying) */
4819 if(length >= pp->pp_IOReq.iouh_MaxPktSize)
4821 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4822 KPRINTF(1, ("BulkFlush(%p, %ld/%ld)\n", buffer, remlen, length));
4823 Remove(&pp->pp_Msg.mn_Node);
4824 psdSendPipe(pp, buffer, remlen);
4825 pps->pps_ActivePipe = pp;
4826 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4828 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4829 sigmask = Wait(sigmask);
4830 if(sigmask & pps->pps_AbortSigMask)
4832 KPRINTF(1, ("Kill signal detected!\n"));
4833 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4834 break;
4837 if(!newpp)
4839 psdAbortPipe(pp);
4841 ioerr = psdWaitPipe(pp);
4842 pps->pps_ActivePipe = NULL;
4843 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4845 actual += pp->pp_IOReq.iouh_Actual;
4846 buffer += pp->pp_IOReq.iouh_Actual;
4847 length -= pp->pp_IOReq.iouh_Actual;
4848 if(ioerr)
4850 pps->pps_Error = ioerr;
4851 if(ioerr != UHIOERR_TIMEOUT)
4853 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4854 "Packet(%s) failed: %s (%ld)", (STRPTR) "c",
4855 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4857 ReleaseSemaphore(&pps->pps_AccessLock);
4858 return(actual);
4861 /* buffer remaining bytes */
4862 if(length)
4864 KPRINTF(1, ("BufAdd(%p, %ld)\n", buffer, length));
4865 /* only a few bytes left, so lets buffer them */
4866 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4867 pps->pps_BytesPending += length;
4868 actual += length;
4870 } else {
4871 /* plain writing */
4872 /* start sending out requests */
4873 KPRINTF(1, ("PlainWrite(%p, %ld)\n", buffer, length));
4874 Remove(&pp->pp_Msg.mn_Node);
4875 psdSendPipe(pp, buffer, length);
4876 pps->pps_ActivePipe = pp;
4877 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4879 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4880 sigmask = Wait(sigmask);
4881 if(sigmask & pps->pps_AbortSigMask)
4883 KPRINTF(1, ("Kill signal detected!\n"));
4884 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4885 break;
4888 if(!newpp)
4890 psdAbortPipe(pp);
4892 ioerr = psdWaitPipe(pp);
4893 pps->pps_ActivePipe = NULL;
4894 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4895 if(ioerr)
4897 pps->pps_Error = ioerr;
4898 if(ioerr != UHIOERR_TIMEOUT)
4900 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4901 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4902 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4905 actual = pp->pp_IOReq.iouh_Actual;
4907 } else {
4908 KPRINTF(2, ("No free pipe!\n"));
4911 ReleaseSemaphore(&pps->pps_AccessLock);
4912 return(actual);
4913 AROS_LIBFUNC_EXIT
4915 /* \\\ */
4917 /* /// "psdStreamFlush()" */
4918 AROS_LH1(LONG, psdStreamFlush,
4919 AROS_LHA(struct PsdPipeStream *, pps, A1),
4920 LIBBASETYPEPTR, ps, 76, psd)
4922 AROS_LIBFUNC_INIT
4923 struct PsdPipe *pp;
4924 ULONG cnt;
4925 LONG ioerr;
4926 LONG ret = FALSE;
4928 KPRINTF(2, ("psdStreamFlush(%p)\n", pps));
4929 if(!pps)
4931 return(-1);
4933 ObtainSemaphore(&pps->pps_AccessLock);
4934 pps->pps_Error = 0;
4935 if(pps->pps_Endpoint->pep_Direction)
4937 /* IN */
4938 KPRINTF(2, ("Flushing in...\n"));
4939 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4941 psdAbortPipe(pps->pps_Pipes[cnt]);
4943 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4945 psdWaitPipe(pps->pps_Pipes[cnt]);
4947 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4948 while(pp->pp_Msg.mn_Node.ln_Succ)
4950 Remove(&pp->pp_Msg.mn_Node);
4951 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4952 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4954 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4956 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4958 pps->pps_ReqBytes = 0;
4959 pps->pps_BytesPending = 0;
4960 pps->pps_Offset = 0;
4961 ret = TRUE;
4962 } else {
4963 /* OUT */
4964 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4965 if(pp->pp_Msg.mn_Node.ln_Succ)
4967 ret = TRUE;
4968 if(pps->pps_BytesPending)
4970 KPRINTF(2, ("Flushing out %ld...\n", pps->pps_BytesPending));
4971 Remove(&pp->pp_Msg.mn_Node);
4972 ioerr = psdDoPipe(pp, pps->pps_Buffer, pps->pps_BytesPending);
4973 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4974 pps->pps_BytesPending = 0;
4975 if(ioerr)
4977 pps->pps_Error = ioerr;
4978 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamFlush",
4979 "Packet(%s) failed: %s (%ld)", (STRPTR) "f",
4980 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4981 ret = FALSE;
4983 } else {
4984 KPRINTF(2, ("Nothing to flush\n"));
4988 ReleaseSemaphore(&pps->pps_AccessLock);
4989 return(ret);
4990 AROS_LIBFUNC_EXIT
4992 /* \\\ */
4994 /* /// "psdGetStreamError()" */
4995 AROS_LH1(LONG, psdGetStreamError,
4996 AROS_LHA(struct PsdPipeStream *, pps, A1),
4997 LIBBASETYPEPTR, ps, 77, psd)
4999 AROS_LIBFUNC_INIT
5000 KPRINTF(1, ("psdGetStreamError(%p)\n", pps));
5001 if(pps)
5003 return((LONG) pps->pps_Error);
5004 } else {
5005 return(-1);
5007 AROS_LIBFUNC_EXIT
5009 /* \\\ */
5011 /* *** Realtime Iso */
5013 /* /// "psdAllocRTIsoHandler()" */
5014 AROS_LH2(struct PsdRTIsoHandler *, psdAllocRTIsoHandlerA,
5015 AROS_LHA(struct PsdEndpoint *, pep, A0),
5016 AROS_LHA(struct TagItem *, tags, A1),
5017 LIBBASETYPEPTR, ps, 93, psd)
5019 AROS_LIBFUNC_INIT
5020 struct PsdRTIsoHandler *prt;
5021 struct PsdPipe *pp;
5022 LONG ioerr;
5024 KPRINTF(2, ("psdAllocRTIso(%p, %p)\n", pep, tags));
5025 if(!pep)
5027 return(NULL);
5029 if(pep->pep_TransType != USEAF_ISOCHRONOUS)
5031 return(NULL);
5033 if(!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_RT_ISO))
5035 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support realtime iso transfers. Sorry.");
5036 return(NULL);
5038 if((prt = psdAllocVec(sizeof(struct PsdRTIsoHandler))))
5040 prt->prt_Device = pep->pep_Interface->pif_Config->pc_Device;
5041 prt->prt_Endpoint = pep;
5042 prt->prt_RTIso.urti_OutPrefetch = 2048;
5043 if((pp = prt->prt_Pipe = psdAllocPipe(prt->prt_Device, (struct MsgPort *) 0xffffffff, pep)))
5045 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = NULL;
5046 psdSetAttrsA(PGA_RTISO, prt, tags);
5047 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ADDISOHANDLER;
5048 pp->pp_IOReq.iouh_Data = &prt->prt_RTIso;
5049 // hardware must support quick IO for this to work!
5050 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5051 if(!ioerr)
5053 Forbid();
5054 AddTail(&prt->prt_Device->pd_RTIsoHandlers, &prt->prt_Node);
5055 Permit();
5056 return(prt);
5057 } else {
5058 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5059 "Adding RT Iso Handler failed: %s (%ld)",
5060 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5062 psdFreePipe(prt->prt_Pipe);
5064 psdFreeVec(prt);
5066 return(NULL);
5067 AROS_LIBFUNC_EXIT
5069 /* \\\ */
5071 /* /// "psdFreeRTIsoHandler()" */
5072 AROS_LH1(void, psdFreeRTIsoHandler,
5073 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5074 LIBBASETYPEPTR, ps, 94, psd)
5076 AROS_LIBFUNC_INIT
5077 struct PsdPipe *pp;
5079 if(!prt)
5081 return;
5083 Forbid();
5084 Remove(&prt->prt_Node);
5085 Permit();
5086 pp = prt->prt_Pipe;
5087 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_REMISOHANDLER;
5088 DoIO((struct IORequest *) &pp->pp_IOReq);
5089 psdFreePipe(pp);
5090 psdFreeVec(prt);
5091 AROS_LIBFUNC_EXIT
5093 /* \\\ */
5095 /* /// "psdStartRTIso()" */
5096 AROS_LH1(LONG, psdStartRTIso,
5097 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5098 LIBBASETYPEPTR, ps, 95, psd)
5100 AROS_LIBFUNC_INIT
5101 struct PsdPipe *pp;
5102 LONG ioerr;
5104 if(!prt)
5106 return UHIOERR_BADPARAMS;
5108 pp = prt->prt_Pipe;
5109 if(pp->pp_Device->pd_Flags & PDFF_SUSPENDED)
5111 // make sure the device is up and running before trying to send a new pipe
5112 psdResumeDevice(pp->pp_Device);
5114 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STARTRTISO;
5115 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5116 if(!ioerr)
5118 ++pp->pp_Device->pd_IOBusyCount;
5120 return(ioerr);
5121 AROS_LIBFUNC_EXIT
5123 /* \\\ */
5125 /* /// "psdStopRTIso()" */
5126 AROS_LH1(LONG, psdStopRTIso,
5127 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5128 LIBBASETYPEPTR, ps, 96, psd)
5130 AROS_LIBFUNC_INIT
5131 struct PsdPipe *pp;
5132 LONG ioerr;
5134 if(!prt)
5136 return UHIOERR_BADPARAMS;
5138 pp = prt->prt_Pipe;
5139 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STOPRTISO;
5140 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5141 if(!ioerr)
5143 --pp->pp_Device->pd_IOBusyCount;
5145 return(ioerr);
5146 AROS_LIBFUNC_EXIT
5148 /* \\\ */
5150 /* *** Classes *** */
5152 /* /// "psdAddClass()" */
5153 AROS_LH2(struct PsdUsbClass *, psdAddClass,
5154 AROS_LHA(STRPTR, name, A1),
5155 AROS_LHA(ULONG, vers, D0),
5156 LIBBASETYPEPTR, ps, 35, psd)
5158 AROS_LIBFUNC_INIT
5159 struct Library *cls = NULL;
5160 struct PsdUsbClass *puc;
5161 IPTR pri = 0;
5162 STRPTR desc;
5163 UWORD msgoff;
5164 STRPTR origname = name;
5165 STRPTR evilmsg[8] = { "Say hello to %s V%ld.%ld (%s).",
5166 "Whoah! %s V%ld.%ld surprised as %s.",
5167 "The door bell rang for %s V%ld.%ld (%s).",
5168 "Welcome %s V%ld.%ld (%s) to the party.",
5170 "Don't laugh at %s V%ld.%ld for %s.",
5171 "Time has come for %s V%ld.%ld (%s) to join the show.",
5172 "Start blaming %s V%ld.%ld for helping at %s.",
5173 "Ain't %s V%ld.%ld useful for %s?" };
5175 KPRINTF(5, ("psdAddClass(%s, %ld)\n", name, vers));
5177 while(*name)
5179 if((cls = OpenLibrary(name, vers)))
5181 break;
5185 if((*name == '/') || (*name == ':'))
5187 ++name;
5188 break;
5190 } while(*(++name));
5192 if(cls)
5194 Forbid();
5195 if(FindName(&ps->ps_Classes, cls->lib_Node.ln_Name))
5197 Permit();
5198 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5199 "Attempted to add class %s twice. Nothing is good enough for people like you.",
5200 name);
5201 KPRINTF(20, ("attempt to add class twice!\n"));
5202 CloseLibrary(cls);
5203 return(NULL);
5205 Permit();
5206 if((puc = psdAllocVec(sizeof(struct PsdUsbClass))))
5208 puc->puc_Base = ps;
5209 puc->puc_ClassBase = cls;
5210 puc->puc_Node.ln_Name = puc->puc_ClassName = psdCopyStr(cls->lib_Node.ln_Name);
5211 puc->puc_FullPath = psdCopyStr(origname);
5213 usbGetAttrs(UGA_CLASS, NULL,
5214 UCCA_Priority, &pri,
5215 UCCA_Description, &desc,
5216 TAG_END);
5218 puc->puc_Node.ln_Pri = pri;
5219 psdLockWritePBase();
5220 Enqueue(&ps->ps_Classes, &puc->puc_Node);
5221 psdUnlockPBase();
5222 msgoff = ps->ps_FunnyCount++ & 7;
5224 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5225 evilmsg[msgoff],
5226 cls->lib_Node.ln_Name, cls->lib_Version, cls->lib_Revision, desc);
5227 psdSendEvent(EHMB_ADDCLASS, puc, NULL);
5228 return(puc);
5230 CloseLibrary(cls);
5232 return(NULL);
5233 AROS_LIBFUNC_EXIT
5235 /* \\\ */
5237 /* /// "psdRemClass()" */
5238 AROS_LH1(void, psdRemClass,
5239 AROS_LHA(struct PsdUsbClass *, puc, A1),
5240 LIBBASETYPEPTR, ps, 36, psd)
5242 AROS_LIBFUNC_INIT
5243 KPRINTF(5, ("psdRemClass(%p)\n", puc));
5244 psdLockWritePBase();
5245 Remove(&puc->puc_Node);
5246 psdUnlockPBase();
5248 /* Check if there are still bindings remaining */
5249 while(puc->puc_UseCnt)
5251 struct PsdDevice *pd;
5252 struct PsdConfig *pc;
5253 struct PsdInterface *pif;
5255 KPRINTF(20, ("This should never happen: Class %s still in use (%ld), can't close!\n",
5256 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt));
5258 /* Well, try to release the open bindings in a best effort attempt */
5259 psdLockReadPBase();
5260 pd = NULL;
5261 while((pd = psdGetNextDevice(pd)))
5263 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
5265 psdUnlockPBase();
5266 psdReleaseDevBinding(pd);
5267 psdLockReadPBase();
5268 pd = NULL; /* restart */
5269 continue;
5271 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5272 while(pc->pc_Node.ln_Succ)
5274 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5275 while(pif->pif_Node.ln_Succ)
5277 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
5279 psdUnlockPBase();
5280 psdReleaseIfBinding(pif);
5281 psdLockReadPBase();
5282 pd = NULL; /* restart */
5283 continue;
5285 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5287 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5290 psdUnlockPBase();
5291 if(puc->puc_UseCnt)
5293 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
5294 "This should never happen! Class %s still in use (cnt=%ld). Could not get rid of it! Sorry, we're broke.",
5295 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt);
5297 /*psdDelayMS(2000);*/
5300 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5301 "I shot class %s, but I didn't kill the deputy.",
5302 puc->puc_ClassBase->lib_Node.ln_Name);
5303 CloseLibrary(puc->puc_ClassBase);
5304 psdFreeVec(puc->puc_ClassName);
5305 psdFreeVec(puc->puc_FullPath);
5306 psdFreeVec(puc);
5307 psdSendEvent(EHMB_REMCLASS, puc, NULL);
5308 AROS_LIBFUNC_EXIT
5310 /* \\\ */
5312 /* *** Error Msgs *** */
5314 /* /// "psdAddErrorMsgA()" */
5315 AROS_LH4(struct PsdErrorMsg *, psdAddErrorMsgA,
5316 AROS_LHA(UWORD, level, D0),
5317 AROS_LHA(STRPTR, origin, A0),
5318 AROS_LHA(STRPTR, fmtstr, A1),
5319 AROS_LHA(IPTR *, fmtdata, A2),
5320 LIBBASETYPEPTR, ps, 40, psd)
5322 AROS_LIBFUNC_INIT
5323 struct PsdErrorMsg *pem;
5324 if(((!ps->ps_GlobalCfg->pgc_LogInfo) && (level < RETURN_WARN)) ||
5325 ((!ps->ps_GlobalCfg->pgc_LogWarning) && (level >= RETURN_WARN) && (level < RETURN_ERROR)) ||
5326 ((!ps->ps_GlobalCfg->pgc_LogError) && (level >= RETURN_ERROR) && (level < RETURN_FAIL)) ||
5327 ((!ps->ps_GlobalCfg->pgc_LogFailure) && (level >= RETURN_FAIL)))
5329 return(NULL);
5331 if((pem = psdAllocVec(sizeof(struct PsdErrorMsg))))
5333 pem->pem_Base = ps;
5334 pem->pem_Level = level;
5335 if((pem->pem_Origin = psdCopyStr(origin)))
5337 if((pem->pem_Msg = psdCopyStrFmtA(fmtstr, fmtdata)))
5339 if (ps->ps_Flags & PSF_KLOG) {
5340 KPrintF("[%s] %s\n", origin, pem->pem_Msg);
5343 if(pOpenDOS(ps))
5345 DateStamp(&pem->pem_DateStamp);
5346 } else {
5347 struct timerequest tr = ps->ps_TimerIOReq;
5348 tr.tr_node.io_Command = TR_GETSYSTIME;
5349 DoIO((struct IORequest *) &tr);
5350 pem->pem_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60);
5351 pem->pem_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60;
5352 pem->pem_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50;
5354 Forbid();
5355 AddTail(&ps->ps_ErrorMsgs, &pem->pem_Node);
5356 Permit();
5357 psdSendEvent(EHMB_ADDERRORMSG, pem, NULL);
5358 return(pem);
5360 psdFreeVec(pem->pem_Origin);
5362 psdFreeVec(pem);
5364 return(NULL);
5365 AROS_LIBFUNC_EXIT
5367 /* \\\ */
5369 /* /// "psdRemErrorMsg()" */
5370 AROS_LH1(void, psdRemErrorMsg,
5371 AROS_LHA(struct PsdErrorMsg *, pem, A0),
5372 LIBBASETYPEPTR, ps, 41, psd)
5374 AROS_LIBFUNC_INIT
5375 KPRINTF(1, ("psdRemErrorMsg()\n"));
5376 Forbid();
5377 Remove(&pem->pem_Node);
5378 Permit();
5379 psdFreeVec(pem->pem_Origin);
5380 psdFreeVec(pem->pem_Msg);
5381 psdFreeVec(pem);
5382 psdSendEvent(EHMB_REMERRORMSG, pem, NULL);
5383 AROS_LIBFUNC_EXIT
5385 /* \\\ */
5387 /* *** Bindings *** */
5389 /* /// "psdClassScan()" */
5390 AROS_LH0(void, psdClassScan,
5391 LIBBASETYPEPTR, ps, 37, psd)
5393 AROS_LIBFUNC_INIT
5394 struct PsdHardware *phw;
5395 struct PsdDevice *pd;
5396 struct PsdUsbClass *puc;
5398 psdLockReadPBase();
5400 if((FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS) && (!ps->ps_ConfigRead))
5402 // it's the first time we were reading the config and DOS was not available
5403 ps->ps_StartedAsTask = TRUE;
5406 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5407 if(!puc->puc_Node.ln_Succ)
5409 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "ClassScan attempted with no classes installed!");
5410 psdUnlockPBase();
5411 return;
5414 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5415 while(phw->phw_Node.ln_Succ)
5417 if((pd = phw->phw_RootDevice))
5419 // for the root, do it ourselves, the rest is done by each hub task
5420 psdHubClassScan(pd);
5422 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5424 psdUnlockPBase();
5425 //psdSendEvent(EHMB_CLSSCANRDY, NULL, NULL);
5426 KPRINTF(5, ("************ Scanning finished!\n"));
5427 AROS_LIBFUNC_EXIT
5429 /* \\\ */
5431 /* /// "psdDoHubMethodA()" */
5432 AROS_LH3(LONG, psdDoHubMethodA,
5433 AROS_LHA(struct PsdDevice *, pd, A0),
5434 AROS_LHA(ULONG, methodid, D0),
5435 AROS_LHA(APTR, methoddata, A1),
5436 LIBBASETYPEPTR, ps, 92, psd)
5438 AROS_LIBFUNC_INIT
5439 struct PsdUsbClass *puc;
5440 KPRINTF(2, ("psdDoHubMethodA(%p)\n", pd));
5442 if(pd)
5444 if(pd->pd_Hub)
5446 if((pd->pd_Hub->pd_DevBinding) && (puc = pd->pd_Hub->pd_ClsBinding))
5448 return(usbDoMethodA(methodid, methoddata));
5452 return 0;
5453 AROS_LIBFUNC_EXIT
5455 /* \\\ */
5457 /* /// "psdClaimAppBindingA()" */
5458 AROS_LH1(struct PsdAppBinding *, psdClaimAppBindingA,
5459 AROS_LHA(struct TagItem *, tags, A1),
5460 LIBBASETYPEPTR, ps, 45, psd)
5462 AROS_LIBFUNC_INIT
5463 struct PsdDevice *pd;
5464 struct PsdConfig *pc;
5465 struct PsdInterface *pif;
5466 struct PsdDevice *hubpd;
5467 struct PsdAppBinding tmppab;
5468 struct PsdAppBinding *pab = NULL;
5469 struct PsdUsbClass *puc;
5471 APTR binding;
5473 KPRINTF(2, ("psdClaimAppBindingA(%p)\n", tags));
5475 tmppab.pab_Device = NULL;
5476 tmppab.pab_ReleaseHook = NULL;
5477 tmppab.pab_Task = NULL;
5478 tmppab.pab_ForceRelease = FALSE;
5479 psdSetAttrsA(PGA_APPBINDING, &tmppab, tags);
5480 if(tmppab.pab_Device && tmppab.pab_ReleaseHook)
5482 pd = tmppab.pab_Device;
5484 // force release of other bindings first
5485 if(tmppab.pab_ForceRelease)
5487 /* If there are bindings, get rid of them. */
5488 if(pd->pd_DevBinding)
5490 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5491 "%s really wants to bind to %s, so I'm letting the old binding go.",
5492 FindTask(NULL)->tc_Node.ln_Name,
5493 pd->pd_ProductStr);
5495 psdReleaseDevBinding(pd);
5496 } else {
5497 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5498 while(pc->pc_Node.ln_Succ)
5500 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5501 while(pif->pif_Node.ln_Succ)
5503 if(pif->pif_IfBinding)
5505 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5506 "%s really wants to bind to %s, so I'm letting the old binding go.",
5507 FindTask(NULL)->tc_Node.ln_Name,
5508 pd->pd_ProductStr);
5509 psdReleaseIfBinding(pif);
5511 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5513 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5517 hubpd = pd->pd_Hub;
5518 if(!hubpd) // claim app binding at the root hub -- improbable, but possible.
5520 pab = psdHubClaimAppBindingA(tags);
5521 } else {
5522 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5524 pab = (struct PsdAppBinding *) usbDoMethod(UCM_HubClaimAppBinding, binding, tags);
5527 if(pab)
5529 // fill in task names
5530 pab->pab_Task = FindTask(NULL);
5531 pab->pab_Node.ln_Name = pab->pab_Task->tc_Node.ln_Name;
5532 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5533 return(pab);
5536 return(NULL);
5537 AROS_LIBFUNC_EXIT
5539 /* \\\ */
5541 /* /// "psdReleaseAppBinding()" */
5542 AROS_LH1(void, psdReleaseAppBinding,
5543 AROS_LHA(struct PsdAppBinding *, pab, A0),
5544 LIBBASETYPEPTR, ps, 46, psd)
5546 AROS_LIBFUNC_INIT
5547 struct PsdDevice *pd;
5548 struct PsdDevice *hubpd;
5549 struct PsdUsbClass *puc;
5550 APTR binding;
5552 KPRINTF(2, ("psdReleaseAppBinding(%p)\n", pab));
5554 if(pab)
5556 pd = pab->pab_Device;
5557 hubpd = pd->pd_Hub;
5558 if(!hubpd) // release binding of hub (improbable)
5560 psdHubReleaseDevBinding(pd);
5561 return;
5563 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5565 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5568 AROS_LIBFUNC_EXIT
5570 /* \\\ */
5572 /* /// "psdReleaseDevBinding()" */
5573 AROS_LH1(void, psdReleaseDevBinding,
5574 AROS_LHA(struct PsdDevice *, pd, A0),
5575 LIBBASETYPEPTR, ps, 50, psd)
5577 AROS_LIBFUNC_INIT
5578 struct PsdUsbClass *puc;
5579 struct PsdDevice *hubpd;
5580 APTR binding;
5582 KPRINTF(5, ("psdReleaseDevBinding(%p)\n", pd));
5583 if(pd->pd_DevBinding)
5585 hubpd = pd->pd_Hub;
5586 if(!hubpd) // release binding of hub
5588 psdHubReleaseDevBinding(pd);
5589 return;
5591 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5593 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5596 AROS_LIBFUNC_EXIT
5598 /* \\\ */
5600 /* /// "psdReleaseIfBinding()" */
5601 AROS_LH1(void, psdReleaseIfBinding,
5602 AROS_LHA(struct PsdInterface *, pif, A0),
5603 LIBBASETYPEPTR, ps, 51, psd)
5605 AROS_LIBFUNC_INIT
5606 struct PsdUsbClass *puc;
5607 struct PsdDevice *hubpd;
5608 APTR binding;
5610 KPRINTF(5, ("psdReleaseIfBinding(%p)\n", pif));
5611 if(pif->pif_IfBinding && pif->pif_ClsBinding)
5613 hubpd = pif->pif_Config->pc_Device->pd_Hub;
5614 if(!hubpd) // release binding of hub (improbable)
5616 psdHubReleaseIfBinding(pif);
5617 return;
5619 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5621 usbDoMethod(UCM_HubReleaseIfBinding, binding, pif);
5624 AROS_LIBFUNC_EXIT
5626 /* \\\ */
5628 /* /// "psdUnbindAll()" */
5629 AROS_LH0(void, psdUnbindAll,
5630 LIBBASETYPEPTR, ps, 61, psd)
5632 AROS_LIBFUNC_INIT
5633 struct PsdHardware *phw;
5634 struct PsdDevice *pd;
5635 struct PsdConfig *pc;
5636 struct PsdInterface *pif;
5637 BOOL restart;
5639 KPRINTF(10, ("pUnbindAll()\n"));
5640 /* FIXME What happens if devices or hardware gets removed during the process? Need notify semaphore */
5641 psdLockReadPBase();
5644 restart = FALSE;
5645 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5646 while(phw->phw_Node.ln_Succ)
5648 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
5649 while(pd->pd_Node.ln_Succ)
5651 /* If there are bindings, get rid of them. */
5652 if(pd->pd_DevBinding)
5654 psdUnlockPBase();
5655 psdReleaseDevBinding(pd);
5656 psdLockReadPBase();
5657 restart = TRUE;
5658 break;
5660 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5661 while(pc->pc_Node.ln_Succ)
5663 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5664 while(pif->pif_Node.ln_Succ)
5666 if(pif->pif_IfBinding)
5668 psdUnlockPBase();
5669 psdReleaseIfBinding(pif);
5670 psdLockReadPBase();
5671 restart = TRUE;
5672 break;
5674 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5676 if(restart)
5678 break;
5680 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5682 if(restart)
5684 break;
5686 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
5688 if(restart)
5690 break;
5692 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5694 } while(restart);
5695 psdUnlockPBase();
5696 AROS_LIBFUNC_EXIT
5698 /* \\\ */
5700 /* /// "psdHubClassScan()" */
5701 AROS_LH1(void, psdHubClassScan,
5702 AROS_LHA(struct PsdDevice *, pd, A0),
5703 LIBBASETYPEPTR, ps, 82, psd)
5705 AROS_LIBFUNC_INIT
5706 struct PsdUsbClass *puc;
5707 struct PsdConfig *pc;
5708 struct PsdInterface *pif;
5709 struct PsdInterface *firstpif;
5710 struct PsdPipe *pp = NULL;
5711 struct MsgPort *mp;
5712 APTR binding;
5713 UWORD hasifbinding;
5714 BOOL mainif;
5715 STRPTR owner;
5717 KPRINTF(5, ("psdClassScan()\n"));
5719 if(!(mp = CreateMsgPort()))
5721 return;
5723 psdLockReadPBase();
5724 psdLockWriteDevice(pd);
5725 while(!(pd->pd_PoPoCfg.poc_NoClassBind || pd->pd_DevBinding))
5727 if(!(pp = psdAllocPipe(pd, mp, NULL)))
5729 break;
5731 KPRINTF(5, ("Doing ClassScan on Device: %s\n", pd->pd_ProductStr));
5732 hasifbinding = 0;
5733 /* First look if there is any interface binding. We may not change
5734 the current config in this case! */
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;
5740 while(pif->pif_Node.ln_Succ)
5742 if(pif->pif_IfBinding)
5744 hasifbinding = pc->pc_CfgNum;
5745 break;
5747 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5749 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5752 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5753 if((!hasifbinding) && owner)
5755 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5756 while(puc->puc_Node.ln_Succ)
5758 if(!strcmp(owner, puc->puc_ClassName))
5760 if((pd->pd_DevBinding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd)))
5762 pd->pd_ClsBinding = puc;
5763 puc->puc_UseCnt++;
5764 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5765 } else {
5766 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5767 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5769 break;
5771 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5773 /* no more scanning required, abort here */
5774 break;
5777 /* Second attempt */
5778 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5779 while(pc->pc_Node.ln_Succ)
5781 if((!hasifbinding) || (hasifbinding == pc->pc_CfgNum))
5783 /* If the current config is not the one selected, change it */
5784 if(pd->pd_CurrCfg != pc->pc_CfgNum)
5786 psdSetDeviceConfig(pp, pc->pc_CfgNum);
5788 KPRINTF(5, (" Config %ld\n", pc->pc_CfgNum));
5789 /* If something went wrong above, we must exclude this config */
5790 if(pd->pd_CurrCfg == pc->pc_CfgNum)
5792 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5793 while(pif->pif_Node.ln_Succ)
5795 KPRINTF(5, (" Interface %ld\n", pif->pif_IfNum));
5796 firstpif = pif;
5797 mainif = TRUE;
5798 if(!pif->pif_IfBinding)
5800 binding = NULL;
5803 if(!psdSetAltInterface(pp, pif))
5805 pif->pif_IfBinding = NULL;
5806 /* Okay, this alternate setting failed. Try to get next one */
5807 if(!mainif)
5809 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5810 if(pif->pif_Node.ln_Succ)
5812 KPRINTF(5, ("CONT!\n"));
5813 continue;
5814 } else {
5815 KPRINTF(5, ("BREAK!\n"));
5816 pif = firstpif;
5817 break;
5821 owner = psdGetForcedBinding(pd->pd_IDString, pif->pif_IDString);
5822 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5823 while(puc->puc_Node.ln_Succ)
5825 KPRINTF(5, (">>>PING %s!\n", puc->puc_ClassName));
5826 if(owner)
5828 if(!strcmp(owner, puc->puc_ClassName))
5830 binding = (APTR) usbDoMethod(UCM_ForceInterfaceBinding, pif);
5831 if(!binding)
5833 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5834 "Forced interface binding of %s to %s failed.", pd->pd_ProductStr, owner);
5837 if(!binding)
5839 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5840 continue;
5842 } else {
5843 binding = (APTR) usbDoMethod(UCM_AttemptInterfaceBinding, pif);
5845 Forbid();
5846 KPRINTF(5, ("<<<PONG!!\n"));
5847 if(binding)
5849 KPRINTF(5, ("Got binding!\n"));
5850 /* Find root config structure */
5851 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5852 while(pif->pif_Node.ln_Succ)
5854 if(pif->pif_IfNum == firstpif->pif_IfNum)
5856 break;
5858 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5860 if(!pif->pif_Node.ln_Succ)
5862 KPRINTF(5, ("Fucked it up!\n"));
5863 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Something incredibly stupid happend. I've given up.");
5864 Permit();
5865 break;
5867 pif->pif_IfBinding = binding;
5868 pif->pif_ClsBinding = puc;
5869 hasifbinding = pc->pc_CfgNum;
5870 puc->puc_UseCnt++;
5871 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5872 Permit();
5873 break;
5875 Permit();
5876 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5878 if(binding)
5880 break;
5882 //break; /* FIXME: DISABLED ALTSCANNING */
5883 /* Check alternate setting */
5884 if(pif->pif_AlterIfs.lh_Head->ln_Succ)
5886 /* There are some alternative interfaces, start at top */
5887 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
5888 mainif = FALSE;
5890 } while(pif != firstpif);
5891 //pif->pif_IfBinding = binding;
5892 if(!binding)
5894 psdSetAltInterface(pp, pif);
5896 /* Hohum, search current main interface then */
5897 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5898 while(pif->pif_Node.ln_Succ)
5900 if(pif->pif_IfNum == firstpif->pif_IfNum)
5902 break;
5904 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5907 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5911 KPRINTF(5, ("End, next ConfigCheck!\n"));
5912 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5914 /* Could not establish interface binding, try device binding then */
5915 //psdUnlockPBase();
5916 if(!hasifbinding)
5918 //pd->pd_DevBinding = (APTR) ~0UL;
5919 binding = NULL;
5920 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5921 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5922 while(puc->puc_Node.ln_Succ)
5924 binding = NULL;
5925 if(owner)
5927 if(!strcmp(owner, puc->puc_ClassName))
5929 binding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd, TAG_END);
5930 if(!binding)
5932 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5933 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5936 if(!binding)
5938 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5939 continue;
5941 } else {
5942 binding = (APTR) usbDoMethod(UCM_AttemptDeviceBinding, pd);
5944 if(binding)
5946 pd->pd_DevBinding = binding;
5947 pd->pd_ClsBinding = puc;
5948 puc->puc_UseCnt++;
5949 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5950 break;
5952 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5954 pd->pd_DevBinding = binding;
5956 break;
5958 if(pp)
5960 psdFreePipe(pp);
5962 // call hub class scan code
5963 if((binding = pd->pd_DevBinding) && (puc = pd->pd_ClsBinding))
5965 usbDoMethod(UCM_HubClassScan, binding);
5967 psdUnlockDevice(pd);
5968 psdUnlockPBase();
5969 DeleteMsgPort(mp);
5970 AROS_LIBFUNC_EXIT
5972 /* \\\ */
5974 /* /// "psdHubClaimAppBindingA()" */
5975 AROS_LH1(struct PsdAppBinding *, psdHubClaimAppBindingA,
5976 AROS_LHA(struct TagItem *, tags, A1),
5977 LIBBASETYPEPTR, ps, 83, psd)
5979 AROS_LIBFUNC_INIT
5980 struct PsdDevice *pd;
5981 struct PsdAppBinding *pab;
5982 struct PsdConfig *pc;
5983 struct PsdInterface *pif;
5985 BOOL hasbinding = FALSE;
5986 KPRINTF(2, ("psdHubClaimAppBindingA(%p)\n", tags));
5988 if((pab = psdAllocVec(sizeof(struct PsdAppBinding))))
5990 psdSetAttrsA(PGA_APPBINDING, pab, tags);
5991 if(pab->pab_Device && pab->pab_ReleaseHook)
5993 pd = pab->pab_Device;
5994 if(pd->pd_DevBinding)
5996 hasbinding = TRUE;
5997 } else {
5998 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5999 while(pc->pc_Node.ln_Succ)
6001 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6003 while(pif->pif_Node.ln_Succ)
6005 if(pif->pif_IfBinding)
6007 hasbinding = TRUE;
6008 break;
6010 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6012 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6015 if(!hasbinding)
6017 pd->pd_Flags |= PDFF_APPBINDING;
6018 pd->pd_DevBinding = pab;
6019 pd->pd_ClsBinding = NULL;
6020 return(pab);
6023 psdFreeVec(pab);
6025 return(NULL);
6026 AROS_LIBFUNC_EXIT
6028 /* \\\ */
6030 /* /// "psdHubReleaseDevBinding()" */
6031 AROS_LH1(void, psdHubReleaseDevBinding,
6032 AROS_LHA(struct PsdDevice *, pd, A0),
6033 LIBBASETYPEPTR, ps, 84, psd)
6035 AROS_LIBFUNC_INIT
6036 struct PsdUsbClass *puc;
6037 APTR binding;
6038 struct PsdAppBinding *pab;
6040 KPRINTF(5, ("psdHubReleaseDevBinding(%p)\n", pd));
6041 if(pd)
6043 psdLockWriteDevice(pd);
6044 if((binding = pd->pd_DevBinding))
6046 pd->pd_DevBinding = NULL;
6047 if(pd->pd_Flags & PDFF_APPBINDING)
6049 pab = (struct PsdAppBinding *) binding;
6050 CallHookPkt(pab->pab_ReleaseHook, pab, (APTR) pab->pab_UserData);
6051 pd->pd_ClsBinding = NULL;
6052 pd->pd_Flags &= ~PDFF_APPBINDING;
6053 psdFreeVec(pab);
6054 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6055 } else {
6056 puc = pd->pd_ClsBinding;
6057 if(puc)
6059 pd->pd_ClsBinding = NULL;
6060 usbDoMethod(UCM_ReleaseDeviceBinding, binding);
6061 puc->puc_UseCnt--;
6062 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6066 psdUnlockDevice(pd);
6068 AROS_LIBFUNC_EXIT
6070 /* \\\ */
6072 /* /// "psdHubReleaseIfBinding()" */
6073 AROS_LH1(void, psdHubReleaseIfBinding,
6074 AROS_LHA(struct PsdInterface *, pif, A0),
6075 LIBBASETYPEPTR, ps, 85, psd)
6077 AROS_LIBFUNC_INIT
6078 struct PsdUsbClass *puc;
6079 struct PsdDevice *pd;
6080 APTR binding;
6082 KPRINTF(5, ("psdHubReleaseIfBinding(%p)\n", pif));
6084 if(pif)
6086 pd = pif->pif_Config->pc_Device;
6087 psdLockWriteDevice(pd);
6088 if((binding = pif->pif_IfBinding))
6090 pif->pif_IfBinding = NULL;
6091 puc = pif->pif_ClsBinding;
6092 if(puc)
6094 pif->pif_ClsBinding = NULL;
6095 usbDoMethod(UCM_ReleaseInterfaceBinding, binding);
6096 puc->puc_UseCnt--;
6098 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6100 psdUnlockDevice(pd);
6102 AROS_LIBFUNC_EXIT
6104 /* \\\ */
6106 /* *** Events *** */
6108 /* /// "psdAddEventHandler()" */
6109 AROS_LH2(struct PsdEventHook *, psdAddEventHandler,
6110 AROS_LHA(struct MsgPort *, mp, A1),
6111 AROS_LHA(ULONG, msgmask, D0),
6112 LIBBASETYPEPTR, ps, 47, psd)
6114 AROS_LIBFUNC_INIT
6115 struct PsdEventHook *peh = NULL;
6117 KPRINTF(5, ("psdAddEventHandler(%p, %p)\n", mp, msgmask));
6119 if(mp)
6121 ObtainSemaphore(&ps->ps_ReentrantLock);
6122 if((peh = psdAllocVec(sizeof(struct PsdEventHook))))
6124 peh->peh_MsgPort = mp;
6125 peh->peh_MsgMask = msgmask;
6126 AddTail(&ps->ps_EventHooks, &peh->peh_Node);
6128 ReleaseSemaphore(&ps->ps_ReentrantLock);
6130 return(peh);
6131 AROS_LIBFUNC_EXIT
6133 /* \\\ */
6135 /* /// "psdRemEventHandler()" */
6136 AROS_LH1(void, psdRemEventHandler,
6137 AROS_LHA(struct PsdEventHook *, peh, A0),
6138 LIBBASETYPEPTR, ps, 48, psd)
6140 AROS_LIBFUNC_INIT
6141 struct Message *msg;
6143 KPRINTF(5, ("psdRemEventHandler(%p)\n", peh));
6144 if(!peh)
6146 return;
6148 ObtainSemaphore(&ps->ps_ReentrantLock);
6149 Remove(&peh->peh_Node);
6150 while((msg = GetMsg(peh->peh_MsgPort)))
6152 ReplyMsg(msg);
6154 ReleaseSemaphore(&ps->ps_ReentrantLock);
6155 pGarbageCollectEvents(ps);
6156 psdFreeVec(peh);
6157 AROS_LIBFUNC_EXIT
6159 /* \\\ */
6161 /* /// "psdSendEvent()" */
6162 AROS_LH3(void, psdSendEvent,
6163 AROS_LHA(ULONG, ehmt, D0),
6164 AROS_LHA(APTR, param1, A0),
6165 AROS_LHA(APTR, param2, A1),
6166 LIBBASETYPEPTR, ps, 49, psd)
6168 AROS_LIBFUNC_INIT
6169 struct PsdEventNote *pen;
6170 struct PsdEventHook *peh;
6171 ULONG msgmask = (1L<<ehmt);
6173 KPRINTF(1, ("psdSendEvent(%p, %p, %p)\n", ehmt, param1, param2));
6175 pGarbageCollectEvents(ps);
6176 ObtainSemaphore(&ps->ps_ReentrantLock);
6177 peh = (struct PsdEventHook *) ps->ps_EventHooks.lh_Head;
6178 while(peh->peh_Node.ln_Succ)
6180 if(peh->peh_MsgMask & msgmask)
6182 if((pen = psdAllocVec(sizeof(struct PsdEventNote))))
6184 pen->pen_Msg.mn_ReplyPort = &ps->ps_EventReplyPort;
6185 pen->pen_Msg.mn_Length = sizeof(struct PsdEventNote);
6186 pen->pen_Event = ehmt;
6187 pen->pen_Param1 = param1;
6188 pen->pen_Param2 = param2;
6189 PutMsg(peh->peh_MsgPort, &pen->pen_Msg);
6192 peh = (struct PsdEventHook *) peh->peh_Node.ln_Succ;
6194 ReleaseSemaphore(&ps->ps_ReentrantLock);
6195 AROS_LIBFUNC_EXIT
6197 /* \\\ */
6199 /* *** Configuration *** */
6201 /* /// "psdReadCfg()" */
6202 AROS_LH2(BOOL, psdReadCfg,
6203 AROS_LHA(struct PsdIFFContext *, pic, A0),
6204 AROS_LHA(APTR, formdata, A1),
6205 LIBBASETYPEPTR, ps, 52, psd)
6207 AROS_LIBFUNC_INIT
6208 struct PsdIFFContext *subpic;
6209 LONG len;
6210 ULONG chlen;
6211 ULONG *buf = formdata;
6212 BOOL res = TRUE;
6213 KPRINTF(10, ("psdReadCfg(%p, %p)\n", pic, formdata));
6215 pLockSemExcl(ps, &ps->ps_ConfigLock);
6216 if(!pic)
6218 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6219 if(!(pic->pic_Node.ln_Succ))
6221 pUnlockSem(ps, &ps->ps_ConfigLock);
6222 return(FALSE);
6225 if((AROS_LONG2BE(*buf) != ID_FORM) || (AROS_LONG2BE(buf[2]) != pic->pic_FormID))
6227 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to replace a cfg form with a chunk or with an alien form!");
6228 pUnlockSem(ps, &ps->ps_ConfigLock);
6229 return(FALSE);
6231 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6232 while(subpic->pic_Node.ln_Succ)
6234 pFreeForm(ps, subpic);
6235 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6237 pic->pic_ChunksLen = 0;
6238 len = (AROS_LONG2BE(buf[1]) - 3) & ~1UL;
6239 buf += 3;
6240 while(len >= 8)
6242 if(!(pAddCfgChunk(ps, pic, buf)))
6244 break;
6246 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
6247 len -= chlen;
6248 buf = (ULONG *) (((UBYTE *) buf) + chlen);
6250 if(len)
6252 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
6253 res = 0;
6256 pUnlockSem(ps, &ps->ps_ConfigLock);
6257 ps->ps_CheckConfigReq = TRUE;
6258 return(res);
6259 AROS_LIBFUNC_EXIT
6261 /* \\\ */
6263 /* /// "psdLoadCfgFromDisk()" */
6264 AROS_LH1(BOOL, psdLoadCfgFromDisk,
6265 AROS_LHA(STRPTR, filename, A1),
6266 LIBBASETYPEPTR, ps, 79, psd)
6268 AROS_LIBFUNC_INIT
6269 ULONG *buf;
6270 BOOL loaded = FALSE;
6271 BPTR filehandle;
6272 ULONG formhead[3];
6273 ULONG formlen;
6275 XPRINTF(10, ("Loading config file: %s\n", filename));
6277 if(!filename)
6279 loaded = psdLoadCfgFromDisk("ENV:Sys/poseidon.prefs");
6280 if(loaded)
6282 return(TRUE);
6285 loaded = psdLoadCfgFromDisk("ENVARC:Sys/poseidon.prefs");
6287 return(loaded);
6290 if(!pOpenDOS(ps))
6292 KPRINTF(1, ("dos.library not available yet\n"));
6293 return(FALSE);
6296 filehandle = Open(filename, MODE_OLDFILE);
6297 KPRINTF(1, ("File handle 0x%p\n", filehandle));
6298 if(filehandle)
6300 if(Read(filehandle, formhead, 12) == 12)
6302 KPRINTF(1, ("Read header\n"));
6303 if((AROS_LONG2BE(formhead[0]) == ID_FORM) && (AROS_LONG2BE(formhead[2]) == IFFFORM_PSDCFG))
6305 formlen = AROS_LONG2BE(formhead[1]);
6306 KPRINTF(1, ("Header OK, %lu bytes\n", formlen));
6308 buf = (ULONG *) psdAllocVec(formlen + 8);
6309 if(buf)
6311 buf[0] = formhead[0];
6312 buf[1] = formhead[1];
6313 buf[2] = formhead[2];
6314 if(Read(filehandle, &buf[3], formlen - 4) == formlen - 4)
6316 KPRINTF(1, ("Data read OK\n"));
6318 psdReadCfg(NULL, buf);
6319 psdParseCfg();
6321 KPRINTF(1, ("All done\n"));
6322 loaded = TRUE;
6324 psdFreeVec(buf);
6328 Close(filehandle);
6329 } else {
6330 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6331 "Failed to load config from '%s'!",
6332 filename);
6334 if(loaded)
6336 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6338 return(loaded);
6339 AROS_LIBFUNC_EXIT
6341 /* \\\ */
6343 /* /// "psdSaveCfgToDisk()" */
6344 AROS_LH2(BOOL, psdSaveCfgToDisk,
6345 AROS_LHA(STRPTR, filename, A1),
6346 AROS_LHA(BOOL, executable, D0),
6347 LIBBASETYPEPTR, ps, 80, psd)
6349 AROS_LIBFUNC_INIT
6350 ULONG *buf;
6351 BOOL saved = FALSE;
6352 BPTR filehandle;
6354 if(!filename)
6356 saved = psdSaveCfgToDisk("ENVARC:Sys/poseidon.prefs", FALSE);
6357 saved &= psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE);
6358 return(saved);
6361 if(!pOpenDOS(ps))
6363 return(FALSE);
6365 pLockSemShared(ps, &ps->ps_ConfigLock);
6367 buf = (ULONG *) psdWriteCfg(NULL);
6368 if(buf)
6370 /* Write file */
6371 filehandle = Open(filename, MODE_NEWFILE);
6372 if(filehandle)
6374 Write(filehandle, buf, (AROS_LONG2BE(buf[1])+9) & ~1UL);
6375 Close(filehandle);
6376 saved = TRUE;
6377 } else {
6378 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6379 "Failed to write config to '%s'!",
6380 filename);
6382 psdFreeVec(buf);
6384 pUnlockSem(ps, &ps->ps_ConfigLock);
6385 if(saved)
6387 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6389 return(saved);
6390 AROS_LIBFUNC_EXIT
6392 /* \\\ */
6394 /* /// "psdWriteCfg()" */
6395 AROS_LH1(APTR, psdWriteCfg,
6396 AROS_LHA(struct PsdIFFContext *, pic, A0),
6397 LIBBASETYPEPTR, ps, 53, psd)
6399 AROS_LIBFUNC_INIT
6400 ULONG len;
6401 APTR buf = NULL;
6403 KPRINTF(10, ("psdWriteCfg(%p)\n", pic));
6405 pLockSemShared(ps, &ps->ps_ConfigLock);
6406 if(!pic)
6408 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6409 if(!(pic->pic_Node.ln_Succ))
6411 pUnlockSem(ps, &ps->ps_ConfigLock);
6412 return(NULL);
6415 pUpdateGlobalCfg(ps, pic);
6416 ps->ps_CheckConfigReq = TRUE;
6417 len = pGetFormLength(pic);
6418 if((buf = psdAllocVec(len)))
6420 pInternalWriteForm(pic, buf);
6422 pUnlockSem(ps, &ps->ps_ConfigLock);
6423 return(buf);
6424 AROS_LIBFUNC_EXIT
6426 /* \\\ */
6428 /* /// "psdFindCfgForm()" */
6429 AROS_LH2(struct PsdIFFContext *, psdFindCfgForm,
6430 AROS_LHA(struct PsdIFFContext *, pic, A0),
6431 AROS_LHA(ULONG, formid, D0),
6432 LIBBASETYPEPTR, ps, 54, psd)
6434 AROS_LIBFUNC_INIT
6435 struct PsdIFFContext *subpic;
6437 KPRINTF(160, ("psdFindCfgForm(0x%p, 0x%08lx)\n", pic, formid));
6438 pLockSemShared(ps, &ps->ps_ConfigLock);
6439 if(!pic)
6441 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6442 if(!(pic->pic_Node.ln_Succ))
6444 pUnlockSem(ps, &ps->ps_ConfigLock);
6445 return(NULL);
6448 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6449 while(subpic->pic_Node.ln_Succ)
6451 if(subpic->pic_FormID == formid)
6453 pUnlockSem(ps, &ps->ps_ConfigLock);
6454 return(subpic);
6456 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
6458 pUnlockSem(ps, &ps->ps_ConfigLock);
6459 return(NULL);
6460 AROS_LIBFUNC_EXIT
6462 /* \\\ */
6464 /* /// "psdNextCfgForm()" */
6465 AROS_LH1(struct PsdIFFContext *, psdNextCfgForm,
6466 AROS_LHA(struct PsdIFFContext *, pic, A0),
6467 LIBBASETYPEPTR, ps, 55, psd)
6469 AROS_LIBFUNC_INIT
6470 ULONG formid;
6471 KPRINTF(160, ("psdNextCfgForm(%p)\n", pic));
6473 if(!pic)
6475 return(NULL);
6477 pLockSemShared(ps, &ps->ps_ConfigLock);
6478 formid = pic->pic_FormID;
6479 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6480 while(pic->pic_Node.ln_Succ)
6482 if(pic->pic_FormID == formid)
6484 pUnlockSem(ps, &ps->ps_ConfigLock);
6486 KPRINTF(1, ("Found context 0x%p\n", pic));
6487 return(pic);
6489 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6491 pUnlockSem(ps, &ps->ps_ConfigLock);
6492 return(NULL);
6493 AROS_LIBFUNC_EXIT
6495 /* \\\ */
6497 /* /// "psdAllocCfgForm()" */
6498 AROS_LH1(struct PsdIFFContext *, psdAllocCfgForm,
6499 AROS_LHA(ULONG, formid, D0),
6500 LIBBASETYPEPTR, ps, 86, psd)
6502 AROS_LIBFUNC_INIT
6503 struct PsdIFFContext *pic;
6504 KPRINTF(10, ("psdAllocCfgForm(%p)\n", formid));
6505 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
6507 NewList(&pic->pic_SubForms);
6508 //pic->pic_Parent = parent;
6509 pic->pic_FormID = formid;
6510 pic->pic_FormLength = 4;
6511 pic->pic_Chunks = NULL;
6512 pic->pic_ChunksLen = 0;
6513 pic->pic_BufferLen = 0;
6514 Forbid();
6515 AddTail(&ps->ps_AlienConfigs, &pic->pic_Node);
6516 Permit();
6518 return(pic);
6519 AROS_LIBFUNC_EXIT
6521 /* \\\ */
6523 /* /// "psdRemCfgForm()" */
6524 AROS_LH1(void, psdRemCfgForm,
6525 AROS_LHA(struct PsdIFFContext *, pic, A0),
6526 LIBBASETYPEPTR, ps, 56, psd)
6528 AROS_LIBFUNC_INIT
6529 KPRINTF(10, ("psdRemCfgForm(%p)\n", pic));
6531 pLockSemExcl(ps, &ps->ps_ConfigLock);
6532 if(!pic)
6534 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6535 if(!(pic->pic_Node.ln_Succ))
6537 pUnlockSem(ps, &ps->ps_ConfigLock);
6538 return;
6541 pFreeForm(ps, pic);
6542 pUnlockSem(ps, &ps->ps_ConfigLock);
6543 ps->ps_CheckConfigReq = TRUE;
6544 AROS_LIBFUNC_EXIT
6546 /* \\\ */
6548 /* /// "psdAddCfgEntry()" */
6549 AROS_LH2(struct PsdIFFContext *, psdAddCfgEntry,
6550 AROS_LHA(struct PsdIFFContext *, pic, A0),
6551 AROS_LHA(APTR, formdata, A1),
6552 LIBBASETYPEPTR, ps, 57, psd)
6554 AROS_LIBFUNC_INIT
6555 struct PsdIFFContext *res;
6557 KPRINTF(10, ("psdAddCfgEntry(%p, %p)\n", pic, formdata));
6558 pLockSemExcl(ps, &ps->ps_ConfigLock);
6559 if(!pic)
6561 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6562 if(!(pic->pic_Node.ln_Succ))
6564 pUnlockSem(ps, &ps->ps_ConfigLock);
6565 return(NULL);
6568 res = pAddCfgChunk(ps, pic, formdata);
6569 pUnlockSem(ps, &ps->ps_ConfigLock);
6570 ps->ps_CheckConfigReq = TRUE;
6571 return(res);
6572 AROS_LIBFUNC_EXIT
6574 /* \\\ */
6576 /* /// "psdRemCfgChunk()" */
6577 AROS_LH2(BOOL, psdRemCfgChunk,
6578 AROS_LHA(struct PsdIFFContext *, pic, A0),
6579 AROS_LHA(ULONG, chnkid, D0),
6580 LIBBASETYPEPTR, ps, 58, psd)
6582 AROS_LIBFUNC_INIT
6583 BOOL res = FALSE;
6585 KPRINTF(10, ("psdRemCfgChunk(%p, %p)\n", pic, chnkid));
6586 pLockSemExcl(ps, &ps->ps_ConfigLock);
6587 if(!pic)
6589 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6590 if(!(pic->pic_Node.ln_Succ))
6592 pUnlockSem(ps, &ps->ps_ConfigLock);
6593 return(FALSE);
6596 if(chnkid)
6598 res = pRemCfgChunk(ps, pic, chnkid);
6599 } else {
6600 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6601 while(subpic->pic_Node.ln_Succ)
6603 pFreeForm(ps, subpic);
6604 res = TRUE;
6605 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6607 if(pic->pic_ChunksLen)
6609 res = TRUE;
6611 pic->pic_ChunksLen = 0;
6612 pic->pic_FormLength = 4;
6615 pUnlockSem(ps, &ps->ps_ConfigLock);
6616 ps->ps_CheckConfigReq = TRUE;
6617 return(res);
6618 AROS_LIBFUNC_EXIT
6620 /* \\\ */
6622 /* /// "psdGetCfgChunk()" */
6623 AROS_LH2(APTR, psdGetCfgChunk,
6624 AROS_LHA(struct PsdIFFContext *, pic, A0),
6625 AROS_LHA(ULONG, chnkid, D0),
6626 LIBBASETYPEPTR, ps, 59, psd)
6628 AROS_LIBFUNC_INIT
6629 ULONG *chnk;
6630 ULONG *res = NULL;
6632 KPRINTF(10, ("psdGetCfgChunk(%p, 0x%08lx)\n", pic, chnkid));
6634 pLockSemShared(ps, &ps->ps_ConfigLock);
6635 if(!pic)
6637 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6638 if(!(pic->pic_Node.ln_Succ))
6640 pUnlockSem(ps, &ps->ps_ConfigLock);
6641 return(NULL);
6644 pUpdateGlobalCfg(ps, pic);
6645 chnk = pFindCfgChunk(ps, pic, chnkid);
6646 if(chnk)
6648 res = psdAllocVec(AROS_LONG2BE(chnk[1])+8);
6649 if(res)
6651 memcpy(res, chnk, AROS_LONG2BE(chnk[1])+8);
6654 pUnlockSem(ps, &ps->ps_ConfigLock);
6655 return(res);
6656 AROS_LIBFUNC_EXIT
6658 /* \\\ */
6660 /* /// "psdParseCfg()" */
6661 AROS_LH0(void, psdParseCfg,
6662 LIBBASETYPEPTR, ps, 60, psd)
6664 AROS_LIBFUNC_INIT
6665 struct PsdIFFContext *pic;
6666 struct PsdIFFContext *subpic;
6667 ULONG *chnk;
6668 STRPTR name;
6669 ULONG unit;
6670 struct PsdHardware *phw;
6671 struct PsdUsbClass *puc;
6672 BOOL removeall = TRUE;
6673 BOOL nodos = (FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS);
6674 IPTR restartme;
6676 XPRINTF(10, ("psdParseCfg()\n"));
6678 pLockSemShared(ps, &ps->ps_ConfigLock);
6679 pCheckCfgChanged(ps);
6680 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6681 if(!pic)
6683 pUnlockSem(ps, &ps->ps_ConfigLock);
6684 return;
6687 // if no config for hardware is found, we don't remove the devices,
6688 // because this could render the system useless (no USB mice or
6689 // keyboards to configure the hardware!)
6690 if(!psdFindCfgForm(pic, IFFFORM_UHWDEVICE))
6692 XPRINTF(10, ("No hardware data present\n"));
6693 removeall = FALSE;
6696 psdLockReadPBase();
6698 /* select all hardware devices for removal */
6699 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6700 while(phw->phw_Node.ln_Succ)
6702 phw->phw_RemoveMe = removeall;
6703 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6706 /* select all classes for removal */
6707 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6708 while(puc->puc_Node.ln_Succ)
6711 * For kickstart-resident classes we check usage count, and
6712 * remove them only if it's zero.
6713 * These classes can be responsible for devices which we can use
6714 * at boot time. If we happen to remove them, we can end up with
6715 * no input or storage devices at all.
6717 if (FindResident(puc->puc_ClassName))
6718 puc->puc_RemoveMe = (puc->puc_UseCnt == 0);
6719 else
6720 puc->puc_RemoveMe = TRUE;
6722 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6725 psdUnlockPBase();
6727 /* Get Hardware config */
6728 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6729 while(subpic)
6731 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6732 if(chnk)
6734 name = (STRPTR) &chnk[2];
6735 unit = 0;
6736 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6737 if(chnk)
6739 unit = chnk[2];
6741 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6743 phw = pFindHardware(ps, name, unit);
6744 XPRINTF(5, ("Have configuration for device 0x%p (%s unit %u)\n", phw, name, unit));
6745 if(phw)
6747 phw->phw_RemoveMe = FALSE;
6751 subpic = psdNextCfgForm(subpic);
6754 /* Get Class config */
6755 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6756 while(subpic)
6758 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6759 if(chnk)
6761 name = (STRPTR) &chnk[2];
6762 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6763 XPRINTF(5, ("Have configuration for class 0x%p (%s)\n", puc, name));
6764 if(puc)
6766 puc->puc_RemoveMe = FALSE;
6769 subpic = psdNextCfgForm(subpic);
6772 // unlock config while removing to avoid deadlocks.
6773 pUnlockSem(ps, &ps->ps_ConfigLock);
6775 /* now remove remaining classes not found in the config */
6776 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6777 while(puc->puc_Node.ln_Succ)
6779 if(puc->puc_RemoveMe)
6781 XPRINTF(5, ("Removing class %s\n", puc->puc_ClassName));
6782 psdRemClass(puc);
6783 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6784 } else {
6785 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6789 /* now remove all remaining hardware not found in the config */
6790 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6791 while(phw->phw_Node.ln_Succ)
6793 if(phw->phw_RemoveMe)
6795 XPRINTF(5, ("Removing device %s unit %u\n", phw->phw_DevName, phw->phw_Unit));
6796 psdRemHardware(phw);
6797 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6798 } else {
6799 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6803 pLockSemShared(ps, &ps->ps_ConfigLock);
6804 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6805 if(!pic)
6807 pUnlockSem(ps, &ps->ps_ConfigLock);
6808 // oops!
6809 return;
6812 /* Add missing Classes */
6813 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6814 while(subpic)
6816 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6817 if(chnk)
6819 /* *** FIXME *** POSSIBLE DEADLOCK WHEN CLASS TRIES TO DO CONFIG STUFF IN
6820 AN EXTERNAL TASK INSIDE LIBOPEN CODE */
6821 name = (STRPTR) &chnk[2];
6822 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6823 if(!puc)
6825 psdAddClass(name, 0);
6828 subpic = psdNextCfgForm(subpic);
6831 /* Now really mount Hardware found in config */
6832 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6833 while(subpic)
6835 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6836 if(chnk)
6838 name = (STRPTR) &chnk[2];
6839 unit = 0;
6840 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6841 if(chnk)
6843 unit = chnk[2];
6845 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6847 phw = pFindHardware(ps, name, unit);
6848 if(!phw)
6850 phw = psdAddHardware(name, unit);
6851 if(phw)
6853 psdEnumerateHardware(phw);
6858 subpic = psdNextCfgForm(subpic);
6860 pUnlockSem(ps, &ps->ps_ConfigLock);
6862 if(!nodos && ps->ps_StartedAsTask)
6864 // last time we were reading the config before DOS, so maybe we need to
6865 // unbind some classes that need to be overruled by newly available classes,
6866 // such as hid.class overruling bootmouse & bootkeyboard.
6867 // so unbind those classes that promote themselves as AfterDOS
6869 psdLockReadPBase();
6870 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Checking AfterDOS...");
6871 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6872 while(puc->puc_Node.ln_Succ)
6874 restartme = FALSE;
6875 usbGetAttrs(UGA_CLASS, NULL,
6876 UCCA_AfterDOSRestart, &restartme,
6877 TAG_END);
6879 if(restartme && puc->puc_UseCnt)
6881 struct PsdDevice *pd;
6882 struct PsdConfig *pc;
6883 struct PsdInterface *pif;
6885 /* Well, try to release the open bindings in a best effort attempt */
6886 pd = NULL;
6887 while((pd = psdGetNextDevice(pd)))
6889 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
6891 psdUnlockPBase();
6892 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6893 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6894 puc->puc_ClassName, "device", pd->pd_ProductStr);
6895 psdReleaseDevBinding(pd);
6896 psdLockReadPBase();
6897 pd = NULL; /* restart */
6898 continue;
6900 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6901 while(pc->pc_Node.ln_Succ)
6903 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6904 while(pif->pif_Node.ln_Succ)
6906 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
6908 psdUnlockPBase();
6909 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6910 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6911 puc->puc_ClassName, "interface", pd->pd_ProductStr);
6912 psdReleaseIfBinding(pif);
6913 psdLockReadPBase();
6914 pd = NULL; /* restart */
6915 continue;
6917 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6919 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6923 usbDoMethodA(UCM_DOSAvailableEvent, NULL);
6924 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6926 ps->ps_StartedAsTask = FALSE;
6927 psdUnlockPBase();
6930 if(nodos && (!ps->ps_ConfigRead))
6932 // it's the first time we were reading the config and DOS was not available
6933 ps->ps_StartedAsTask = TRUE;
6935 ps->ps_ConfigRead = TRUE;
6936 ps->ps_SavedConfigHash = ps->ps_ConfigHash; // update saved hash
6938 /* do a class scan */
6939 psdClassScan();
6941 if(nodos && ps->ps_GlobalCfg->pgc_BootDelay)
6943 // wait for hubs to settle
6944 psdDelayMS(1000);
6945 puc = (struct PsdUsbClass *) FindName(&ps->ps_Classes, "massstorage.class");
6946 if(puc && puc->puc_UseCnt)
6948 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6949 "Delaying further execution by %ld second(s) (boot delay).",
6950 ps->ps_GlobalCfg->pgc_BootDelay);
6951 if(ps->ps_GlobalCfg->pgc_BootDelay >= 1);
6953 psdDelayMS((ps->ps_GlobalCfg->pgc_BootDelay-1)*1000);
6955 } else {
6956 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Boot delay skipped, no mass storage devices found.");
6959 AROS_LIBFUNC_EXIT
6961 /* \\\ */
6963 /* /// "psdSetClsCfg()" */
6964 AROS_LH2(BOOL, psdSetClsCfg,
6965 AROS_LHA(STRPTR, owner, A0),
6966 AROS_LHA(APTR, form, A1),
6967 LIBBASETYPEPTR, ps, 62, psd)
6969 AROS_LIBFUNC_INIT
6970 struct PsdIFFContext *pic;
6971 BOOL result = FALSE;
6973 KPRINTF(10, ("psdSetClsCfg(%s, %p)\n", owner, form));
6974 pLockSemExcl(ps, &ps->ps_ConfigLock);
6975 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
6976 while(pic)
6978 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
6980 pic = psdFindCfgForm(pic, IFFFORM_CLASSDATA);
6981 if(pic)
6983 if(form)
6985 result = psdReadCfg(pic, form);
6986 } else {
6987 psdRemCfgChunk(pic, 0);
6988 result = TRUE;
6990 break;
6991 } else {
6992 break;
6995 pic = psdNextCfgForm(pic);
6997 if(result)
6999 pUnlockSem(ps, &ps->ps_ConfigLock);
7000 pCheckCfgChanged(ps);
7001 return(result);
7003 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7004 if(pic->pic_Node.ln_Succ)
7006 pic = pAllocForm(ps, pic, IFFFORM_CLASSCFG);
7007 if(pic)
7009 if(pAddStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7011 if(form)
7013 if(pAddCfgChunk(ps, pic, form))
7015 pUnlockSem(ps, &ps->ps_ConfigLock);
7016 pCheckCfgChanged(ps);
7017 return(TRUE);
7019 } else {
7020 ULONG buf[3];
7021 buf[0] = AROS_LONG2BE(ID_FORM);
7022 buf[1] = AROS_LONG2BE(4);
7023 buf[2] = AROS_LONG2BE(IFFFORM_CLASSDATA);
7024 if(pAddCfgChunk(ps, pic, buf))
7026 pUnlockSem(ps, &ps->ps_ConfigLock);
7027 pCheckCfgChanged(ps);
7028 return(TRUE);
7034 pUnlockSem(ps, &ps->ps_ConfigLock);
7035 pCheckCfgChanged(ps);
7036 return(FALSE);
7037 AROS_LIBFUNC_EXIT
7039 /* \\\ */
7041 /* /// "psdGetClsCfg()" */
7042 AROS_LH1(struct PsdIFFContext *, psdGetClsCfg,
7043 AROS_LHA(STRPTR, owner, A0),
7044 LIBBASETYPEPTR, ps, 63, psd)
7046 AROS_LIBFUNC_INIT
7047 struct PsdIFFContext *pic;
7049 KPRINTF(10, ("psdGetClsCfg(%s)\n", owner));
7050 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7051 while(pic)
7053 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7055 return(psdFindCfgForm(pic, IFFFORM_CLASSDATA));
7057 pic = psdNextCfgForm(pic);
7059 return(NULL);
7060 AROS_LIBFUNC_EXIT
7062 /* \\\ */
7064 /* /// "psdSetUsbDevCfg()" */
7065 AROS_LH4(BOOL, psdSetUsbDevCfg,
7066 AROS_LHA(STRPTR, owner, A0),
7067 AROS_LHA(STRPTR, devid, A2),
7068 AROS_LHA(STRPTR, ifid, A3),
7069 AROS_LHA(APTR, form, A1),
7070 LIBBASETYPEPTR, ps, 64, psd)
7072 AROS_LIBFUNC_INIT
7073 struct PsdIFFContext *pic;
7074 struct PsdIFFContext *cpic = NULL;
7075 struct PsdIFFContext *mpic = NULL;
7076 BOOL result = FALSE;
7078 KPRINTF(10, ("psdSetUsbDevCfg(%s, %s, %s, %p)\n", owner, devid, ifid, form));
7079 pLockSemExcl(ps, &ps->ps_ConfigLock);
7080 /* Find device config form. It contains all device config data */
7081 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7082 while(pic)
7084 /* Find DEVID-Chunk. Check if it matches our device id */
7085 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7087 cpic = NULL;
7088 /* We found the correct device. Now if we need to store interface data, find the interface first */
7089 if(ifid)
7091 /* Search interface config form */
7092 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7093 while(mpic)
7095 /* Found the form. Find the the ID String for the interface */
7096 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7098 /* ID did match, now check for owner */
7099 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7101 /* found it! So there is already a config saved in there. Search for dev config data form */
7102 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7103 if(!cpic)
7105 /* not found, generate it */
7106 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7108 break;
7111 mpic = psdNextCfgForm(mpic);
7113 if(!cpic)
7115 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7117 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7119 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7121 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7126 } else {
7127 /* Search for device config */
7128 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7129 while(mpic)
7131 /* search for the right owner */
7132 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7134 /* found it! So there is already a config saved in there. Search for dev config data form */
7135 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7136 if(!cpic)
7138 /* not found, generate it */
7139 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7141 break;
7143 mpic = psdNextCfgForm(mpic);
7145 if(!cpic) /* no device config form */
7147 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7149 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7151 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7156 if(cpic)
7158 if(form)
7160 result = psdReadCfg(cpic, form);
7161 } else {
7162 psdRemCfgChunk(cpic, 0);
7163 result = TRUE;
7165 break;
7168 pic = psdNextCfgForm(pic);
7170 if(result)
7172 pUnlockSem(ps, &ps->ps_ConfigLock);
7173 pCheckCfgChanged(ps);
7174 return(result);
7176 cpic = NULL;
7177 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7178 if(pic->pic_Node.ln_Succ)
7180 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7181 if(pic)
7183 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7185 if(ifid)
7187 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7189 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7191 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7193 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7197 } else {
7198 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7200 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7202 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7206 if(cpic)
7208 if(form)
7210 result = psdReadCfg(cpic, form);
7211 } else {
7212 psdRemCfgChunk(cpic, 0);
7213 result = TRUE;
7219 pUnlockSem(ps, &ps->ps_ConfigLock);
7220 pCheckCfgChanged(ps);
7221 return(result);
7222 AROS_LIBFUNC_EXIT
7224 /* \\\ */
7226 /* /// "psdGetUsbDevCfg()" */
7227 AROS_LH3(struct PsdIFFContext *, psdGetUsbDevCfg,
7228 AROS_LHA(STRPTR, owner, A0),
7229 AROS_LHA(STRPTR, devid, A2),
7230 AROS_LHA(STRPTR, ifid, A3),
7231 LIBBASETYPEPTR, ps, 65, psd)
7233 AROS_LIBFUNC_INIT
7234 struct PsdIFFContext *pic;
7235 struct PsdIFFContext *cpic = NULL;
7236 struct PsdIFFContext *mpic = NULL;
7238 KPRINTF(10, ("psdGetUsbDevCfg(%s, %s, %s)\n", owner, devid, ifid));
7239 pLockSemShared(ps, &ps->ps_ConfigLock);
7240 /* Find device config form. It contains all device config data */
7241 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7242 while(pic)
7244 /* Find DEVID-Chunk. Check if it matches our device id */
7245 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7247 cpic = NULL;
7248 /* We found the correct device. Now if we need to store interface data, find the interface first */
7249 if(ifid)
7251 /* Search interface config form */
7252 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7253 while(mpic)
7255 /* Found the form. Find the the ID String for the interface */
7256 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7258 /* ID did match, now check for owner */
7259 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7261 /* found it! So there is already a config saved in there. Search for dev config data form */
7262 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7263 break;
7266 mpic = psdNextCfgForm(mpic);
7268 } else {
7269 /* Search for device config */
7270 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7271 while(mpic)
7273 /* search for the right owner */
7274 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7276 /* found it! So there is already a config saved in there. Search for dev config data form */
7277 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7278 break;
7280 mpic = psdNextCfgForm(mpic);
7283 break;
7285 pic = psdNextCfgForm(pic);
7287 pUnlockSem(ps, &ps->ps_ConfigLock);
7288 KPRINTF(1, ("Result %p\n", cpic));
7289 return(cpic);
7290 AROS_LIBFUNC_EXIT
7292 /* \\\ */
7294 /* /// "psdSetForcedBinding()" */
7295 AROS_LH3(BOOL, psdSetForcedBinding,
7296 AROS_LHA(STRPTR, owner, A2),
7297 AROS_LHA(STRPTR, devid, A0),
7298 AROS_LHA(STRPTR, ifid, A1),
7299 LIBBASETYPEPTR, ps, 69, psd)
7301 AROS_LIBFUNC_INIT
7302 struct PsdIFFContext *pic;
7303 struct PsdIFFContext *mpic = NULL;
7304 ULONG olen = 0;
7305 BOOL result = FALSE;
7307 if(owner)
7309 olen = strlen(owner);
7311 pLockSemExcl(ps, &ps->ps_ConfigLock);
7312 /* Find device config form. It contains all device config data */
7313 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7314 while(pic)
7316 /* Find DEVID-Chunk. Check if it matches our device id */
7317 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7319 /* We found the correct device. Now if we need to store interface data, find the interface first */
7320 if(ifid)
7322 /* Search interface config form */
7323 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7324 while(mpic)
7326 /* Found the form. Find the the ID String for the interface */
7327 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7329 /* ID did match, insert/replace forced binding */
7330 if(olen)
7332 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7334 result = TRUE;
7336 } else {
7337 pRemCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7338 result = TRUE;
7341 mpic = psdNextCfgForm(mpic);
7343 if(!olen)
7345 result = TRUE;
7347 if((!result) && olen)
7349 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7351 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7353 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7355 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7357 result = TRUE;
7363 } else {
7364 /* Add FBND chunk */
7365 if(olen)
7367 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7369 result = TRUE;
7371 } else {
7372 pRemCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7373 result = TRUE;
7376 break;
7378 pic = psdNextCfgForm(pic);
7380 if(!olen)
7382 result = TRUE;
7384 if(result)
7386 pUnlockSem(ps, &ps->ps_ConfigLock);
7387 pCheckCfgChanged(ps);
7388 return(result);
7390 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7391 if(pic->pic_Node.ln_Succ)
7393 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7394 if(pic)
7396 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7398 if(ifid)
7400 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7402 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7404 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7406 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7408 result = TRUE;
7413 } else {
7414 /* Add FBND chunk */
7415 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7417 result = TRUE;
7423 pUnlockSem(ps, &ps->ps_ConfigLock);
7424 pCheckCfgChanged(ps);
7425 return(result);
7426 AROS_LIBFUNC_EXIT
7428 /* \\\ */
7430 /* /// "psdGetForcedBinding()" */
7431 AROS_LH2(STRPTR, psdGetForcedBinding,
7432 AROS_LHA(STRPTR, devid, A0),
7433 AROS_LHA(STRPTR, ifid, A1),
7434 LIBBASETYPEPTR, ps, 70, psd)
7436 AROS_LIBFUNC_INIT
7437 struct PsdIFFContext *pic;
7438 struct PsdIFFContext *mpic = NULL;
7439 ULONG *chunk;
7440 STRPTR owner = NULL;
7442 pLockSemShared(ps, &ps->ps_ConfigLock);
7443 /* Find device config form. It contains all device config data */
7444 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7445 while(pic)
7447 /* Find DEVID-Chunk. Check if it matches our device id */
7448 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7450 /* We found the correct device. Now if we need to store interface data, find the interface first */
7451 if(ifid)
7453 /* Search interface config form */
7454 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7455 while(mpic)
7457 /* Found the form. Find the the ID String for the interface */
7458 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7460 /* ID did match, now check for forced binding */
7461 chunk = pFindCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7462 if(chunk)
7464 owner = (STRPTR) &chunk[2];
7465 break;
7468 mpic = psdNextCfgForm(mpic);
7470 } else {
7471 /* Search for device forced binding */
7472 chunk = pFindCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7473 if(chunk)
7475 owner = (STRPTR) &chunk[2];
7476 break;
7479 break;
7481 pic = psdNextCfgForm(pic);
7483 pUnlockSem(ps, &ps->ps_ConfigLock);
7484 return(owner);
7485 AROS_LIBFUNC_EXIT
7487 /* \\\ */
7489 /* /// "psdAddStringChunk()" */
7490 AROS_LH3(BOOL, psdAddStringChunk,
7491 AROS_LHA(struct PsdIFFContext *, pic, A0),
7492 AROS_LHA(ULONG, chunkid, D0),
7493 AROS_LHA(CONST_STRPTR, str, A1),
7494 LIBBASETYPEPTR, ps, 87, psd)
7496 AROS_LIBFUNC_INIT
7497 BOOL res;
7498 KPRINTF(10, ("psdAddStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7499 pLockSemExcl(ps, &ps->ps_ConfigLock);
7500 res = pAddStringChunk(ps, pic, chunkid, str);
7501 pUnlockSem(ps, &ps->ps_ConfigLock);
7502 return(res);
7503 AROS_LIBFUNC_EXIT
7505 /* \\\ */
7507 /* /// "psdMatchStringChunk()" */
7508 AROS_LH3(BOOL, psdMatchStringChunk,
7509 AROS_LHA(struct PsdIFFContext *, pic, A0),
7510 AROS_LHA(ULONG, chunkid, D0),
7511 AROS_LHA(CONST_STRPTR, str, A1),
7512 LIBBASETYPEPTR, ps, 88, psd)
7514 AROS_LIBFUNC_INIT
7515 BOOL res;
7516 KPRINTF(10, ("psdMatchStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7517 pLockSemShared(ps, &ps->ps_ConfigLock);
7518 res = pMatchStringChunk(ps, pic, chunkid, str);
7519 pUnlockSem(ps, &ps->ps_ConfigLock);
7520 return(res);
7521 AROS_LIBFUNC_EXIT
7523 /* \\\ */
7525 /* /// "psdGetStringChunk()" */
7526 AROS_LH2(STRPTR, psdGetStringChunk,
7527 AROS_LHA(struct PsdIFFContext *, pic, A0),
7528 AROS_LHA(ULONG, chunkid, D0),
7529 LIBBASETYPEPTR, ps, 89, psd)
7531 AROS_LIBFUNC_INIT
7532 STRPTR str;
7533 KPRINTF(10, ("psdGetStringChunk(%p, %p)\n", pic, chunkid));
7534 pLockSemShared(ps, &ps->ps_ConfigLock);
7535 str = pGetStringChunk(ps, pic, chunkid);
7536 pUnlockSem(ps, &ps->ps_ConfigLock);
7537 return(str);
7538 AROS_LIBFUNC_EXIT
7540 /* \\\ */
7542 /* *** Configuration (non-library subroutines) *** */
7544 /* /// "pAllocForm()" */
7545 struct PsdIFFContext * pAllocForm(LIBBASETYPEPTR ps, struct PsdIFFContext *parent, ULONG formid)
7547 struct PsdIFFContext *pic;
7548 KPRINTF(10, ("pAllocForm(%p, %p)\n", parent, formid));
7549 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
7551 NewList(&pic->pic_SubForms);
7552 //pic->pic_Parent = parent;
7553 pic->pic_FormID = formid;
7554 pic->pic_FormLength = 4;
7555 pic->pic_Chunks = NULL;
7556 pic->pic_ChunksLen = 0;
7557 pic->pic_BufferLen = 0;
7558 Forbid();
7559 if(parent)
7561 AddTail(&parent->pic_SubForms, &pic->pic_Node);
7562 } else {
7563 AddTail(&ps->ps_ConfigRoot, &pic->pic_Node);
7565 Permit();
7567 return(pic);
7569 /* \\\ */
7571 /* /// "pFreeForm()" */
7572 void pFreeForm(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7574 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7575 KPRINTF(10, ("pFreeForm(%p)\n", pic));
7576 Remove(&pic->pic_Node);
7577 while(subpic->pic_Node.ln_Succ)
7579 pFreeForm(ps, subpic);
7580 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7582 psdFreeVec(pic->pic_Chunks);
7583 psdFreeVec(pic);
7585 /* \\\ */
7587 /* /// "pGetFormLength()" */
7588 ULONG pGetFormLength(struct PsdIFFContext *pic)
7590 ULONG len = (5 + pic->pic_ChunksLen) & ~1UL;
7591 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7592 //KPRINTF(10, ("pGetFormLength(%p)\n", pic));
7593 while(subpic->pic_Node.ln_Succ)
7595 len += pGetFormLength(subpic);
7596 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7598 pic->pic_FormLength = len;
7599 //KPRINTF(10, ("FormLen=%ld\n", len+8));
7600 return(len + 8);
7602 /* \\\ */
7604 /* /// "pFindCfgChunk()" */
7605 APTR pFindCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7607 ULONG *buf = pic->pic_Chunks;
7608 ULONG len = pic->pic_ChunksLen;
7609 ULONG chlen;
7610 KPRINTF(10, ("pFindCfgChunk(%p, %p)\n", pic, chnkid));
7612 while(len)
7614 if(AROS_LONG2BE(*buf) == chnkid)
7616 KPRINTF(10, ("Found at %p\n", buf));
7617 return(buf);
7619 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7620 len -= chlen;
7621 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7623 KPRINTF(10, ("Not found!\n"));
7624 return(NULL);
7626 /* \\\ */
7628 /* /// "pRemCfgChunk()" */
7629 BOOL pRemCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7631 ULONG *buf = pic->pic_Chunks;
7632 ULONG len = pic->pic_ChunksLen;
7633 ULONG chlen;
7634 KPRINTF(10, ("pRemCfgChunk(%p, %p)\n", pic, chnkid));
7636 while(len)
7638 chlen = ((AROS_LONG2BE(buf[1])) + 9) & ~1UL;
7639 if(AROS_LONG2BE(*buf) == chnkid)
7641 len -= chlen;
7642 if(len)
7644 memcpy(buf, &((UBYTE *) buf)[chlen], (size_t) len);
7646 pic->pic_ChunksLen -= chlen;
7647 KPRINTF(10, ("Deleted %ld bytes to %ld chunk len\n", chlen, pic->pic_ChunksLen));
7648 return(TRUE);
7650 len -= chlen;
7651 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7653 KPRINTF(10, ("Not found!\n"));
7654 return(FALSE);
7656 /* \\\ */
7658 /* /// "pAddCfgChunk()" */
7659 struct PsdIFFContext * pAddCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, APTR chunk)
7661 LONG len;
7662 LONG chlen;
7663 ULONG *buf = chunk;
7664 ULONG *newbuf;
7665 struct PsdIFFContext *subpic;
7666 KPRINTF(10, ("pAddCfgChunk(%p, %p)\n", pic, chunk));
7667 if(AROS_LONG2BE(*buf) == ID_FORM)
7669 buf++;
7670 len = ((AROS_LONG2BE(*buf)) - 3) & ~1UL;
7671 buf++;
7672 if((subpic = pAllocForm(ps, pic, AROS_LONG2BE(*buf))))
7674 buf++;
7675 while(len >= 8)
7677 if(!(pAddCfgChunk(ps, subpic, buf)))
7679 break;
7681 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7682 len -= chlen;
7683 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7685 if(len)
7687 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
7688 return(NULL);
7690 } else {
7691 return(NULL);
7693 return(subpic);
7694 } else {
7695 pRemCfgChunk(ps, pic, AROS_LONG2BE(*buf));
7696 len = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7697 if(pic->pic_ChunksLen+len > pic->pic_BufferLen)
7699 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));
7701 /* Expand buffer */
7702 if((newbuf = psdAllocVec((pic->pic_ChunksLen+len)<<1)))
7704 if(pic->pic_ChunksLen)
7706 memcpy(newbuf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7707 psdFreeVec(pic->pic_Chunks);
7709 pic->pic_Chunks = newbuf;
7710 pic->pic_BufferLen = (pic->pic_ChunksLen+len)<<1;
7711 } else {
7712 return(NULL);
7715 memcpy(&(((UBYTE *) pic->pic_Chunks)[pic->pic_ChunksLen]), chunk, (size_t) len);
7716 pic->pic_ChunksLen += len;
7717 return(pic);
7720 /* \\\ */
7722 /* /// "pInternalWriteForm()" */
7723 ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf)
7725 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7726 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7727 *buf++ = AROS_LONG2BE(ID_FORM);
7728 *buf++ = AROS_LONG2BE(pic->pic_FormLength);
7729 *buf++ = AROS_LONG2BE(pic->pic_FormID);
7730 if(pic->pic_ChunksLen)
7732 memcpy(buf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7733 buf = (ULONG *) (((UBYTE *) buf) + pic->pic_ChunksLen);
7735 while(subpic->pic_Node.ln_Succ)
7737 buf = pInternalWriteForm(subpic, buf);
7738 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7740 return(buf);
7742 /* \\\ */
7744 /* /// "pCalcCfgCRC()" */
7745 ULONG pCalcCfgCRC(struct PsdIFFContext *pic)
7747 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7748 ULONG len;
7749 ULONG crc = pic->pic_FormID;
7750 UWORD *ptr;
7752 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7753 if(pic->pic_ChunksLen)
7755 len = pic->pic_ChunksLen>>1;
7756 if(len)
7758 ptr = (UWORD *) pic->pic_Chunks;
7761 crc = ((crc<<1)|(crc>>31))^(*ptr++);
7762 } while(--len);
7765 while(subpic->pic_Node.ln_Succ)
7767 crc ^= pCalcCfgCRC(subpic);
7768 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7770 return(crc);
7772 /* \\\ */
7774 /* /// "pCheckCfgChanged()" */
7775 BOOL pCheckCfgChanged(LIBBASETYPEPTR ps)
7777 ULONG crc;
7778 struct PsdIFFContext *pic;
7779 struct PsdIFFContext *subpic;
7780 STRPTR tmpstr;
7782 pLockSemShared(ps, &ps->ps_ConfigLock);
7783 ps->ps_CheckConfigReq = FALSE;
7784 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7785 if(!(pic->pic_Node.ln_Succ))
7787 pUnlockSem(ps, &ps->ps_ConfigLock);
7788 return(FALSE);
7790 crc = pCalcCfgCRC(pic);
7791 if(crc != ps->ps_ConfigHash)
7793 ULONG *chnk;
7794 ps->ps_ConfigHash = crc;
7795 /* Get Global config */
7796 if((subpic = psdFindCfgForm(pic, IFFFORM_STACKCFG)))
7798 if((chnk = pFindCfgChunk(ps, subpic, IFFCHNK_GLOBALCFG)))
7800 CopyMem(&chnk[2], ((UBYTE *) ps->ps_GlobalCfg) + 8, min(AROS_LONG2BE(chnk[1]), AROS_LONG2BE(ps->ps_GlobalCfg->pgc_Length)));
7802 if(!pMatchStringChunk(ps, subpic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile))
7804 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_INSERTSND)))
7806 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
7807 ps->ps_PoPo.po_InsertSndFile = tmpstr;
7810 if(!pMatchStringChunk(ps, subpic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile))
7812 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_REMOVESND)))
7814 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
7815 ps->ps_PoPo.po_RemoveSndFile = tmpstr;
7819 pUnlockSem(ps, &ps->ps_ConfigLock);
7820 psdSendEvent(EHMB_CONFIGCHG, NULL, NULL);
7821 return(TRUE);
7823 pUnlockSem(ps, &ps->ps_ConfigLock);
7824 return(FALSE);
7826 /* \\\ */
7828 /* /// "pAddStringChunk()" */
7829 BOOL pAddStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7831 BOOL res = FALSE;
7832 ULONG len = strlen(str);
7833 ULONG *chnk = (ULONG *) psdAllocVec((ULONG) len+8+2);
7834 if(chnk)
7836 chnk[0] = AROS_LONG2BE(chunkid);
7837 chnk[1] = AROS_LONG2BE(len+1);
7838 strcpy((STRPTR) &chnk[2], str);
7839 if(pAddCfgChunk(ps, pic, chnk))
7841 res = TRUE;
7843 psdFreeVec(chnk);
7845 return(res);
7847 /* \\\ */
7849 /* /// "pMatchStringChunk()" */
7850 BOOL pMatchStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7852 ULONG *chunk;
7853 ULONG len;
7854 STRPTR srcptr;
7855 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7857 srcptr = (STRPTR) &chunk[2];
7858 len = AROS_LONG2BE(chunk[1]);
7859 while(len-- && *srcptr)
7861 if(*str++ != *srcptr++)
7863 return(FALSE);
7866 if(!*str)
7868 return(TRUE);
7871 return(FALSE);
7873 /* \\\ */
7875 /* /// "pGetStringChunk()" */
7876 STRPTR pGetStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid)
7878 ULONG *chunk;
7879 STRPTR str;
7880 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7882 if((str = (STRPTR) psdAllocVec(AROS_LONG2BE(chunk[1]) + 1)))
7884 memcpy(str, &chunk[2], (size_t) AROS_LONG2BE(chunk[1]));
7885 return(str);
7888 return(NULL);
7890 /* \\\ */
7892 /* /// "pUpdateGlobalCfg()" */
7893 void pUpdateGlobalCfg(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7895 struct PsdIFFContext *tmppic;
7896 /* Set Global config */
7897 if(pic == (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head)
7899 if((tmppic = psdFindCfgForm(NULL, IFFFORM_STACKCFG)))
7901 pAddCfgChunk(ps, tmppic, ps->ps_GlobalCfg);
7902 pAddStringChunk(ps, tmppic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile);
7903 pAddStringChunk(ps, tmppic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile);
7907 /* \\\ */
7909 /* *** Misc (non library functions) ***/
7911 /* /// "pGetDevConfig()" */
7912 BOOL pGetDevConfig(struct PsdPipe *pp)
7914 struct PsdDevice *pd = pp->pp_Device;
7915 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
7916 UBYTE *tempbuf;
7917 struct UsbStdCfgDesc uscd;
7918 ULONG len;
7919 LONG ioerr;
7920 STRPTR classname;
7921 UWORD curcfg = 0;
7923 KPRINTF(1, ("Getting configuration descriptor...\n"));
7924 psdLockWriteDevice(pd);
7925 while(curcfg < pd->pd_NumCfgs)
7927 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
7928 USR_GET_DESCRIPTOR, (UDT_CONFIGURATION<<8)|curcfg, 0);
7930 /*tempbuf = psdAllocVec(256);
7931 ioerr = psdDoPipe(pp, tempbuf, 34);
7932 if(ioerr == UHIOERR_RUNTPACKET)
7934 ioerr = 0;
7936 memcpy(&uscd, tempbuf, 9);*/
7937 ioerr = psdDoPipe(pp, &uscd, 9);//sizeof(struct UsbStdCfgDesc));
7938 if(!ioerr)
7940 KPRINTF(1, ("Config type: %ld\n", (ULONG) uscd.bDescriptorType));
7941 len = (ULONG) AROS_WORD2LE(uscd.wTotalLength);
7942 KPRINTF(1, ("Configsize %ld, total size %ld\n", (ULONG) uscd.bLength, len));
7943 if((tempbuf = psdAllocVec(len)))
7944 //if(1)
7946 KPRINTF(1, ("Getting whole configuration descriptor...\n"));
7947 ioerr = psdDoPipe(pp, tempbuf, len);
7948 if(!ioerr)
7950 struct PsdConfig *pc = NULL;
7951 struct PsdInterface *pif = NULL;
7952 struct PsdInterface *altif = NULL;
7953 struct PsdEndpoint *pep = NULL;
7954 struct PsdDescriptor *pdd = NULL;
7955 UBYTE *dbuf = tempbuf;
7956 UBYTE *bufend;
7957 ULONG dlen;
7958 bufend = &dbuf[len];
7959 while(dbuf < bufend)
7961 dlen = dbuf[0]; /* bLength */
7962 if(dlen < 2)
7964 break;
7966 if(&dbuf[dlen] > bufend)
7968 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "End of descriptor past buffer!");
7970 switch(dbuf[1]) /* bDescriptorType */
7972 case UDT_CONFIGURATION:
7974 struct UsbStdCfgDesc *usc = (struct UsbStdCfgDesc *) dbuf;
7975 pif = NULL;
7976 altif = NULL;
7977 pep = NULL;
7978 if((pc = pAllocConfig(pd)))
7980 pd->pd_Flags |= PDFF_CONFIGURED;
7981 pc->pc_NumIfs = usc->bNumInterfaces;
7982 pc->pc_CfgNum = usc->bConfigurationValue;
7983 pc->pc_Attr = usc->bmAttributes;
7984 pc->pc_MaxPower = usc->bMaxPower<<1;
7986 KPRINTF(1, (" Config %ld\n", pc->pc_CfgNum));
7987 if(usc->iConfiguration)
7989 pc->pc_CfgStr = psdGetStringDescriptor(pp, usc->iConfiguration);
7991 if(!pc->pc_CfgStr)
7993 pc->pc_CfgStr = psdCopyStrFmt("Configuration %ld", pc->pc_CfgNum);
7995 } else {
7996 KPRINTF(20, (" Config allocation failed\n"));
7998 break;
8001 case UDT_INTERFACE:
8003 struct UsbStdIfDesc *usif = (struct UsbStdIfDesc *) dbuf;
8004 pep = NULL;
8005 if(pc)
8007 if((altif = pAllocInterface(pc)))
8009 altif->pif_IfNum = usif->bInterfaceNumber;
8010 altif->pif_Alternate = usif->bAlternateSetting;
8011 altif->pif_NumEPs = usif->bNumEndpoints;
8012 altif->pif_IfClass = usif->bInterfaceClass;
8013 altif->pif_IfSubClass = usif->bInterfaceSubClass;
8014 altif->pif_IfProto = usif->bInterfaceProtocol;
8015 KPRINTF(2, (" Interface %ld\n", altif->pif_IfNum));
8016 if(usif->iInterface)
8018 altif->pif_IfStr = psdGetStringDescriptor(pp, usif->iInterface);
8020 if(!altif->pif_IfStr)
8022 classname = psdNumToStr(NTS_CLASSCODE, (LONG) altif->pif_IfClass, NULL);
8023 if(classname)
8025 altif->pif_IfStr = psdCopyStrFmt("%s interface (%ld)", classname, altif->pif_IfNum);
8026 } else {
8027 altif->pif_IfStr = psdCopyStrFmt("Interface %ld", altif->pif_IfNum);
8030 KPRINTF(2, (" IfName : %s\n"
8031 " Alternate : %ld\n"
8032 " NumEPs : %ld\n"
8033 " IfClass : %ld\n"
8034 " IfSubClass: %ld\n"
8035 " IfProto : %ld\n",
8036 altif->pif_IfStr, altif->pif_Alternate,
8037 altif->pif_NumEPs,
8038 altif->pif_IfClass,
8039 altif->pif_IfSubClass, altif->pif_IfProto));
8040 if(pc->pc_CfgNum == 1)
8042 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx",
8043 altif->pif_IfNum, altif->pif_Alternate,
8044 altif->pif_IfClass, altif->pif_IfSubClass,
8045 altif->pif_IfProto);
8046 } else {
8047 // for more than one config, add config number (retain backwards compatibility with most devices)
8048 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx-%02lx",
8049 pc->pc_CfgNum,
8050 altif->pif_IfNum, altif->pif_Alternate,
8051 altif->pif_IfClass, altif->pif_IfSubClass,
8052 altif->pif_IfProto);
8055 /* Move the interface to the alternatives if possible */
8056 if(altif->pif_Alternate)
8058 if(!pif)
8060 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Alternate interface without prior main interface!");
8061 KPRINTF(20, (" Alternate interface without prior main interface\n"));
8062 pif = altif;
8063 } else {
8064 Remove(&altif->pif_Node);
8065 AddTail(&pif->pif_AlterIfs, &altif->pif_Node);
8066 altif->pif_ParentIf = pif;
8068 } else {
8069 altif->pif_ParentIf = NULL;
8070 pif = altif;
8072 } else {
8073 KPRINTF(20, (" Interface allocation failed\n"));
8075 } else {
8076 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Interface without prior config descriptor!");
8077 KPRINTF(20, (" Interface descriptor without Config\n"));
8079 break;
8082 case UDT_ENDPOINT:
8084 struct UsbStdEPDesc *usep = (struct UsbStdEPDesc *) dbuf;
8085 if(altif)
8087 if((pep = pAllocEndpoint(altif)))
8089 STRPTR eptype;
8090 pep->pep_EPNum = usep->bEndpointAddress & 0x0f;
8091 pep->pep_Direction = usep->bEndpointAddress>>7;
8092 pep->pep_TransType = usep->bmAttributes & 0x03;
8093 pep->pep_SyncType = (usep->bmAttributes>>2) & 0x03;
8094 pep->pep_UsageType = (usep->bmAttributes>>4) & 0x03;
8095 eptype = (pep->pep_TransType == USEAF_INTERRUPT) ? "int" : "iso";
8097 pep->pep_MaxPktSize = AROS_WORD2LE(usep->wMaxPacketSize) & 0x07ff;
8098 pep->pep_NumTransMuFr = ((AROS_WORD2LE(usep->wMaxPacketSize)>>11) & 3) + 1;
8099 if(pep->pep_NumTransMuFr == 4)
8101 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains illegal Num Trans µFrame value!");
8102 pep->pep_NumTransMuFr = 1;
8105 pep->pep_Interval = usep->bInterval;
8106 if(pd->pd_Flags & PDFF_HIGHSPEED)
8108 switch(pep->pep_TransType)
8110 case USEAF_CONTROL:
8111 case USEAF_BULK:
8112 //pep->pep_Interval = 0; // no use here, NAK rate not of interest
8113 break;
8115 case USEAF_ISOCHRONOUS:
8116 if(pep->pep_MaxPktSize > 1024)
8118 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8119 "Endpoint contains %s (%ld) MaxPktSize value!",
8120 (STRPTR) "too high", pep->pep_MaxPktSize);
8121 pep->pep_MaxPktSize = 1024;
8124 case USEAF_INTERRUPT:
8125 if(!pep->pep_Interval)
8127 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8128 "%sspeed %s endpoint contains %s interval value! Fixing.",
8129 (STRPTR) "High", eptype, (STRPTR) "zero");
8130 pep->pep_Interval = 1;
8132 else if(pep->pep_Interval > 16)
8134 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8135 "%sspeed %s endpoint contains %s interval value! Fixing.",
8136 (STRPTR) "High", eptype, (STRPTR) "too high");
8137 pep->pep_Interval = 16;
8139 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8140 break;
8143 else if(pd->pd_Flags & PDFF_LOWSPEED)
8145 switch(pep->pep_TransType)
8147 case USEAF_INTERRUPT:
8148 if(pep->pep_Interval < 8)
8150 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8151 (STRPTR) "Low", eptype, (STRPTR) "too low");
8152 pep->pep_Interval = 8;
8154 break;
8156 case USEAF_CONTROL:
8157 case USEAF_BULK:
8158 pep->pep_Interval = 0; // no use here
8159 break;
8161 case USEAF_ISOCHRONOUS:
8162 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Lowspeed devices cannot have isochronous endpoints!");
8163 break;
8165 } else {
8166 switch(pep->pep_TransType)
8168 case USEAF_INTERRUPT:
8169 if(!pep->pep_Interval)
8171 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8172 (STRPTR) "Full", eptype, (STRPTR) "zero");
8173 pep->pep_Interval = 1;
8175 break;
8177 case USEAF_CONTROL:
8178 case USEAF_BULK:
8179 pep->pep_Interval = 0; // no use here
8180 break;
8182 case USEAF_ISOCHRONOUS:
8183 if(pep->pep_MaxPktSize > 1023)
8185 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains too high (%ld) MaxPktSize value! Fixing.", pep->pep_MaxPktSize);
8186 pep->pep_MaxPktSize = 1023;
8188 if(!pep->pep_Interval)
8190 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8191 (STRPTR) "Full", eptype, (STRPTR) "zero");
8192 pep->pep_Interval = 1;
8194 else if(pep->pep_Interval > 16)
8196 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8197 (STRPTR) "Full", eptype, (STRPTR) "too high");
8198 pep->pep_Interval = 16;
8200 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8201 break;
8205 KPRINTF(2, (" Endpoint %ld\n", pep->pep_EPNum));
8206 KPRINTF(2, (" Direction : %s\n"
8207 " TransType : %ld\n"
8208 " MaxPktSize: %ld\n"
8209 " Interval : %ld\n",
8210 (pep->pep_Direction ? "IN" : "OUT"),
8211 pep->pep_TransType, pep->pep_MaxPktSize,
8212 pep->pep_Interval));
8214 } else {
8215 KPRINTF(20, (" Endpoint allocation failed\n"));
8217 } else {
8218 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint without prior interface descriptor!");
8219 KPRINTF(20, (" Endpoint descriptor without Interface\n"));
8221 break;
8224 case UDT_DEVICE:
8225 case UDT_HUB:
8226 case UDT_HID:
8227 case UDT_REPORT:
8228 case UDT_PHYSICAL:
8229 case UDT_CS_INTERFACE:
8230 case UDT_CS_ENDPOINT:
8231 case UDT_DEVICE_QUALIFIER:
8232 case UDT_OTHERSPEED_QUALIFIER:
8233 case UDT_INTERFACE_POWER:
8234 case UDT_OTG:
8235 //psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping descriptor %02lx (pc=%p, pif=%p altpif=%p).", dbuf[1], pc, pif, altif);
8236 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8237 break;
8239 default:
8240 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping unknown descriptor %02lx.", dbuf[1]);
8241 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8242 break;
8244 // add descriptor to device
8245 pdd = pAllocDescriptor(pd, dbuf);
8246 if(pdd)
8248 STRPTR descname = NULL;
8250 pdd->pdd_Config = pc;
8251 pdd->pdd_Interface = altif;
8252 pdd->pdd_Endpoint = pep;
8253 if(pdd->pdd_Interface)
8255 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
8257 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8258 if(!descname)
8260 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8263 if(!descname)
8265 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8267 if(!descname)
8269 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8272 if(descname)
8274 pdd->pdd_Name = descname;
8277 dbuf += dlen;
8279 KPRINTF(1, ("Configuration acquired!\n"));
8280 psdFreeVec(tempbuf);
8281 curcfg++;
8282 continue;
8283 //psdUnlockDevice(pd);
8284 //return(TRUE);
8285 } else {
8286 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8287 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8288 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8289 KPRINTF(15, ("GET_DESCRIPTOR failed %ld!\n", ioerr));
8291 psdFreeVec(tempbuf);
8292 } else {
8293 KPRINTF(20, ("No memory for %ld bytes config temp buffer!\n", len));
8295 } else {
8296 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8297 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8298 9, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8299 KPRINTF(15, ("GET_DESCRIPTOR (9) failed %ld!\n", ioerr));
8301 psdUnlockDevice(pd);
8302 return(FALSE);
8304 psdUnlockDevice(pd);
8305 return(TRUE);
8307 /* \\\ */
8309 /* /// "pPowerRecurseDrain()" */
8310 ULONG pPowerRecurseDrain(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8312 struct PsdDevice *nextpd;
8313 struct PsdConfig *pc;
8314 UWORD maxdrain = 666;
8315 UWORD childdrain;
8316 BOOL selfpwd = TRUE;
8317 pd->pd_PowerDrain = 0;
8319 /* look at config */
8320 if((pc = pd->pd_CurrentConfig))
8323 /* if suspended, no more than 500µA are drained */
8324 if(pd->pd_Flags & PDFF_SUSPENDED)
8326 pd->pd_PowerDrain = (pc->pc_MaxPower >= 100) ? 3 : 1;
8327 return(pd->pd_PowerDrain);
8329 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8330 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8331 maxdrain = selfpwd ? 500 : 100;
8334 /* examine children */
8335 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8336 while(nextpd->pd_Node.ln_Succ)
8338 if(nextpd->pd_Hub == pd)
8340 childdrain = pPowerRecurseDrain(ps, nextpd);
8341 // limit the drain to the maximum power suckage
8342 pd->pd_PowerDrain += (childdrain > maxdrain) ? maxdrain : childdrain;
8344 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8347 /* look at config */
8348 if(selfpwd)
8350 pd->pd_PowerDrain = 0;
8351 } else {
8352 pd->pd_PowerDrain += pc->pc_MaxPower;
8354 return(pd->pd_PowerDrain);
8356 /* \\\ */
8358 /* /// "pPowerRecurseSupply()" */
8359 void pPowerRecurseSupply(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8361 struct PsdDevice *nextpd;
8362 struct PsdConfig *pc;
8363 UWORD ports = 0;
8364 UWORD supply = 666;
8365 BOOL selfpwd = TRUE;
8367 /* look at config */
8368 if((pc = pd->pd_CurrentConfig))
8370 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8371 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8374 /* count children */
8375 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8376 while(nextpd->pd_Node.ln_Succ)
8378 if(nextpd->pd_Hub == pd) // this device is a child of us (we're a hub!)
8380 ports++;
8382 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8385 /* look at config */
8386 if(selfpwd)
8388 if(pc)
8390 pd->pd_PowerSupply = ports ? 500*ports + pc->pc_MaxPower : pc->pc_MaxPower;
8392 supply = 500; // each downstream port gets the full monty
8393 } else {
8394 // the parent hub has already set the amount of supply for this port
8395 if(pd->pd_PowerSupply >= pc->pc_MaxPower)
8397 // the downstream ports get the remaining divided attention
8398 if(ports)
8400 // avoid division by zero
8401 supply = (pd->pd_PowerSupply - pc->pc_MaxPower) / ports;
8402 if(supply > 100)
8404 // limit to 100 mA per port
8405 supply = 100;
8408 } else {
8409 supply = 1; // bad luck, out of power
8413 /* set supply */
8414 if(ports) /* needs to be a hub */
8416 // propagate supply down to the children
8417 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8418 while(nextpd->pd_Node.ln_Succ)
8420 if(nextpd->pd_Hub == pd)
8422 nextpd->pd_PowerSupply = supply;
8423 pPowerRecurseSupply(ps, nextpd);
8425 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8428 if(pd->pd_PowerDrain > pd->pd_PowerSupply)
8430 if(!(pd->pd_Flags & PDFF_LOWPOWER))
8432 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8433 "Detected low power condition for '%s'.", pd->pd_ProductStr);
8434 pd->pd_Flags |= PDFF_LOWPOWER;
8435 psdSendEvent(EHMB_DEVICELOWPW, pd, NULL);
8437 } else {
8438 if(pd->pd_Flags & PDFF_LOWPOWER)
8440 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
8441 "Low power condition resolved for '%s'.", pd->pd_ProductStr);
8442 pd->pd_Flags &= ~PDFF_LOWPOWER;
8446 /* \\\ */
8448 /* /// "pGarbageCollectEvents()" */
8449 void pGarbageCollectEvents(LIBBASETYPEPTR ps)
8451 struct PsdEventNote *pen;
8452 while((pen = (struct PsdEventNote *) GetMsg(&ps->ps_EventReplyPort)))
8454 psdFreeVec(pen);
8457 /* \\\ */
8459 /* /// "pFindName()" */
8460 struct Node * pFindName(LIBBASETYPEPTR ps, struct List *list, STRPTR name)
8462 struct Node *res = NULL;
8464 Forbid();
8465 while(*name)
8467 res = FindName(list, name);
8468 if(res)
8470 break;
8474 if((*name == '/') || (*name == ':'))
8476 ++name;
8477 break;
8479 } while(*(++name));
8481 Permit();
8482 return(res);
8484 /* \\\ */
8486 /* /// "pStripString()" */
8487 void pStripString(LIBBASETYPEPTR ps, STRPTR str)
8489 STRPTR srcptr = str;
8490 STRPTR tarptr = str;
8491 STRPTR lastgoodchar = str;
8492 BOOL leadingspaces = TRUE;
8493 UBYTE ch;
8494 ULONG len = 0;
8496 while((ch = *srcptr++))
8498 len++;
8499 if(ch == ' ')
8501 if(!leadingspaces)
8503 *tarptr++ = ch;
8505 } else {
8506 *tarptr++ = ch;
8507 lastgoodchar = tarptr;
8508 leadingspaces = FALSE;
8511 *lastgoodchar = 0;
8512 // empty string?
8513 if((str == lastgoodchar) && (len > 6))
8515 strcpy(str, "<empty>");
8518 /* \\\ */
8520 /* /// "pFixBrokenConfig()" */
8521 BOOL pFixBrokenConfig(struct PsdPipe *pp)
8523 struct PsdDevice *pd = pp->pp_Device;
8524 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
8525 struct PsdConfig *pc;
8526 struct PsdInterface *pif;
8527 BOOL fixed = FALSE;
8529 switch(pd->pd_VendorID)
8531 case 0x03eb: /* Atmel */
8532 if(pd->pd_ProductID == 0x3312)
8534 psdFreeVec(pd->pd_ProductStr);
8535 pd->pd_ProductStr = psdCopyStr("Highway/Subway Root Hub");
8537 break;
8539 case 0x04e6: /* E-Shuttle */
8540 if(pd->pd_ProductID == 0x0001) /* LS120 */
8542 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8543 /* Get msd interface and fix it */
8544 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8545 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8547 fixed = TRUE;
8548 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "E-Shuttle LS120");
8549 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8550 pif->pif_IfSubClass = MS_ATAPI_SUBCLASS;
8551 pif->pif_IfProto = MS_PROTO_CB;
8554 break;
8556 case 0x054C: /* Sony */
8557 if((pd->pd_ProductID == 0x002E) || (pd->pd_ProductID == 0x0010)) /* Handycam */
8559 fixed = TRUE;
8560 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Sony MSD");
8561 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8562 /* Get msd interface and fix it */
8563 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8564 pif->pif_IfSubClass = MS_RBC_SUBCLASS;
8566 break;
8568 case 0x057b: /* Y-E Data */
8569 if(pd->pd_ProductID == 0x0000) /* Flashbuster U */
8571 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8572 /* Get msd interface and fix it */
8573 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8574 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8576 fixed = TRUE;
8577 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Y-E Data USB Floppy");
8578 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8579 pif->pif_IfSubClass = MS_UFI_SUBCLASS;
8580 pif->pif_IfProto = (pd->pd_DevVers < 0x0300) ? MS_PROTO_CB : MS_PROTO_CBI;
8583 break;
8585 case 0x04ce: /* ScanLogic */
8586 if(pd->pd_ProductID == 0x0002)
8588 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "ScanLogic");
8589 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8590 /* Get msd interface and fix it */
8591 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8592 fixed = TRUE;
8593 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8595 break;
8597 case 0x0584: /* Ratoc cardreader */
8598 if(pd->pd_ProductID == 0x0008)
8600 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "RATOC");
8601 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8602 /* Get msd interface and fix it */
8603 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8604 fixed = TRUE;
8605 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8606 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8607 pif->pif_IfProto = MS_PROTO_BULK;
8609 break;
8611 case 0x04b8: /* Epson */
8612 if(pd->pd_ProductID == 0x0602) /* EPX Storage device (Card slot in Printer) */
8614 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Epson storage");
8615 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8616 /* Get msd interface and fix it */
8617 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8618 fixed = TRUE;
8619 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8620 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8621 pif->pif_IfProto = MS_PROTO_BULK;
8623 break;
8625 default:
8626 break;
8628 return(fixed);
8630 /* \\\ */
8632 /* /// "pOpenDOS()" */
8633 BOOL pOpenDOS(LIBBASETYPEPTR ps)
8635 if(DOSBase)
8637 return TRUE;
8639 if((DOSBase = OpenLibrary("dos.library", 39)))
8641 return TRUE;
8643 return FALSE;
8645 /* \\\ */
8647 /* *** Class Scan Task *** */
8649 /* /// "pStartEventHandler()" */
8650 BOOL pStartEventHandler(LIBBASETYPEPTR ps)
8652 struct PsdHandlerTask *ph = &ps->ps_EventHandler;
8654 ObtainSemaphore(&ps->ps_PoPoLock);
8655 if(ph->ph_Task)
8657 ReleaseSemaphore(&ps->ps_PoPoLock);
8658 return(TRUE);
8660 ph->ph_ReadySignal = SIGB_SINGLE;
8661 ph->ph_ReadySigTask = FindTask(NULL);
8662 SetSignal(0, SIGF_SINGLE); // clear single bit
8663 if(psdSpawnSubTask("Poseidon Event Broadcast", pEventHandlerTask, ps))
8665 Wait(1UL<<ph->ph_ReadySignal);
8667 ph->ph_ReadySigTask = NULL;
8668 //FreeSignal(ph->ph_ReadySignal);
8669 if(ph->ph_Task)
8671 ReleaseSemaphore(&ps->ps_PoPoLock);
8672 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Event broadcaster started.");
8673 return(TRUE);
8675 ReleaseSemaphore(&ps->ps_PoPoLock);
8676 return(FALSE);
8678 /* \\\ */
8680 /* *** Hardware Driver Task *** */
8682 /* /// "pQuickForwardRequest()" */
8683 AROS_UFH1(void, pQuickForwardRequest,
8684 AROS_UFHA(struct MsgPort *, msgport, A1))
8686 AROS_USERFUNC_INIT
8687 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8688 struct PsdPipe *pp;
8690 while((pp = (struct PsdPipe *) RemHead(&msgport->mp_MsgList)))
8692 if(pp->pp_AbortPipe)
8694 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8695 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8696 ReplyMsg(&pp->pp_Msg);
8697 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8698 } else {
8699 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8700 pp->pp_IOReq.iouh_UserData = pp;
8701 SendIO((struct IORequest *) &pp->pp_IOReq);
8702 ++phw->phw_MsgCount;
8705 AROS_USERFUNC_EXIT
8707 /* \\\ */
8709 /* /// "pQuickReplyRequest()" */
8710 AROS_UFH1(void, pQuickReplyRequest,
8711 AROS_UFHA(struct MsgPort *, msgport, A1))
8713 AROS_USERFUNC_INIT
8714 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8715 struct IOUsbHWReq *ioreq;
8717 while((ioreq = (struct IOUsbHWReq *) RemHead(&msgport->mp_MsgList)))
8719 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8720 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8721 --phw->phw_MsgCount;
8723 AROS_USERFUNC_EXIT
8725 /* \\\ */
8727 /* /// "pDeviceTask()" */
8728 AROS_UFH0(void, pDeviceTask)
8730 AROS_USERFUNC_INIT
8731 LIBBASETYPEPTR ps;
8732 struct PsdHardware *phw;
8733 struct Task *thistask;
8734 ULONG sigs;
8735 ULONG sigmask;
8736 LONG ioerr;
8737 struct TagItem taglist[11];
8738 struct TagItem *tag;
8739 struct PsdPipe *pp;
8740 struct IOUsbHWReq *ioreq;
8742 STRPTR prodname = NULL;
8743 STRPTR manufacturer = NULL;
8744 STRPTR description = NULL;
8745 STRPTR copyright = NULL;
8746 ULONG version = 0;
8747 ULONG revision = 0;
8748 ULONG driververs = 0x0100;
8749 ULONG caps = UHCF_ISO;
8750 STRPTR devname;
8751 ULONG cnt;
8753 if(!(ps = (LIBBASETYPEPTR) OpenLibrary("poseidon.library", 4)))
8755 Alert(AG_OpenLib);
8756 return;
8758 thistask = FindTask(NULL);
8759 SetTaskPri(thistask, 21);
8760 phw = thistask->tc_UserData;
8762 #ifndef PA_CALLBACK // undocumented exec feature
8763 #define PA_CALLBACK 3
8764 #endif
8766 phw->phw_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8767 phw->phw_TaskMsgPort.mp_Node.ln_Name = (APTR) phw;
8768 phw->phw_TaskMsgPort.mp_Flags = PA_SIGNAL;
8769 phw->phw_TaskMsgPort.mp_SigTask = thistask;
8770 phw->phw_TaskMsgPort.mp_SigBit = AllocSignal(-1L);
8771 NewList(&phw->phw_TaskMsgPort.mp_MsgList);
8773 phw->phw_DevMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8774 phw->phw_DevMsgPort.mp_Node.ln_Name = (APTR) phw;
8775 phw->phw_DevMsgPort.mp_Flags = PA_SIGNAL;
8776 phw->phw_DevMsgPort.mp_SigTask = thistask;
8777 phw->phw_DevMsgPort.mp_SigBit = AllocSignal(-1L);
8778 NewList(&phw->phw_DevMsgPort.mp_MsgList);
8780 if((phw->phw_RootIOReq = (struct IOUsbHWReq *) CreateIORequest(&phw->phw_DevMsgPort, sizeof(struct IOUsbHWReq))))
8782 devname = phw->phw_DevName;
8783 ioerr = -1;
8784 while(*devname)
8786 if(!(ioerr = OpenDevice(devname, phw->phw_Unit, (struct IORequest *) phw->phw_RootIOReq, 0)))
8788 break;
8792 if((*devname == '/') || (*devname == ':'))
8794 ++devname;
8795 break;
8797 } while(*(++devname));
8800 if(!ioerr)
8802 phw->phw_Node.ln_Name = phw->phw_RootIOReq->iouh_Req.io_Device->dd_Library.lib_Node.ln_Name;
8803 tag = taglist;
8804 tag->ti_Tag = UHA_ProductName;
8805 tag->ti_Data = (IPTR) &prodname;
8806 ++tag;
8807 tag->ti_Tag = UHA_Manufacturer;
8808 tag->ti_Data = (IPTR) &manufacturer;
8809 ++tag;
8810 tag->ti_Tag = UHA_Description;
8811 tag->ti_Data = (IPTR) &description;
8812 ++tag;
8813 tag->ti_Tag = UHA_Version;
8814 tag->ti_Data = (IPTR) &version;
8815 ++tag;
8816 tag->ti_Tag = UHA_Revision;
8817 tag->ti_Data = (IPTR) &revision;
8818 ++tag;
8819 tag->ti_Tag = UHA_Copyright;
8820 tag->ti_Data = (IPTR) &copyright;
8821 ++tag;
8822 tag->ti_Tag = UHA_DriverVersion;
8823 tag->ti_Data = (IPTR) &driververs;
8824 ++tag;
8825 tag->ti_Tag = UHA_Capabilities;
8826 tag->ti_Data = (IPTR) &caps;
8827 ++tag;
8828 tag->ti_Tag = TAG_END;
8829 phw->phw_RootIOReq->iouh_Data = taglist;
8830 phw->phw_RootIOReq->iouh_Req.io_Command = UHCMD_QUERYDEVICE;
8831 DoIO((struct IORequest *) phw->phw_RootIOReq);
8833 phw->phw_ProductName = psdCopyStr(prodname ? prodname : (STRPTR) "n/a");
8834 phw->phw_Manufacturer = psdCopyStr(manufacturer ? manufacturer : (STRPTR) "n/a");
8835 phw->phw_Description = psdCopyStr(description ? description : (STRPTR) "n/a");
8836 phw->phw_Copyright = psdCopyStr(copyright ? copyright : (STRPTR) "n/a");
8837 phw->phw_Version = version;
8838 phw->phw_Revision = revision;
8839 phw->phw_DriverVers = driververs;
8840 phw->phw_Capabilities = caps;
8842 sigmask = SIGBREAKF_CTRL_C;
8843 if(caps & UHCF_QUICKIO)
8845 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Enabling QuickIO for %s.", prodname);
8846 phw->phw_TaskMsgPort.mp_Flags = PA_CALLBACK;
8847 phw->phw_TaskMsgPort.mp_SigTask = (APTR) pQuickForwardRequest;
8849 phw->phw_DevMsgPort.mp_Flags = PA_CALLBACK;
8850 phw->phw_DevMsgPort.mp_SigTask = (APTR) pQuickReplyRequest;
8851 } else {
8852 sigmask |= (1UL<<phw->phw_DevMsgPort.mp_SigBit)|(1UL<<phw->phw_TaskMsgPort.mp_SigBit);
8855 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
8856 phw->phw_Task = thistask;
8858 psdLockWritePBase();
8859 AddTail(&ps->ps_Hardware, &phw->phw_Node);
8860 psdUnlockPBase();
8862 Forbid();
8863 if(phw->phw_ReadySigTask)
8865 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
8867 Permit();
8870 KPRINTF(1, ("Main loop wait.\n"));
8871 while((pp = (struct PsdPipe *) GetMsg(&phw->phw_TaskMsgPort)))
8873 if(pp->pp_AbortPipe)
8875 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8876 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8877 ReplyMsg(&pp->pp_Msg);
8878 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8879 } else {
8880 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8881 pp->pp_IOReq.iouh_UserData = pp;
8882 SendIO((struct IORequest *) &pp->pp_IOReq);
8883 ++phw->phw_MsgCount;
8886 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8888 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8889 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8890 --phw->phw_MsgCount;
8892 sigs = Wait(sigmask);
8893 } while(!(sigs & SIGBREAKF_CTRL_C));
8894 /* Flush all pending IO Requests */
8895 phw->phw_RootIOReq->iouh_Req.io_Command = CMD_FLUSH;
8896 DoIO((struct IORequest *) phw->phw_RootIOReq);
8897 cnt = 0;
8898 while(phw->phw_MsgCount)
8900 KPRINTF(20, ("Still %ld iorequests pending!\n", phw->phw_MsgCount));
8901 psdDelayMS(100);
8902 if(++cnt == 50)
8904 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8905 "There are still %ld IORequests pending, before unit can go down. Driver buggy?",
8906 phw->phw_MsgCount);
8908 if(cnt == 300)
8910 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8911 "Okay, I've waited long enough, sod these %ld IORequests.",
8912 phw->phw_MsgCount);
8913 phw->phw_MsgCount = 0;
8914 break;
8916 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8918 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8919 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8920 --phw->phw_MsgCount;
8923 psdLockWritePBase();
8924 Remove(&phw->phw_Node);
8925 psdUnlockPBase();
8926 CloseDevice((struct IORequest *) phw->phw_RootIOReq);
8927 } else {
8928 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
8929 "Opening %s unit %ld failed %s (%ld).",
8930 phw->phw_DevName, phw->phw_Unit, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8932 DeleteIORequest((struct IORequest *) phw->phw_RootIOReq);
8933 phw->phw_RootIOReq = NULL;
8935 FreeSignal((LONG) phw->phw_TaskMsgPort.mp_SigBit);
8936 FreeSignal((LONG) phw->phw_DevMsgPort.mp_SigBit);
8938 CloseLibrary((struct Library *) ps);
8939 phw->phw_Task = NULL;
8941 Forbid();
8942 if(phw->phw_ReadySigTask)
8944 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
8946 AROS_USERFUNC_EXIT
8948 /* \\\ */
8950 /* /// "pEventHandlerTask()" */
8951 AROS_UFH0(void, pEventHandlerTask)
8953 AROS_USERFUNC_INIT
8954 LIBBASETYPEPTR ps;
8955 struct Task *thistask;
8956 struct timeval currtime;
8957 ULONG sigs;
8958 ULONG sigmask;
8959 struct PsdUsbClass *puc;
8960 struct PsdHandlerTask *ph;
8961 struct PsdEventNote *pen;
8962 ULONG counter;
8963 ULONG cfgchanged;
8965 thistask = FindTask(NULL);
8966 ps = thistask->tc_UserData;
8967 ph = &ps->ps_EventHandler;
8968 SetTaskPri(thistask, 0);
8970 if((ph->ph_MsgPort = CreateMsgPort()))
8972 if((ph->ph_TimerMsgPort = CreateMsgPort()))
8974 if((ph->ph_TimerIOReq = (struct timerequest *) CreateIORequest(ph->ph_TimerMsgPort, sizeof(struct timerequest))))
8976 if(!(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) ph->ph_TimerIOReq, 0)))
8978 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
8979 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "EventHandler";
8980 ph->ph_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
8982 ph->ph_EventHandler = psdAddEventHandler(ph->ph_MsgPort, EHMF_CONFIGCHG);
8983 if(ph->ph_EventHandler)
8985 ph->ph_Task = thistask;
8986 Forbid();
8987 if(ph->ph_ReadySigTask)
8989 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
8991 Permit();
8993 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
8994 SendIO(&ph->ph_TimerIOReq->tr_node);
8995 sigmask = (1UL<<ph->ph_MsgPort->mp_SigBit)|(1UL<<ph->ph_TimerMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
8996 counter = 0;
8997 cfgchanged = 0;
9000 if(ps->ps_CheckConfigReq)
9002 pCheckCfgChanged(ps);
9004 while((pen = (struct PsdEventNote *) GetMsg(ph->ph_MsgPort)))
9006 switch(pen->pen_Event)
9008 case EHMB_CONFIGCHG:
9009 if(!cfgchanged)
9011 cfgchanged = counter;
9013 break;
9016 ReplyMsg(&pen->pen_Msg);
9018 if(CheckIO(&ph->ph_TimerIOReq->tr_node))
9020 BOOL startpopo;
9021 WaitIO(&ph->ph_TimerIOReq->tr_node);
9022 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9023 SendIO(&ph->ph_TimerIOReq->tr_node);
9024 counter++;
9025 startpopo = !((counter & 3) || ps->ps_PoPo.po_Task);
9026 if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) &&
9027 (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) &&
9028 (!ps->ps_GlobalCfg->pgc_PopupDeviceGone))
9030 startpopo = FALSE; // no need to start popo, no windows wanted
9032 if(startpopo)
9034 struct PsdPoPo *po = &ps->ps_PoPo;
9036 po->po_ReadySignal = SIGB_SINGLE;
9037 po->po_ReadySigTask = FindTask(NULL);
9038 SetSignal(0, SIGF_SINGLE); // clear single bit
9039 if(psdSpawnSubTask("PoPo (Poseidon Popups)", pPoPoGUITask, ps))
9041 Wait(1UL<<po->po_ReadySignal);
9043 po->po_ReadySigTask = NULL;
9044 //FreeSignal(po->po_ReadySignal);
9045 if(po->po_Task)
9047 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "PoPo kicks ass.");
9050 if((cfgchanged + 2) == counter)
9052 KPRINTF(10, ("Sending information about config changed to all classes.\n"));
9053 /* Inform all classes */
9054 psdLockReadPBase();
9055 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
9056 while(puc->puc_Node.ln_Succ)
9058 usbDoMethod(UCM_ConfigChangedEvent);
9059 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
9061 psdUnlockPBase();
9062 cfgchanged = 0;
9064 // power saving stuff, check every second
9065 if((counter & 1) && ps->ps_GlobalCfg->pgc_PowerSaving)
9067 struct PsdDevice *pd = NULL;
9068 struct PsdInterface *pif;
9069 GetSysTime((APTR) &currtime);
9070 while((pd = psdGetNextDevice(pd)))
9072 if((pd->pd_DevClass != HUB_CLASSCODE) &&
9073 ((pd->pd_Flags & (PDFF_CONFIGURED|PDFF_DEAD|PDFF_SUSPENDED|PDFF_APPBINDING|PDFF_DELEXPUNGE)) == PDFF_CONFIGURED))
9075 if(pd->pd_LastActivity.tv_secs && ((currtime.tv_secs - pd->pd_LastActivity.tv_secs) > ps->ps_GlobalCfg->pgc_SuspendTimeout))
9077 BOOL doit = TRUE;
9078 IPTR suspendable;
9079 if(!((pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP) && ps->ps_GlobalCfg->pgc_ForceSuspend))
9081 if(pd->pd_DevBinding && ((puc = pd->pd_ClsBinding)))
9083 suspendable = 0;
9084 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9085 if(!suspendable)
9087 doit = FALSE;
9090 pif = (struct PsdInterface *) pd->pd_CurrentConfig->pc_Interfaces.lh_Head;
9091 while(pif->pif_Node.ln_Succ)
9093 if(pif->pif_IfBinding && ((puc = pif->pif_ClsBinding)))
9095 suspendable = 0;
9096 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9097 if(!suspendable)
9099 doit = FALSE;
9100 break;
9103 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
9106 if(doit)
9108 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Suspending '%s'.", pd->pd_ProductStr);
9109 psdSuspendDevice(pd);
9111 pd->pd_LastActivity.tv_secs = 0;
9117 sigs = Wait(sigmask);
9118 } while(!(sigs & SIGBREAKF_CTRL_C));
9119 psdRemEventHandler(ph->ph_EventHandler);
9120 ph->ph_EventHandler = NULL;
9121 AbortIO(&ph->ph_TimerIOReq->tr_node);
9122 WaitIO(&ph->ph_TimerIOReq->tr_node);
9124 CloseDevice((struct IORequest *) ph->ph_TimerIOReq);
9126 DeleteIORequest((struct IORequest *) ph->ph_TimerIOReq);
9128 DeleteMsgPort(ph->ph_TimerMsgPort);
9130 DeleteMsgPort(ph->ph_MsgPort);
9131 ph->ph_MsgPort = NULL;
9133 Forbid();
9134 ph->ph_Task = NULL;
9135 if(ph->ph_ReadySigTask)
9137 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9139 AROS_USERFUNC_EXIT
9141 /* \\\ */
9143 /*****************************************************************/
9145 /* /// "Packtables for psdGetAttrs() and psdSetAttrs() " */
9146 /* Pack table for PsdBase */
9147 static const ULONG PsdBasePT[] =
9149 PACK_STARTTABLE(PA_Dummy),
9150 PACK_ENTRY(PA_Dummy, PA_ConfigRead, PsdBase, ps_ConfigRead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9151 PACK_ENTRY(PA_Dummy, PA_GlobalConfig, PsdBase, ps_GlobalCfg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9152 PACK_ENTRY(PA_Dummy, PA_MemPoolUsage, PsdBase, ps_MemAllocated, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9153 PACK_ENTRY(PA_Dummy, PA_CurrConfigHash, PsdBase, ps_ConfigHash, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9154 PACK_ENTRY(PA_Dummy, PA_SavedConfigHash, PsdBase, ps_SavedConfigHash, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9155 PACK_ENTRY(PA_Dummy, PA_ReleaseVersion, PsdBase, ps_ReleaseVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9156 PACK_ENTRY(PA_Dummy, PA_OSVersion, PsdBase, ps_OSVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9157 PACK_ENDTABLE
9160 /* Pack table for PsdErrorMsg */
9161 static const ULONG PsdErrorMsgPT[] =
9163 PACK_STARTTABLE(EMA_Dummy),
9164 PACK_ENTRY(EMA_Dummy, EMA_Level, PsdErrorMsg, pem_Level, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9165 PACK_ENTRY(EMA_Dummy, EMA_Origin, PsdErrorMsg, pem_Origin, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9166 PACK_ENTRY(EMA_Dummy, EMA_Msg, PsdErrorMsg, pem_Msg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9167 PACK_ENDTABLE
9170 /* Pack table for PsdUsbClass */
9171 static const ULONG PsdUsbClassPT[] =
9173 PACK_STARTTABLE(UCA_Dummy),
9174 PACK_ENTRY(UCA_Dummy, UCA_ClassBase, PsdUsbClass, puc_ClassBase, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9175 PACK_ENTRY(UCA_Dummy, UCA_ClassName, PsdUsbClass, puc_ClassName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9176 PACK_ENTRY(UCA_Dummy, UCA_FullPath, PsdUsbClass, puc_FullPath, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9177 PACK_ENTRY(UCA_Dummy, UCA_UseCount, PsdUsbClass, puc_UseCnt, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9178 PACK_ENDTABLE
9181 /* Pack table for PsdHardware */
9182 static const ULONG PsdHardwarePT[] =
9184 PACK_STARTTABLE(HA_Dummy),
9185 PACK_ENTRY(HA_Dummy, HA_DeviceName, PsdHardware, phw_DevName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9186 PACK_ENTRY(HA_Dummy, HA_DeviceUnit, PsdHardware, phw_Unit, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9187 PACK_ENTRY(HA_Dummy, HA_ProductName, PsdHardware, phw_ProductName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9188 PACK_ENTRY(HA_Dummy, HA_Manufacturer, PsdHardware, phw_Manufacturer, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9189 PACK_ENTRY(HA_Dummy, HA_Description, PsdHardware, phw_Description, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9190 PACK_ENTRY(HA_Dummy, HA_Copyright, PsdHardware, phw_Copyright, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9191 PACK_ENTRY(HA_Dummy, HA_Version, PsdHardware, phw_Version, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9192 PACK_ENTRY(HA_Dummy, HA_Revision, PsdHardware, phw_Revision, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9193 PACK_ENTRY(HA_Dummy, HA_DriverVersion, PsdHardware, phw_DriverVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9194 PACK_ENDTABLE
9197 /* Pack table for PsdDevice */
9198 static const ULONG PsdDevicePT[] =
9200 PACK_STARTTABLE(DA_Dummy),
9201 PACK_ENTRY(DA_Dummy, DA_Address, PsdDevice, pd_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9202 PACK_ENTRY(DA_Dummy, DA_NumConfigs, PsdDevice, pd_NumCfgs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9203 PACK_ENTRY(DA_Dummy, DA_CurrConfig, PsdDevice, pd_CurrCfg, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9204 PACK_ENTRY(DA_Dummy, DA_Config, PsdDevice, pd_CurrentConfig, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9205 PACK_ENTRY(DA_Dummy, DA_HubDevice, PsdDevice, pd_Hub, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9206 PACK_ENTRY(DA_Dummy, DA_UsbVersion, PsdDevice, pd_USBVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9207 PACK_ENTRY(DA_Dummy, DA_Class, PsdDevice, pd_DevClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9208 PACK_ENTRY(DA_Dummy, DA_SubClass, PsdDevice, pd_DevSubClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9209 PACK_ENTRY(DA_Dummy, DA_Protocol, PsdDevice, pd_DevProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9210 PACK_ENTRY(DA_Dummy, DA_VendorID, PsdDevice, pd_VendorID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9211 PACK_ENTRY(DA_Dummy, DA_MaxPktSize0, PsdDevice, pd_MaxPktSize0, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9212 PACK_ENTRY(DA_Dummy, DA_ProductID, PsdDevice, pd_ProductID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9213 PACK_ENTRY(DA_Dummy, DA_Version, PsdDevice, pd_DevVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9214 PACK_ENTRY(DA_Dummy, DA_Manufacturer, PsdDevice, pd_MnfctrStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9215 PACK_ENTRY(DA_Dummy, DA_ProductName, PsdDevice, pd_ProductStr, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9216 PACK_ENTRY(DA_Dummy, DA_OrigProductName, PsdDevice, pd_OldProductStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9217 PACK_ENTRY(DA_Dummy, DA_SerialNumber, PsdDevice, pd_SerNumStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9218 PACK_ENTRY(DA_Dummy, DA_Hardware, PsdDevice, pd_Hardware, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9219 PACK_ENTRY(DA_Dummy, DA_Binding, PsdDevice, pd_DevBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9220 PACK_ENTRY(DA_Dummy, DA_BindingClass, PsdDevice, pd_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9221 PACK_ENTRY(DA_Dummy, DA_LangIDArray, PsdDevice, pd_LangIDArray, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9222 PACK_ENTRY(DA_Dummy, DA_CurrLangID, PsdDevice, pd_CurrLangID, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9223 PACK_ENTRY(DA_Dummy, DA_IDString, PsdDevice, pd_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9224 PACK_ENTRY(DA_Dummy, DA_CloneCount, PsdDevice, pd_CloneCount, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9225 PACK_ENTRY(DA_Dummy, DA_AtHubPortNumber, PsdDevice, pd_HubPort, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9226 PACK_ENTRY(DA_Dummy, DA_PowerDrained, PsdDevice, pd_PowerDrain, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9227 PACK_ENTRY(DA_Dummy, DA_PowerSupply, PsdDevice, pd_PowerSupply, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9228 PACK_ENTRY(DA_Dummy, DA_IsNewToMe, PsdDevice, pd_IsNewToMe, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9229 PACK_ENTRY(DA_Dummy, DA_InhibitPopup, PsdDevice, pd_PoPoCfg.poc_InhibitPopup, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9230 PACK_ENTRY(DA_Dummy, DA_InhibitClassBind, PsdDevice, pd_PoPoCfg.poc_NoClassBind, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9231 PACK_ENTRY(DA_Dummy, DA_OverridePowerInfo, PsdDevice, pd_PoPoCfg.poc_OverridePowerInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9232 PACK_ENTRY(DA_Dummy, DA_HubThinkTime, PsdDevice, pd_HubThinkTime, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9233 PACK_WORDBIT(DA_Dummy, DA_IsLowspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_LOWSPEED),
9234 PACK_WORDBIT(DA_Dummy, DA_IsHighspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HIGHSPEED),
9235 PACK_WORDBIT(DA_Dummy, DA_IsConnected, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONNECTED),
9236 PACK_WORDBIT(DA_Dummy, DA_HasAddress, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVADDR),
9237 PACK_WORDBIT(DA_Dummy, DA_HasDevDesc, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVDESC),
9238 PACK_WORDBIT(DA_Dummy, DA_IsConfigured, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONFIGURED),
9239 PACK_WORDBIT(DA_Dummy, DA_IsDead, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_DEAD),
9240 PACK_WORDBIT(DA_Dummy, DA_IsSuspended, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUSPENDED),
9241 PACK_WORDBIT(DA_Dummy, DA_HasAppBinding, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_APPBINDING),
9242 PACK_WORDBIT(DA_Dummy, DA_NeedsSplitTrans, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_NEEDSSPLIT),
9243 PACK_WORDBIT(DA_Dummy, DA_LowPower, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_LOWPOWER),
9244 #ifdef AROS_USB30_CODE
9245 PACK_WORDBIT(DA_Dummy, DA_IsSuperspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUPERSPEED),
9246 #endif
9247 PACK_ENDTABLE
9250 /* Pack table for PsdConfig */
9251 static const ULONG PsdConfigPT[] =
9253 PACK_STARTTABLE(CA_Dummy),
9254 PACK_ENTRY(CA_Dummy, CA_ConfigNum, PsdConfig, pc_CfgNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9255 PACK_ENTRY(CA_Dummy, CA_MaxPower, PsdConfig, pc_MaxPower, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9256 PACK_ENTRY(CA_Dummy, CA_ConfigName, PsdConfig, pc_CfgStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9257 PACK_ENTRY(CA_Dummy, CA_NumInterfaces, PsdConfig, pc_NumIfs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9258 PACK_ENTRY(CA_Dummy, CA_Attrs, PsdConfig, pc_Attr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9259 PACK_ENTRY(CA_Dummy, CA_Device, PsdConfig, pc_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9260 PACK_WORDBIT(CA_Dummy, CA_SelfPowered, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_PACKUNPACK, USCAF_SELF_POWERED),
9261 PACK_WORDBIT(CA_Dummy, CA_RemoteWakeup, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_UNPACKONLY, USCAF_REMOTE_WAKEUP),
9262 PACK_ENDTABLE
9265 /* Pack table for PsdDescriptor */
9266 static const ULONG PsdDescriptorPT[] =
9268 PACK_STARTTABLE(DDA_Dummy),
9269 PACK_ENTRY(DDA_Dummy, DDA_Device, PsdDescriptor, pdd_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9270 PACK_ENTRY(DDA_Dummy, DDA_Config, PsdDescriptor, pdd_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9271 PACK_ENTRY(DDA_Dummy, DDA_Interface, PsdDescriptor, pdd_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9272 PACK_ENTRY(DDA_Dummy, DDA_Endpoint, PsdDescriptor, pdd_Endpoint, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9273 PACK_ENTRY(DDA_Dummy, DDA_Name, PsdDescriptor, pdd_Name, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9274 PACK_ENTRY(DDA_Dummy, DDA_DescriptorType, PsdDescriptor, pdd_Type, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9275 PACK_ENTRY(DDA_Dummy, DDA_CS_SubType, PsdDescriptor, pdd_CSSubType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9276 PACK_ENTRY(DDA_Dummy, DDA_DescriptorData, PsdDescriptor, pdd_Data, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9277 PACK_ENTRY(DDA_Dummy, DDA_DescriptorLength, PsdDescriptor, pdd_Length, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9278 PACK_ENDTABLE
9281 /* Pack table for PsdInterface */
9282 static const ULONG PsdInterfacePT[] =
9284 PACK_STARTTABLE(IFA_Dummy),
9285 PACK_ENTRY(IFA_Dummy, IFA_InterfaceNum, PsdInterface, pif_IfNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9286 PACK_ENTRY(IFA_Dummy, IFA_AlternateNum, PsdInterface, pif_Alternate, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9287 PACK_ENTRY(IFA_Dummy, IFA_NumEndpoints, PsdInterface, pif_NumEPs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9288 PACK_ENTRY(IFA_Dummy, IFA_Class, PsdInterface, pif_IfClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9289 PACK_ENTRY(IFA_Dummy, IFA_SubClass, PsdInterface, pif_IfSubClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9290 PACK_ENTRY(IFA_Dummy, IFA_Protocol, PsdInterface, pif_IfProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9291 PACK_ENTRY(IFA_Dummy, IFA_InterfaceName, PsdInterface, pif_IfStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9292 PACK_ENTRY(IFA_Dummy, IFA_Config, PsdInterface, pif_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9293 PACK_ENTRY(IFA_Dummy, IFA_Binding, PsdInterface, pif_IfBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9294 PACK_ENTRY(IFA_Dummy, IFA_BindingClass, PsdInterface, pif_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9295 PACK_ENTRY(IFA_Dummy, IFA_IDString, PsdInterface, pif_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9296 PACK_ENDTABLE
9299 /* Pack table for PsdEndpoint */
9300 static const ULONG PsdEndpointPT[] =
9302 PACK_STARTTABLE(EA_Dummy),
9303 PACK_ENTRY(EA_Dummy, EA_EndpointNum, PsdEndpoint, pep_EPNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9304 PACK_ENTRY(EA_Dummy, EA_TransferType, PsdEndpoint, pep_TransType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9305 PACK_ENTRY(EA_Dummy, EA_MaxPktSize, PsdEndpoint, pep_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9306 PACK_ENTRY(EA_Dummy, EA_Interval, PsdEndpoint, pep_Interval, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9307 PACK_ENTRY(EA_Dummy, EA_NumTransMuFrame, PsdEndpoint, pep_NumTransMuFr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9308 PACK_ENTRY(EA_Dummy, EA_SyncType, PsdEndpoint, pep_SyncType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9309 PACK_ENTRY(EA_Dummy, EA_UsageType, PsdEndpoint, pep_UsageType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9310 PACK_ENTRY(EA_Dummy, EA_Interface, PsdEndpoint, pep_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9311 PACK_WORDBIT(EA_Dummy, EA_IsIn, PsdEndpoint, pep_Direction, PKCTRL_BIT|PKCTRL_UNPACKONLY, 1),
9312 PACK_ENDTABLE
9315 /* Pack table for PsdPipe */
9316 static const ULONG PsdPipePT[] =
9318 PACK_STARTTABLE(PPA_Dummy),
9319 PACK_ENTRY(PPA_Dummy, PPA_Endpoint, PsdPipe, pp_Endpoint, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9320 PACK_ENTRY(PPA_Dummy, PPA_Error, PsdPipe, pp_IOReq.iouh_Req.io_Error, PKCTRL_BYTE|PKCTRL_UNPACKONLY),
9321 PACK_ENTRY(PPA_Dummy, PPA_Actual, PsdPipe, pp_IOReq.iouh_Actual, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9322 PACK_ENTRY(PPA_Dummy, PPA_EndpointNum, PsdPipe, pp_IOReq.iouh_Endpoint, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9323 PACK_ENTRY(PPA_Dummy, PPA_DeviceAddress, PsdPipe, pp_IOReq.iouh_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9324 PACK_ENTRY(PPA_Dummy, PPA_MaxPktSize, PsdPipe, pp_IOReq.iouh_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9325 PACK_ENTRY(PPA_Dummy, PPA_NakTimeoutTime, PsdPipe, pp_IOReq.iouh_NakTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9326 PACK_ENTRY(PPA_Dummy, PPA_Interval, PsdPipe, pp_IOReq.iouh_Interval, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9327 PACK_WORDBIT(PPA_Dummy, PPA_NoShortPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NOSHORTPKT),
9328 PACK_WORDBIT(PPA_Dummy, PPA_NakTimeout, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NAKTIMEOUT),
9329 PACK_WORDBIT(PPA_Dummy, PPA_AllowRuntPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_ALLOWRUNTPKTS),
9330 PACK_ENDTABLE
9333 /* Pack table for PsdAppBinding */
9334 static const ULONG PsdAppBindingPT[] =
9336 PACK_STARTTABLE(ABA_Dummy),
9337 PACK_ENTRY(ABA_Dummy, ABA_ReleaseHook, PsdAppBinding, pab_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9338 PACK_ENTRY(ABA_Dummy, ABA_Device, PsdAppBinding, pab_Device, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9339 PACK_ENTRY(ABA_Dummy, ABA_UserData, PsdAppBinding, pab_UserData, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9340 PACK_ENTRY(ABA_Dummy, ABA_Task, PsdAppBinding, pab_Task, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9341 PACK_ENTRY(ABA_Dummy, ABA_ForceRelease, PsdAppBinding, pab_ForceRelease, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9342 PACK_ENDTABLE
9345 /* Pack table for PsdAppBinding */
9346 static const ULONG PsdEventNotePT[] =
9348 PACK_STARTTABLE(ENA_Dummy),
9349 PACK_ENTRY(ENA_Dummy, ENA_EventID, PsdEventNote, pen_Event, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9350 PACK_ENTRY(ENA_Dummy, ENA_Param1, PsdEventNote, pen_Param1, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9351 PACK_ENTRY(ENA_Dummy, ENA_Param2, PsdEventNote, pen_Param2, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9352 PACK_ENDTABLE
9355 /* Pack table for PsdGlobalCfg */
9356 static const ULONG PsdGlobalCfgPT[] =
9358 PACK_STARTTABLE(GCA_Dummy),
9359 PACK_ENTRY(GCA_Dummy, GCA_LogInfo, PsdGlobalCfg, pgc_LogInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9360 PACK_ENTRY(GCA_Dummy, GCA_LogWarning, PsdGlobalCfg, pgc_LogWarning, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9361 PACK_ENTRY(GCA_Dummy, GCA_LogError, PsdGlobalCfg, pgc_LogError, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9362 PACK_ENTRY(GCA_Dummy, GCA_LogFailure, PsdGlobalCfg, pgc_LogFailure, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9363 PACK_ENTRY(GCA_Dummy, GCA_BootDelay, PsdGlobalCfg, pgc_BootDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9364 PACK_ENTRY(GCA_Dummy, GCA_SubTaskPri, PsdGlobalCfg, pgc_SubTaskPri, PKCTRL_WORD|PKCTRL_PACKUNPACK),
9365 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceNew, PsdGlobalCfg, pgc_PopupDeviceNew, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9366 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceGone, PsdGlobalCfg, pgc_PopupDeviceGone, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9367 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceDeath, PsdGlobalCfg, pgc_PopupDeviceDeath, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9368 PACK_ENTRY(GCA_Dummy, GCA_PopupCloseDelay, PsdGlobalCfg, pgc_PopupCloseDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9369 PACK_ENTRY(GCA_Dummy, GCA_PopupActivateWin, PsdGlobalCfg, pgc_PopupActivateWin, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9370 PACK_ENTRY(GCA_Dummy, GCA_PopupWinToFront, PsdGlobalCfg, pgc_PopupWinToFront, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9371 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableLP, PsdGlobalCfg, pgc_AutoDisableLP, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9372 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableDead, PsdGlobalCfg, pgc_AutoDisableDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9373 PACK_ENTRY(GCA_Dummy, GCA_AutoRestartDead, PsdGlobalCfg, pgc_AutoRestartDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9374 PACK_ENTRY(GCA_Dummy, GCA_PowerSaving, PsdGlobalCfg, pgc_PowerSaving, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9375 PACK_ENTRY(GCA_Dummy, GCA_ForceSuspend, PsdGlobalCfg, pgc_ForceSuspend, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9376 PACK_ENTRY(GCA_Dummy, GCA_SuspendTimeout, PsdGlobalCfg, pgc_SuspendTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9377 PACK_ENTRY(GCA_Dummy, GCA_PrefsVersion, PsdGlobalCfg, pgc_PrefsVersion, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9378 PACK_ENDTABLE
9381 /* Pack table for PsdPipeStream */
9382 static const ULONG PsdPipeStreamPT[] =
9384 PACK_STARTTABLE(PSA_Dummy),
9385 PACK_ENTRY(PSA_Dummy, PSA_MessagePort, PsdPipeStream, pps_MsgPort, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9386 PACK_ENTRY(PSA_Dummy, PSA_NumPipes, PsdPipeStream, pps_NumPipes, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9387 PACK_ENTRY(PSA_Dummy, PSA_BufferSize, PsdPipeStream, pps_BufferSize, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9388 PACK_ENTRY(PSA_Dummy, PSA_NakTimeoutTime, PsdPipeStream, pps_NakTimeoutTime, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9389 PACK_ENTRY(PSA_Dummy, PSA_BytesPending, PsdPipeStream, pps_BytesPending, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9390 PACK_ENTRY(PSA_Dummy, PSA_Error, PsdPipeStream, pps_Error, PKCTRL_LONG|PKCTRL_PACKUNPACK),
9391 PACK_ENTRY(PSA_Dummy, PSA_TermArray, PsdPipeStream, pps_TermArray, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9392 PACK_ENTRY(PSA_Dummy, PSA_AbortSigMask, PsdPipeStream, pps_AbortSigMask, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9393 PACK_ENTRY(PSA_Dummy, PSA_ActivePipe, PsdPipeStream, pps_ActivePipe, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9394 PACK_WORDBIT(PSA_Dummy, PSA_AsyncIO, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ASYNCIO),
9395 PACK_WORDBIT(PSA_Dummy, PSA_ShortPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_SHORTTERM),
9396 PACK_WORDBIT(PSA_Dummy, PSA_ReadAhead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_READAHEAD),
9397 PACK_WORDBIT(PSA_Dummy, PSA_BufferedRead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERREAD),
9398 PACK_WORDBIT(PSA_Dummy, PSA_BufferedWrite, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERWRITE),
9399 PACK_WORDBIT(PSA_Dummy, PSA_NoZeroPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NOSHORTPKT),
9400 PACK_WORDBIT(PSA_Dummy, PSA_NakTimeout, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NAKTIMEOUT),
9401 PACK_WORDBIT(PSA_Dummy, PSA_AllowRuntPackets, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ALLOWRUNT),
9402 PACK_WORDBIT(PSA_Dummy, PSA_DoNotWait, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_DONOTWAIT),
9403 PACK_ENDTABLE
9406 /* Pack table for PsdRTIsoHandler */
9407 static const ULONG PsdRTIsoHandlerPT[] =
9409 PACK_STARTTABLE(RTA_Dummy),
9410 PACK_ENTRY(RTA_Dummy, RTA_InRequestHook, PsdRTIsoHandler, prt_RTIso.urti_InReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9411 PACK_ENTRY(RTA_Dummy, RTA_OutRequestHook, PsdRTIsoHandler, prt_RTIso.urti_OutReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9412 PACK_ENTRY(RTA_Dummy, RTA_InDoneHook, PsdRTIsoHandler, prt_RTIso.urti_InDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9413 PACK_ENTRY(RTA_Dummy, RTA_OutDoneHook, PsdRTIsoHandler, prt_RTIso.urti_OutDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9414 PACK_ENTRY(RTA_Dummy, RTA_ReleaseHook, PsdRTIsoHandler, prt_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9415 PACK_ENTRY(RTA_Dummy, RTA_OutPrefetchSize, PsdRTIsoHandler, prt_RTIso.urti_OutPrefetch, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9416 PACK_ENDTABLE
9419 /* PGA assignment table */
9420 static const ULONG *PsdPTArray[] =
9422 NULL,
9423 PsdBasePT,
9424 PsdUsbClassPT,
9425 PsdHardwarePT,
9426 PsdDevicePT,
9427 PsdConfigPT,
9428 PsdInterfacePT,
9429 PsdEndpointPT,
9430 PsdErrorMsgPT,
9431 PsdPipePT,
9432 PsdAppBindingPT,
9433 PsdEventNotePT,
9434 PsdGlobalCfgPT,
9435 PsdPipeStreamPT,
9436 PsdDescriptorPT,
9437 PsdRTIsoHandlerPT
9439 /* \\\ */