Removed so that we can do the vendor copy again.
[AROS.git] / rom / usb / poseidon / poseidon.library.c
blob27cc07093d29f61e6ee7c5b834700e400775caad
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
2864 struct PsdDevice *pd = pp->pp_Device;
2865 struct PsdDevice *itpd = pp->pp_Device;
2866 struct PsdConfig *pc;
2867 struct PsdInterface *pif;
2868 struct UsbStdDevDesc usdd;
2870 UWORD oldflags;
2871 ULONG oldnaktimeout;
2873 LONG ioerr;
2875 STRPTR classname;
2876 STRPTR vendorname;
2878 ULONG devclass;
2880 BOOL hasprodname;
2881 BOOL haspopupinhibit;
2883 UWORD cfgnum;
2885 struct PsdIFFContext *pic;
2887 ULONG *chnk;
2888 UBYTE dummybuf[8];
2890 #ifdef AROS_USB30_CODE
2891 struct UsbStdBOSDesc usbosd;
2892 LONG ioerr_bos;
2893 #endif
2895 KPRINTF(2, ("psdEnumerateDevice(%p)\n", pp));
2897 #ifdef AROS_USB2OTG_CODE
2898 struct PsdHardware *phw = pp->pp_Device->pd_Hardware;
2900 if( !(phw->phw_Capabilities & UHCF_USB2OTG) ) {
2902 Driver informs us that it is not USB2OTG device
2903 - Follow regular code path
2905 } else {
2907 Driver informs us that it is USB2OTG device
2908 - Follow USB2OTG code path
2911 #endif
2913 psdLockWriteDevice(pd);
2914 if(pAllocDevAddr(pd)) {
2916 oldflags = pp->pp_IOReq.iouh_Flags;
2917 oldnaktimeout = pp->pp_IOReq.iouh_NakTimeout;
2918 pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
2919 pp->pp_IOReq.iouh_NakTimeout = 1000;
2920 pp->pp_IOReq.iouh_DevAddr = 0;
2922 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2923 ioerr = psdDoPipe(pp, dummybuf, 8);
2924 if(ioerr && (ioerr != UHIOERR_RUNTPACKET)) {
2925 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "GET_DESCRIPTOR (len %ld) failed: %s (%ld)", 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
2926 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
2929 KPRINTF(1, ("Setting DevAddr %ld...\n", pd->pd_DevAddr));
2930 psdPipeSetup(pp, URTF_STANDARD|URTF_DEVICE, USR_SET_ADDRESS, pd->pd_DevAddr, 0);
2931 ioerr = psdDoPipe(pp, NULL, 0);
2933 This is tricky: Maybe the device has accepted the command,
2934 but failed to send an ACK. Now, every resend trial will
2935 go to the wrong address!
2937 if((ioerr == UHIOERR_TIMEOUT) || (ioerr == UHIOERR_STALL)) {
2938 KPRINTF(1, ("First attempt failed, retrying new address\n"));
2939 /*pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;*/
2940 psdDelayMS(250);
2941 ioerr = psdDoPipe(pp, NULL, 0);
2942 /*pp->pp_IOReq.iouh_DevAddr = 0;*/
2945 if(!ioerr) {
2946 pd->pd_Flags |= PDFF_HASDEVADDR|PDFF_CONNECTED;
2947 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
2949 psdDelayMS(50); /* Allowed time to settle */
2951 KPRINTF(1, ("Getting MaxPktSize0...\n"));
2952 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_DEVICE<<8, 0);
2953 ioerr = psdDoPipe(pp, &usdd, 8);
2954 if(!ioerr) {
2955 switch(usdd.bMaxPacketSize0)
2957 case 8:
2958 case 16:
2959 case 32:
2960 case 64:
2961 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = usdd.bMaxPacketSize0;
2962 break;
2963 #ifdef AROS_USB30_CODE
2964 case 9:
2965 if((AROS_LE2WORD(usdd.bcdUSB) >= 0x0300)) {
2966 /* 9 is the only valid value for superspeed mode and it is the exponent of 2 =512 bytes */
2967 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = (1<<9);
2968 break;
2970 #endif
2971 default:
2972 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Illegal MaxPktSize0=%ld for endpoint 0", (ULONG) usdd.bMaxPacketSize0);
2973 KPRINTF(2, ("Illegal MaxPktSize0=%ld!\n", usdd.bMaxPacketSize0));
2974 //pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0 = 8;
2975 ioerr = UHIOERR_CRCERROR;
2976 break;
2980 if(!ioerr)
2982 KPRINTF(1, (" MaxPktSize0 = %ld\n", pd->pd_MaxPktSize0));
2983 KPRINTF(1, ("Getting full descriptor...\n"));
2984 ioerr = psdDoPipe(pp, &usdd, sizeof(struct UsbStdDevDesc));
2985 if(!ioerr)
2987 pAllocDescriptor(pd, (UBYTE *) &usdd);
2988 pd->pd_Flags |= PDFF_HASDEVDESC;
2989 pd->pd_USBVers = AROS_WORD2LE(usdd.bcdUSB);
2990 pd->pd_DevClass = usdd.bDeviceClass;
2991 pd->pd_DevSubClass = usdd.bDeviceSubClass;
2992 pd->pd_DevProto = usdd.bDeviceProtocol;
2993 pd->pd_VendorID = AROS_WORD2LE(usdd.idVendor);
2994 pd->pd_ProductID = AROS_WORD2LE(usdd.idProduct);
2995 pd->pd_DevVers = AROS_WORD2LE(usdd.bcdDevice);
2996 vendorname = psdNumToStr(NTS_VENDORID, (LONG) pd->pd_VendorID, NULL);
2998 // patch to early determine highspeed roothubs
2999 if((!pd->pd_Hub) && (pd->pd_USBVers >= 0x200) && (pd->pd_USBVers < 0x300)) {
3000 pd->pd_Flags |= PDFF_HIGHSPEED;
3003 #ifdef AROS_USB30_CODE
3004 if(((!pd->pd_Hub) && pd->pd_USBVers >= 0x300)) {
3005 pd->pd_Flags |= PDFF_SUPERSPEED;
3009 The USB 3.0 and USB 2.0 LPM specifications define a new USB descriptor called the Binary Device Object Store (BOS)
3010 for a USB device, which reports a bcdUSB value greater than 0x0200 in their device descriptor
3012 if((pd->pd_USBVers > 0x200)) {
3013 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_BOS<<8, 0);
3014 ioerr_bos = psdDoPipe(pp, &usbosd, sizeof(struct UsbStdBOSDesc));
3015 if(!ioerr_bos) {
3016 XPRINTF(1, ("BOS descriptor received...\n"));
3019 BOS descriptor bLength = sizeof(struct UsbStdBOSDesc)
3020 BOS descriptor bNumDeviceCaps != 0
3021 BOS descriptor wTotalLength >= bLength + (bNumDeviceCaps * sizeof(protocol specific capability descriptor))
3023 if(usbosd.bLength != sizeof(struct UsbStdBOSDesc)) {
3024 XPRINTF(1, ("Invalid BOS descriptor bLength!\n"));
3027 if(usbosd.bNumDeviceCaps == 0) {
3028 XPRINTF(1, ("Invalid BOS descriptor bNumDeviceCaps!\n"));
3029 }else if(usbosd.wTotalLength < (usbosd.bLength + (usbosd.bNumDeviceCaps * 2))) {
3030 XPRINTF(1, ("Invalid BOS descriptor wTotalLength!\n"));
3033 } else {
3034 XPRINTF(1, ("GET_DESCRIPTOR (5) failed %ld!\n", ioerr_bos));
3037 #endif
3039 if(usdd.iManufacturer) {
3040 pd->pd_MnfctrStr = psdGetStringDescriptor(pp, usdd.iManufacturer);
3043 if(usdd.iProduct) {
3044 pd->pd_ProductStr = psdGetStringDescriptor(pp, usdd.iProduct);
3047 if(usdd.iSerialNumber) {
3048 pd->pd_SerNumStr = psdGetStringDescriptor(pp, usdd.iSerialNumber);
3051 if(!pd->pd_MnfctrStr) {
3052 pd->pd_MnfctrStr = psdCopyStr(vendorname ? vendorname : (STRPTR) "n/a");
3055 if(!pd->pd_ProductStr) {
3056 hasprodname = FALSE;
3057 classname = psdNumToStr(NTS_CLASSCODE, (LONG) pd->pd_DevClass, NULL);
3058 if(classname) {
3059 pd->pd_ProductStr = psdCopyStrFmt("%s: Vdr=%04lx/PID=%04lx", classname, pd->pd_VendorID, pd->pd_ProductID);
3060 } else {
3061 pd->pd_ProductStr = psdCopyStrFmt("Cls=%ld/Vdr=%04lx/PID=%04lx", pd->pd_DevClass, pd->pd_VendorID, pd->pd_ProductID);
3063 } else {
3064 hasprodname = TRUE;
3067 if(!pd->pd_SerNumStr) {
3068 pd->pd_SerNumStr = psdCopyStr("n/a");
3071 KPRINTF(2, ("Product : %s\n"
3072 "Manufacturer: %s\n"
3073 "SerialNumber: %s\n",
3074 pd->pd_ProductStr, pd->pd_MnfctrStr, pd->pd_SerNumStr));
3075 KPRINTF(2, ("USBVersion: %04lx\n"
3076 "Class : %ld\n"
3077 "SubClass : %ld\n"
3078 "DevProto : %ld\n"
3079 "VendorID : %ld\n"
3080 "ProductID : %ld\n"
3081 "DevVers : %04lx\n",
3082 pd->pd_USBVers, pd->pd_DevClass, pd->pd_DevSubClass, pd->pd_DevProto,
3083 pd->pd_VendorID, pd->pd_ProductID, pd->pd_DevVers));
3085 /* check for clones */
3086 itpd = NULL;
3087 while((itpd = psdGetNextDevice(itpd)))
3089 if(itpd != pd)
3091 if((itpd->pd_ProductID == pd->pd_ProductID) &&
3092 (itpd->pd_VendorID == pd->pd_VendorID) &&
3093 (!strcmp(itpd->pd_SerNumStr, pd->pd_SerNumStr)) &&
3094 (itpd->pd_CloneCount == pd->pd_CloneCount))
3096 pd->pd_CloneCount++;
3097 itpd = NULL;
3102 pd->pd_IDString = psdCopyStrFmt("%s-%04lx-%04lx-%s-%02lx", pd->pd_ProductStr, pd->pd_VendorID, pd->pd_ProductID, pd->pd_SerNumStr, pd->pd_CloneCount);
3104 pStripString(ps, pd->pd_MnfctrStr);
3105 pStripString(ps, pd->pd_ProductStr);
3106 pStripString(ps, pd->pd_SerNumStr);
3108 /* get custom name of device */
3109 pLockSemExcl(ps, &ps->ps_ConfigLock); // Exclusive lock to avoid deadlock situation when promoting read to write
3110 pd->pd_OldProductStr = pd->pd_ProductStr;
3111 pd->pd_ProductStr = NULL;
3112 haspopupinhibit = FALSE;
3113 pic = psdGetUsbDevCfg("Trident", pd->pd_IDString, NULL);
3114 if(pic)
3116 pd->pd_IsNewToMe = FALSE;
3117 if((pd->pd_ProductStr = pGetStringChunk(ps, pic, IFFCHNK_NAME)))
3119 hasprodname = TRUE;
3121 if((chnk = pFindCfgChunk(ps, pic, IFFCHNK_POPUP)))
3123 struct PsdPoPoCfg *poc = (struct PsdPoPoCfg *) chnk;
3124 CopyMem(((UBYTE *) poc) + 8, ((UBYTE *) &pd->pd_PoPoCfg) + 8, min(AROS_LONG2BE(poc->poc_Length), AROS_LONG2BE(pd->pd_PoPoCfg.poc_Length)));
3125 haspopupinhibit = TRUE;
3127 } else {
3128 pd->pd_IsNewToMe = TRUE;
3129 psdSetUsbDevCfg("Trident", pd->pd_IDString, NULL, NULL);
3131 if(!pd->pd_ProductStr)
3133 pd->pd_ProductStr = psdCopyStr(pd->pd_OldProductStr);
3135 if(!haspopupinhibit)
3137 if(pd->pd_DevClass == HUB_CLASSCODE) // hubs default to true
3139 pd->pd_PoPoCfg.poc_InhibitPopup = TRUE;
3142 pUnlockSem(ps, &ps->ps_ConfigLock);
3144 pd->pd_NumCfgs = usdd.bNumConfigurations;
3145 KPRINTF(10, ("Device has %ld different configurations\n", pd->pd_NumCfgs));
3147 if(pGetDevConfig(pp))
3149 cfgnum = 1;
3150 if(pd->pd_Configs.lh_Head->ln_Succ)
3152 cfgnum = ((struct PsdConfig *) pd->pd_Configs.lh_Head)->pc_CfgNum;
3154 psdSetDeviceConfig(pp, cfgnum); /* *** FIXME *** Workaround for USB2.0 devices */
3156 if(!hasprodname)
3158 devclass = pd->pd_DevClass;
3159 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
3160 while(pc->pc_Node.ln_Succ)
3162 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3163 while(pif->pif_Node.ln_Succ)
3165 if(pif->pif_IfClass)
3167 if(!devclass)
3169 devclass = pif->pif_IfClass;
3170 } else {
3171 if(devclass != pif->pif_IfClass)
3173 devclass = 0;
3174 break;
3178 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3180 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
3182 if(devclass)
3184 classname = psdNumToStr(NTS_CLASSCODE, (LONG) devclass, NULL);
3185 if(classname)
3187 psdFreeVec(pd->pd_ProductStr);
3188 if(vendorname)
3190 pd->pd_ProductStr = psdCopyStrFmt("%s (%s/%04lx)",
3191 classname, vendorname, pd->pd_ProductID);
3192 } else {
3193 pd->pd_ProductStr = psdCopyStrFmt("%s (%04lx/%04lx)",
3194 classname, pd->pd_VendorID, pd->pd_ProductID);
3199 pFixBrokenConfig(pp);
3200 pp->pp_IOReq.iouh_Flags = oldflags;
3201 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3202 psdUnlockDevice(pd);
3203 psdCalculatePower(pd->pd_Hardware);
3204 return(pd);
3205 } /*else {
3206 KPRINTF(15, ("SetDeviceConfig(1) failed\n"));
3208 } else {
3209 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3210 "Could not acquire device configuration for %s",
3211 pd->pd_ProductStr ? pd->pd_ProductStr : (STRPTR) "new device");
3212 KPRINTF(15, ("GetDevConfig() failed\n"));
3214 /* Although the device failed to configure fully, maybe
3215 some firmware will able to use this device anyway? */
3216 pp->pp_IOReq.iouh_Flags = oldflags;
3217 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3219 psdUnlockDevice(pd);
3220 return(pd);
3221 } else {
3222 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3223 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
3224 18, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3225 KPRINTF(15, ("GET_DESCRIPTOR (18) failed %ld!\n", ioerr));
3227 } else {
3228 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3229 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
3230 8, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3231 KPRINTF(15, ("GET_DESCRIPTOR (8) failed %ld!\n", ioerr));
3233 } else {
3234 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
3235 "SET_ADDRESS failed: %s (%ld)",
3236 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
3237 KPRINTF(15, ("SET_ADDRESS failed %ld!\n", ioerr));
3240 pp->pp_IOReq.iouh_Flags = oldflags;
3241 pp->pp_IOReq.iouh_NakTimeout = oldnaktimeout;
3242 } else {
3243 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "This cannot happen! More than 127 devices on the bus???");
3244 KPRINTF(20, ("out of addresses???\n"));
3246 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Device enumeration failed, sorry.");
3247 psdUnlockDevice(pd);
3248 return(NULL);
3249 AROS_LIBFUNC_EXIT
3251 /* \\\ */
3253 /* /// "psdGetNextDevice()" */
3254 AROS_LH1(struct PsdDevice *, psdGetNextDevice,
3255 AROS_LHA(struct PsdDevice *, pd, A0),
3256 LIBBASETYPEPTR, ps, 21, psd)
3258 AROS_LIBFUNC_INIT
3259 struct PsdHardware *phw;
3261 KPRINTF(1, ("psdGetNextDevice(%p)\n", pd));
3262 if(pd)
3264 /* Is there another device node in the current hardware? */
3265 if(pd->pd_Node.ln_Succ->ln_Succ)
3267 return((struct PsdDevice *) pd->pd_Node.ln_Succ);
3269 /* No, then check if there's another hardware to scan */
3270 phw = (struct PsdHardware *) pd->pd_Hardware->phw_Node.ln_Succ;
3271 } else {
3272 /* No context, start with first hardware */
3273 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3275 while(phw->phw_Node.ln_Succ)
3277 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3278 /* Is this an valid entry, or is the list empty? */
3279 if(pd->pd_Node.ln_Succ)
3281 return(pd);
3283 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3285 /* End of list reached */
3286 return(NULL);
3287 AROS_LIBFUNC_EXIT
3289 /* \\\ */
3291 /* /// "psdSuspendBindings()" */
3292 AROS_LH1(BOOL, psdSuspendBindings,
3293 AROS_LHA(struct PsdDevice *, pd, A0),
3294 LIBBASETYPEPTR, ps, 100, psd)
3296 AROS_LIBFUNC_INIT
3297 struct PsdUsbClass *puc;
3298 struct PsdConfig *pc;
3299 struct PsdInterface *pif;
3300 BOOL res = FALSE;
3301 IPTR suspendable;
3302 BOOL force = FALSE;
3304 KPRINTF(5, ("psdSuspendBindings(%p)\n", pd));
3305 if(pd)
3307 if(ps->ps_GlobalCfg->pgc_ForceSuspend && (pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP))
3309 force = TRUE;
3311 // ask existing bindings to go to suspend first -- if they don't support it, break off
3312 if(pd->pd_DevBinding)
3314 if(pd->pd_Flags & PDFF_APPBINDING)
3316 if(!force)
3318 // can't suspend application binding devices
3319 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3320 "Cannot suspend with application binding on '%s'.",
3321 pd->pd_ProductStr);
3322 return FALSE;
3324 psdReleaseDevBinding(pd);
3326 if((puc = pd->pd_ClsBinding))
3328 suspendable = 0;
3329 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3330 if(suspendable)
3332 res = usbDoMethod(UCM_AttemptSuspendDevice, pd->pd_DevBinding);
3333 if(!res)
3335 // didn't want to suspend
3336 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3337 "Class '%s' failed to suspend device '%s'.",
3338 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3339 return FALSE;
3341 } else {
3342 if(pd->pd_IOBusyCount)
3344 if(!force)
3346 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3347 "Class '%s' does not support suspending.",
3348 puc->puc_Node.ln_Name);
3349 return FALSE;
3350 } else {
3351 psdReleaseDevBinding(pd);
3353 } else {
3354 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3355 "Class '%s' does not support suspending, but has no active IO. Suspending anyway.",
3356 puc->puc_Node.ln_Name);
3361 pc = pd->pd_CurrentConfig;
3362 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3363 while(pif->pif_Node.ln_Succ)
3365 if(pif->pif_IfBinding)
3367 if((puc = pif->pif_ClsBinding))
3369 suspendable = 0;
3370 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
3371 if(suspendable)
3373 res = usbDoMethod(UCM_AttemptSuspendDevice, pif->pif_IfBinding);
3374 if(!res)
3376 // didn't want to suspend
3377 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3378 "%s failed to suspend device '%s'.",
3379 puc->puc_Node.ln_Name, pd->pd_ProductStr);
3380 return FALSE;
3382 } else {
3383 if(pd->pd_IOBusyCount)
3385 if(!force)
3388 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3389 "%s does not support suspending.",
3390 puc->puc_Node.ln_Name);
3391 return FALSE;
3392 } else {
3393 psdReleaseIfBinding(pif);
3395 } else {
3396 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3397 "%s does not support suspending, but has no active IO. Suspending anyway.",
3398 puc->puc_Node.ln_Name);
3403 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3405 return TRUE;
3407 return FALSE;
3408 AROS_LIBFUNC_EXIT
3410 /* \\\ */
3412 /* /// "psdSuspendDevice()" */
3413 AROS_LH1(BOOL, psdSuspendDevice,
3414 AROS_LHA(struct PsdDevice *, pd, A0),
3415 LIBBASETYPEPTR, ps, 98, psd)
3417 AROS_LIBFUNC_INIT
3418 struct PsdUsbClass *puc;
3419 struct PsdDevice *hubpd;
3420 APTR binding;
3421 BOOL res = FALSE;
3423 KPRINTF(5, ("psdSuspendDevice(%p)\n", pd));
3424 if(pd)
3426 if(pd->pd_Flags & PDFF_SUSPENDED)
3428 return TRUE;
3430 hubpd = pd->pd_Hub;
3431 if(!hubpd) // suspend root hub
3433 // suspend whole USB, using the HCI UHCMD_USBSUSPEND command
3434 // FIXME currently unsupported!
3435 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Suspending of root hub currently not supported.");
3436 return FALSE;
3439 psdLockWriteDevice(pd);
3440 res = psdSuspendBindings(pd);
3441 psdUnlockDevice(pd);
3442 if(res)
3444 psdLockReadDevice(pd);
3445 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3447 res = usbDoMethod(UCM_HubSuspendDevice, binding, pd);
3449 psdUnlockDevice(pd);
3452 if(!res)
3454 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
3455 "Suspending of device '%s' failed.",
3456 pd->pd_ProductStr);
3458 return(res);
3459 AROS_LIBFUNC_EXIT
3461 /* \\\ */
3463 /* /// "psdResumeBindings()" */
3464 AROS_LH1(BOOL, psdResumeBindings,
3465 AROS_LHA(struct PsdDevice *, pd, A0),
3466 LIBBASETYPEPTR, ps, 101, psd)
3468 AROS_LIBFUNC_INIT
3469 struct PsdUsbClass *puc;
3470 struct PsdConfig *pc;
3471 struct PsdInterface *pif;
3472 BOOL res = FALSE;
3473 BOOL rescan = FALSE;
3475 KPRINTF(5, ("psdResumeBindings(%p)\n", pd));
3476 if(pd)
3478 // ask existing bindings to resume -- if they don't support it, rebind
3479 if(pd->pd_DevBinding)
3481 if(!(pd->pd_Flags & PDFF_APPBINDING))
3483 if((puc = pd->pd_ClsBinding))
3485 res = usbDoMethod(UCM_AttemptResumeDevice, pd->pd_DevBinding);
3486 if(!res)
3488 // if the device couldn't resume, better get rid of the binding
3489 psdReleaseDevBinding(pd);
3490 rescan = TRUE;
3495 pc = pd->pd_CurrentConfig;
3496 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
3497 while(pif->pif_Node.ln_Succ)
3499 if(pif->pif_IfBinding)
3501 if((puc = pif->pif_ClsBinding))
3503 res = usbDoMethod(UCM_AttemptResumeDevice, pif->pif_IfBinding);
3504 if(!res)
3506 // didn't want to suspend
3507 psdReleaseIfBinding(pif);
3508 rescan = TRUE;
3511 break;
3513 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
3515 if(rescan)
3517 psdClassScan();
3520 return(TRUE);
3521 AROS_LIBFUNC_EXIT
3523 /* \\\ */
3525 /* /// "psdResumeDevice()" */
3526 AROS_LH1(BOOL, psdResumeDevice,
3527 AROS_LHA(struct PsdDevice *, pd, A0),
3528 LIBBASETYPEPTR, ps, 99, psd)
3530 AROS_LIBFUNC_INIT
3531 struct PsdUsbClass *puc;
3532 struct PsdDevice *hubpd;
3533 APTR binding;
3534 BOOL res = FALSE;
3536 KPRINTF(5, ("psdResumeDevice(%p)\n", pd));
3537 if(pd)
3539 if(!(pd->pd_Flags & PDFF_SUSPENDED))
3541 return(TRUE);
3543 hubpd = pd->pd_Hub;
3544 if(!hubpd) // resume root hub
3546 // resume whole USB, using the HCI UHCMD_USBRESUME command
3547 // FIXME currently unsupported!
3548 return(FALSE);
3550 psdLockWriteDevice(pd);
3551 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
3553 res = usbDoMethod(UCM_HubResumeDevice, binding, pd);
3555 psdUnlockDevice(pd);
3557 if(res)
3559 psdResumeBindings(pd);
3563 return(res);
3564 AROS_LIBFUNC_EXIT
3566 /* \\\ */
3568 /* /// "psdFindDeviceA()" */
3569 AROS_LH2(struct PsdDevice *, psdFindDeviceA,
3570 AROS_LHA(struct PsdDevice *, pd, A0),
3571 AROS_LHA(struct TagItem *, tags, A1),
3572 LIBBASETYPEPTR, ps, 44, psd)
3574 AROS_LIBFUNC_INIT
3575 struct TagItem *ti;
3576 BOOL takeit;
3577 KPRINTF(2, ("psdFindDeviceA(%p, %p)\n", pd, tags));
3578 while((pd = psdGetNextDevice(pd)))
3580 takeit = TRUE;
3581 if((ti = FindTagItem(DA_ProductID, tags)))
3583 if(ti->ti_Data != pd->pd_ProductID)
3585 takeit = FALSE;
3588 if((ti = FindTagItem(DA_VendorID, tags)))
3590 if(ti->ti_Data != pd->pd_VendorID)
3592 takeit = FALSE;
3595 if((ti = FindTagItem(DA_Class, tags)))
3597 if(ti->ti_Data != pd->pd_DevClass)
3599 takeit = FALSE;
3602 if((ti = FindTagItem(DA_SubClass, tags)))
3604 if(ti->ti_Data != pd->pd_DevSubClass)
3606 takeit = FALSE;
3609 if((ti = FindTagItem(DA_Protocol, tags)))
3611 if(ti->ti_Data != pd->pd_DevProto)
3613 takeit = FALSE;
3616 if((ti = FindTagItem(DA_Version, tags)))
3618 if(ti->ti_Data != pd->pd_DevVers)
3620 takeit = FALSE;
3623 if((ti = FindTagItem(DA_SerialNumber, tags)))
3625 if(strcmp((STRPTR) ti->ti_Data, pd->pd_SerNumStr))
3627 takeit = FALSE;
3630 if((ti = FindTagItem(DA_ProductName, tags)))
3632 if(strcmp((STRPTR) ti->ti_Data, pd->pd_ProductStr))
3634 takeit = FALSE;
3637 if((ti = FindTagItem(DA_Manufacturer, tags)))
3639 if(strcmp((STRPTR) ti->ti_Data, pd->pd_MnfctrStr))
3641 takeit = FALSE;
3644 if((ti = FindTagItem(DA_IDString, tags)))
3646 if(strcmp((STRPTR) ti->ti_Data, pd->pd_IDString))
3648 takeit = FALSE;
3651 if((ti = FindTagItem(DA_Binding, tags)))
3653 if(ti->ti_Data != (IPTR) pd->pd_DevBinding)
3655 takeit = FALSE;
3658 if((ti = FindTagItem(DA_HubDevice, tags)))
3660 if(ti->ti_Data != (IPTR) pd->pd_Hub)
3662 takeit = FALSE;
3666 if(takeit)
3668 return(pd);
3671 return(NULL);
3672 AROS_LIBFUNC_EXIT
3674 /* \\\ */
3676 /* *** Hardware *** */
3678 /* /// "pFindHardware()" */
3679 struct PsdHardware * pFindHardware(LIBBASETYPEPTR ps, STRPTR name, ULONG unit)
3681 struct PsdHardware *phw;
3682 Forbid();
3683 while(*name)
3685 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
3686 while(phw->phw_Node.ln_Succ)
3688 if((phw->phw_Unit == unit) && (!strcmp(phw->phw_DevName, name)))
3690 Permit();
3691 return(phw);
3693 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
3697 if((*name == '/') || (*name == ':'))
3699 ++name;
3700 break;
3702 } while(*(++name));
3704 Permit();
3705 return(NULL);
3707 /* \\\ */
3709 /* /// "psdEnumerateHardware()" */
3710 AROS_LH1(struct PsdDevice *, psdEnumerateHardware,
3711 AROS_LHA(struct PsdHardware *, phw, A0),
3712 LIBBASETYPEPTR, ps, 14, psd)
3714 AROS_LIBFUNC_INIT
3715 struct PsdDevice *pd = NULL;
3716 struct PsdPipe *pp;
3717 struct MsgPort *mp;
3718 KPRINTF(2, ("psdEnumerateHardware(%p)\n", phw));
3720 if((mp = CreateMsgPort()))
3722 Forbid();
3723 if((pd = psdAllocDevice(phw)))
3725 Permit();
3726 if((pp = psdAllocPipe(pd, mp, NULL)))
3728 //pp->pp_IOReq.iouh_Flags |= UHFF_NAKTIMEOUT;
3729 //pp->pp_IOReq.iouh_NakTimeout = 1000;
3730 pd->pd_Flags |= PDFF_CONNECTED;
3731 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_USBRESET;
3732 psdDoPipe(pp, NULL, 0);
3733 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
3734 psdDelayMS(100); // wait for root hub to settle
3735 if(psdEnumerateDevice(pp))
3737 KPRINTF(1, ("Enumeration finished!\n"));
3738 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Root hub has been enumerated.");
3739 psdFreePipe(pp);
3740 DeleteMsgPort(mp);
3741 phw->phw_RootDevice = pd;
3742 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
3743 return(pd);
3745 psdFreePipe(pp);
3747 pFreeBindings(ps, pd);
3748 pFreeDevice(ps, pd);
3749 } else {
3750 Permit();
3752 DeleteMsgPort(mp);
3754 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Root hub enumeration failed. Blame your hardware driver programmer.");
3755 return(NULL);
3756 AROS_LIBFUNC_EXIT
3758 /* \\\ */
3760 /* /// "psdRemHardware()" */
3761 AROS_LH1(void, psdRemHardware,
3762 AROS_LHA(struct PsdHardware *, phw, A0),
3763 LIBBASETYPEPTR, ps, 13, psd)
3765 AROS_LIBFUNC_INIT
3766 struct PsdDevice *pd;
3767 ULONG cnt;
3769 KPRINTF(5, ("FreeHardware(%p)\n", phw));
3771 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3772 while(pd->pd_Node.ln_Succ)
3774 pFreeBindings(ps, pd);
3775 pFreeDevice(ps, pd);
3776 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3777 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3779 cnt = 0;
3780 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3781 while(pd->pd_Node.ln_Succ)
3783 if(pd->pd_UseCnt)
3785 KPRINTF(20, ("Can't remove device, usecnt %ld\n", pd->pd_UseCnt));
3786 if(++cnt == 5)
3788 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3789 "Can't remove device '%s', there are still %ld pipes in use...",
3790 pd->pd_ProductStr, pd->pd_UseCnt);
3792 if(++cnt == 30)
3794 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
3795 "Okay, going down with device '%s' anyway, maybe the driver crashed?",
3796 pd->pd_ProductStr);
3797 pd->pd_UseCnt = 0;
3798 cnt--;
3799 } else {
3800 psdDelayMS(1000);
3802 } else {
3803 pFreeDevice(ps, pd);
3804 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
3806 pd = (struct PsdDevice *) phw->phw_DeadDevices.lh_Head;
3809 Forbid();
3810 /* Note that the subtask unlinks the hardware! */
3811 phw->phw_ReadySignal = SIGB_SINGLE;
3812 phw->phw_ReadySigTask = FindTask(NULL);
3813 if(phw->phw_Task)
3815 Signal(phw->phw_Task, SIGBREAKF_CTRL_C);
3817 Permit();
3818 while(phw->phw_Task)
3820 Wait(1L<<phw->phw_ReadySignal);
3822 //FreeSignal(phw->phw_ReadySignal);
3823 KPRINTF(1, ("FreeHardware(%p) freevec name\n", phw));
3824 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3825 "Removed hardware %s/%ld. Bye bye!",
3826 phw->phw_DevName, phw->phw_Unit);
3827 psdFreeVec(phw->phw_DevName);
3828 psdFreeVec(phw->phw_ProductName);
3829 psdFreeVec(phw->phw_Manufacturer);
3830 psdFreeVec(phw->phw_Description);
3831 psdFreeVec(phw->phw_Copyright);
3832 psdFreeVec(phw);
3833 psdSendEvent(EHMB_REMHARDWARE, phw, NULL);
3834 KPRINTF(1, ("FreeHardware(%p) done\n", phw));
3835 AROS_LIBFUNC_EXIT
3837 /* \\\ */
3839 /* /// "psdAddHardware()" */
3840 AROS_LH2(struct PsdHardware *,psdAddHardware,
3841 AROS_LHA(STRPTR, name, A0),
3842 AROS_LHA(ULONG, unit, D0),
3843 LIBBASETYPEPTR, ps, 12, psd)
3845 AROS_LIBFUNC_INIT
3846 struct PsdHardware *phw;
3847 char buf[64];
3848 struct Task *tmptask;
3849 KPRINTF(5, ("psdAddHardware(%s, %ld)\n", name, unit));
3851 if((phw = psdAllocVec(sizeof(struct PsdHardware))))
3853 NewList(&phw->phw_Devices);
3854 NewList(&phw->phw_DeadDevices);
3855 phw->phw_Unit = unit;
3856 phw->phw_Base = ps;
3857 if((phw->phw_Node.ln_Name = phw->phw_DevName = psdCopyStr(name)))
3859 psdSafeRawDoFmt(buf, 64, "usbhw<%s/%ld>", name, unit);
3860 phw->phw_ReadySignal = SIGB_SINGLE;
3861 phw->phw_ReadySigTask = FindTask(NULL);
3862 SetSignal(0, SIGF_SINGLE); // clear single bit
3863 if((tmptask = psdSpawnSubTask(buf, pDeviceTask, phw)))
3865 psdBorrowLocksWait(tmptask, 1UL<<phw->phw_ReadySignal);
3866 if(phw->phw_Task)
3868 phw->phw_ReadySigTask = NULL;
3869 //FreeSignal(phw->phw_ReadySignal);
3870 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
3871 "New hardware %s/%ld added (%s).",
3872 phw->phw_DevName,
3873 phw->phw_Unit,
3874 phw->phw_ProductName);
3875 psdSendEvent(EHMB_ADDHARDWARE, phw, NULL);
3876 return(phw);
3879 phw->phw_ReadySigTask = NULL;
3880 //FreeSignal(phw->phw_ReadySignal);
3881 psdFreeVec(phw->phw_DevName);
3883 psdFreeVec(phw);
3885 return(NULL);
3886 AROS_LIBFUNC_EXIT
3888 /* \\\ */
3890 /* /// "psdCalculatePower()" */
3891 AROS_LH1(void, psdCalculatePower,
3892 AROS_LHA(struct PsdHardware *, phw, A0),
3893 LIBBASETYPEPTR, ps, 78, psd)
3895 AROS_LIBFUNC_INIT
3896 struct PsdDevice *roothub = NULL;
3897 struct PsdDevice *pd;
3899 psdLockReadPBase();
3900 /* goto root */
3901 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
3902 while(pd->pd_Node.ln_Succ)
3904 if(!pd->pd_Hub)
3906 roothub = pd;
3907 break;
3909 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
3911 if(!roothub)
3913 psdUnlockPBase();
3914 return;
3916 roothub->pd_PowerDrain = 0;
3917 roothub->pd_PowerSupply = 500;
3919 /* calculate drain */
3920 pPowerRecurseDrain(ps, roothub);
3922 /* calculate supply */
3923 pPowerRecurseSupply(ps, roothub);
3924 psdUnlockPBase();
3925 AROS_LIBFUNC_EXIT
3927 /* \\\ */
3929 /* *** Pipes *** */
3931 /* /// "psdAllocPipe()" */
3932 AROS_LH3(struct PsdPipe *, psdAllocPipe,
3933 AROS_LHA(struct PsdDevice *, pd, A0),
3934 AROS_LHA(struct MsgPort *, mp, A1),
3935 AROS_LHA(struct PsdEndpoint *, pep, A2),
3936 LIBBASETYPEPTR, ps, 24, psd)
3938 AROS_LIBFUNC_INIT
3939 struct PsdPipe *pp;
3940 struct PsdDevice *hubpd;
3942 KPRINTF(2, ("psdAllocPipe(%p, %p, %p)\n", pd, mp, pep));
3943 if(!mp || !pd)
3945 return(NULL);
3947 if(pep && (pep->pep_TransType == USEAF_ISOCHRONOUS) && (!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_ISO)))
3949 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support iso transfers. Sorry.");
3950 return(NULL);
3953 if((pp = psdAllocVec(sizeof(struct PsdPipe))))
3955 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
3956 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = mp;
3957 pp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
3958 pp->pp_Device = pd;
3959 pp->pp_Endpoint = pep;
3960 pp->pp_IOReq = *(pd->pd_Hardware->phw_RootIOReq);
3961 pp->pp_IOReq.iouh_DevAddr = pd->pd_DevAddr;
3962 if(pd->pd_Flags & PDFF_LOWSPEED)
3964 pp->pp_IOReq.iouh_Flags |= UHFF_LOWSPEED;
3966 if(pd->pd_Flags & PDFF_HIGHSPEED)
3968 pp->pp_IOReq.iouh_Flags |= UHFF_HIGHSPEED;
3969 if(pep)
3971 switch(pep->pep_NumTransMuFr)
3973 case 2:
3974 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_2;
3975 break;
3976 case 3:
3977 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_3;
3978 break;
3980 default:
3981 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3983 } else {
3984 pp->pp_IOReq.iouh_Flags |= UHFF_MULTI_1;
3987 #ifdef AROS_USB30_CODE
3988 if(pd->pd_Flags & PDFF_SUPERSPEED)
3990 pp->pp_IOReq.iouh_Flags |= UHFF_SUPERSPEED;
3992 #endif
3993 if(pd->pd_Flags & PDFF_NEEDSSPLIT)
3995 /* USB1.1 device connected to a USB2.0 hub */
3996 pp->pp_IOReq.iouh_Flags |= UHFF_SPLITTRANS;
3997 hubpd = pd->pd_Hub;
3998 pp->pp_IOReq.iouh_SplitHubPort = pd->pd_HubPort;
3999 // find the root USB 2.0 hub in the tree
4000 while(hubpd && !(hubpd->pd_Flags & PDFF_HIGHSPEED))
4002 pp->pp_IOReq.iouh_SplitHubPort = hubpd->pd_HubPort;
4003 hubpd = hubpd->pd_Hub;
4005 if(!hubpd)
4007 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Internal error obtaining split transaction hub!");
4008 psdFreeVec(pp);
4009 return(NULL);
4011 pp->pp_IOReq.iouh_Flags |= (hubpd->pd_HubThinkTime<<UHFS_THINKTIME);
4012 pp->pp_IOReq.iouh_SplitHubAddr = hubpd->pd_DevAddr;
4014 if(pep)
4016 switch(pep->pep_TransType)
4018 case USEAF_CONTROL:
4019 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4020 break;
4021 case USEAF_ISOCHRONOUS:
4022 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ISOXFER;
4023 break;
4024 case USEAF_BULK:
4025 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_BULKXFER;
4026 break;
4027 case USEAF_INTERRUPT:
4028 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_INTXFER;
4029 break;
4030 default:
4031 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
4032 "AllocPipe(): Illegal transfer type %ld",
4033 pep->pep_TransType);
4034 KPRINTF(20, ("Illegal transfer type for endpoint!"));
4035 psdFreeVec(pp);
4036 return(NULL);
4039 pp->pp_IOReq.iouh_Dir = (pep->pep_Direction ? UHDIR_IN : UHDIR_OUT);
4040 pp->pp_IOReq.iouh_Endpoint = pep->pep_EPNum;
4041 pp->pp_IOReq.iouh_MaxPktSize = pep->pep_MaxPktSize;
4042 pp->pp_IOReq.iouh_Interval = pep->pep_Interval;
4043 } else {
4044 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_CONTROLXFER;
4045 pp->pp_IOReq.iouh_Dir = UHDIR_SETUP;
4046 pp->pp_IOReq.iouh_Endpoint = 0;
4047 pp->pp_IOReq.iouh_MaxPktSize = pd->pd_MaxPktSize0;
4049 pd->pd_UseCnt++;
4050 return(pp);
4052 return(NULL);
4053 AROS_LIBFUNC_EXIT
4055 /* \\\ */
4057 /* /// "psdFreePipe()" */
4058 AROS_LH1(void, psdFreePipe,
4059 AROS_LHA(struct PsdPipe *, pp, A1),
4060 LIBBASETYPEPTR, ps, 25, psd)
4062 AROS_LIBFUNC_INIT
4063 struct PsdDevice *pd;
4064 if(!pp)
4066 return;
4068 KPRINTF(2, ("psdFreePipe(%p)\n", pp));
4069 pd = pp->pp_Device;
4071 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4073 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4074 "Tried to free pipe on %s that was still pending!", pd->pd_ProductStr);
4075 psdAbortPipe(pp);
4076 psdWaitPipe(pp);
4079 if(!(--pd->pd_UseCnt) && (pd->pd_Flags & PDFF_DELEXPUNGE))
4081 KPRINTF(20, ("Finally getting rid of device %s\n", pd->pd_ProductStr));
4082 pFreeDevice(ps, pd);
4083 //psdSendEvent(EHMB_REMDEVICE, pd, NULL);
4086 psdFreeVec(pp);
4087 AROS_LIBFUNC_EXIT
4089 /* \\\ */
4091 /* /// "psdPipeSetup()" */
4092 AROS_LH5(void, psdPipeSetup,
4093 AROS_LHA(struct PsdPipe *, pp, A1),
4094 AROS_LHA(UWORD, rt, D0),
4095 AROS_LHA(UWORD, rq, D1),
4096 AROS_LHA(UWORD, val, D2),
4097 AROS_LHA(UWORD, idx, D3),
4098 LIBBASETYPEPTR, ps, 26, psd)
4100 AROS_LIBFUNC_INIT
4101 struct UsbSetupData *usd = &pp->pp_IOReq.iouh_SetupData;
4103 KPRINTF(1, ("psdSetupPipe(%p, (%02lx %02lx %04lx %04lx))\n",
4104 pp, rt, rq, val, idx));
4105 usd->bmRequestType = rt;
4106 usd->bRequest = rq;
4107 usd->wValue = AROS_WORD2LE(val);
4108 usd->wIndex = AROS_WORD2LE(idx);
4109 AROS_LIBFUNC_EXIT
4111 /* \\\ */
4113 /* /// "psdDoPipe()" */
4114 AROS_LH3(LONG, psdDoPipe,
4115 AROS_LHA(struct PsdPipe *, pp, A1),
4116 AROS_LHA(APTR, data, A0),
4117 AROS_LHA(ULONG, len, D0),
4118 LIBBASETYPEPTR, ps, 27, psd)
4120 AROS_LIBFUNC_INIT
4121 struct PsdDevice *pd = pp->pp_Device;
4122 KPRINTF(200, ("psdDoPipe(%p, %p, %ld)\n", pp, data, len));
4124 if(pd->pd_Flags & PDFF_CONNECTED)
4126 if(pd->pd_Flags & PDFF_SUSPENDED)
4128 // make sure the device is up and running before trying to send a new pipe
4129 psdResumeDevice(pd);
4132 pp->pp_IOReq.iouh_Data = data;
4133 pp->pp_IOReq.iouh_Length = len;
4134 if(!pp->pp_Endpoint)
4136 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4138 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4139 ++pd->pd_IOBusyCount;
4140 GetSysTime((APTR) &pd->pd_LastActivity);
4141 return(psdWaitPipe(pp));
4142 } else {
4143 psdDelayMS(50);
4144 pp->pp_IOReq.iouh_Actual = 0;
4145 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4146 return(pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT);
4148 AROS_LIBFUNC_EXIT
4150 /* \\\ */
4152 /* /// "psdSendPipe()" */
4153 AROS_LH3(void, psdSendPipe,
4154 AROS_LHA(struct PsdPipe *, pp, A1),
4155 AROS_LHA(APTR, data, A0),
4156 AROS_LHA(ULONG, len, D0),
4157 LIBBASETYPEPTR, ps, 28, psd)
4159 AROS_LIBFUNC_INIT
4160 struct PsdDevice *pd = pp->pp_Device;
4161 KPRINTF(200, ("psdSendPipe(%p, %p, %ld)\n", pp, data, len));
4162 if(pd->pd_Flags & PDFF_CONNECTED)
4164 if(pd->pd_Flags & PDFF_SUSPENDED)
4166 // make sure the device is up and running before trying to send a new pipe
4167 psdResumeDevice(pd);
4170 pp->pp_IOReq.iouh_Data = data;
4171 pp->pp_IOReq.iouh_Length = len;
4172 if(!pp->pp_Endpoint)
4174 pp->pp_IOReq.iouh_SetupData.wLength = AROS_WORD2LE(len);
4176 PutMsg(&pd->pd_Hardware->phw_TaskMsgPort, &pp->pp_Msg);
4177 GetSysTime((APTR) &pd->pd_LastActivity);
4178 ++pd->pd_IOBusyCount;
4179 } else {
4180 psdDelayMS(50);
4181 pp->pp_IOReq.iouh_Actual = 0;
4182 //pp->pp_Msg.mn_Node.ln_Type = NT_REPLYMSG;
4183 pp->pp_IOReq.iouh_Req.io_Error = UHIOERR_TIMEOUT;
4184 ReplyMsg(&pp->pp_Msg);
4185 ++pd->pd_IOBusyCount;
4187 AROS_LIBFUNC_EXIT
4189 /* \\\ */
4191 /* /// "psdAbortPipe()" */
4192 AROS_LH1(void, psdAbortPipe,
4193 AROS_LHA(struct PsdPipe *, pp, A1),
4194 LIBBASETYPEPTR, ps, 29, psd)
4196 AROS_LIBFUNC_INIT
4197 struct PsdPipe *npp;
4199 KPRINTF(5, ("psdAbortPipe(%p)\n", pp));
4200 if(pp->pp_Msg.mn_Node.ln_Type != NT_MESSAGE)
4202 KPRINTF(5, ("Nothing to abort %02lx\n", pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type));
4203 return;
4205 if((npp = psdAllocVec(sizeof(struct PsdPipe))))
4207 //npp->pp_Msg.mn_Node.ln_Type = NT_MESSAGE;
4208 npp->pp_Device = pp->pp_Device;
4209 npp->pp_MsgPort = npp->pp_Msg.mn_ReplyPort = pp->pp_MsgPort;
4210 npp->pp_Msg.mn_Length = sizeof(struct PsdPipe);
4212 npp->pp_AbortPipe = pp;
4213 PutMsg(&pp->pp_Device->pd_Hardware->phw_TaskMsgPort, &npp->pp_Msg);
4214 psdWaitPipe(npp);
4215 psdFreeVec(npp);
4217 AROS_LIBFUNC_EXIT
4219 /* \\\ */
4221 /* /// "psdWaitPipe()" */
4222 AROS_LH1(LONG, psdWaitPipe,
4223 AROS_LHA(struct PsdPipe *, pp, A1),
4224 LIBBASETYPEPTR, ps, 30, psd)
4226 AROS_LIBFUNC_INIT
4227 ULONG sigs = 0;
4228 struct PsdDevice *pd = pp->pp_Device;
4229 LONG ioerr;
4230 KPRINTF(5, ("psdWaitPipe(%p)\n", pp));
4231 while(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4233 KPRINTF(5, ("ln_Type = %02lx\n", pp->pp_Msg.mn_Node.ln_Type));
4234 sigs |= Wait(1L<<pp->pp_MsgPort->mp_SigBit);
4235 KPRINTF(5, ("sigs = %p\n", sigs));
4237 #if 1 // broken?
4238 Forbid();
4239 if(pp->pp_Msg.mn_Node.ln_Type == NT_REPLYMSG)
4241 pp->pp_Msg.mn_Node.ln_Type = NT_FREEMSG;
4242 Remove(&pp->pp_Msg.mn_Node);
4244 //if(pp->pp_MsgPort->mp_MsgList.lh_Head->ln_Succ)
4246 // avoid signals getting lost for other messages arriving.
4247 SetSignal(sigs, sigs);
4249 Permit();
4250 #else
4251 Forbid();
4252 Remove(&pp->pp_Msg.mn_Node);
4253 Permit();
4254 #endif
4255 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4256 switch(ioerr)
4258 case UHIOERR_TIMEOUT:
4259 pd->pd_DeadCount++;
4260 // fall through
4261 case UHIOERR_NAKTIMEOUT:
4262 pd->pd_DeadCount++;
4263 case UHIOERR_CRCERROR:
4264 pd->pd_DeadCount++;
4265 break;
4266 case UHIOERR_RUNTPACKET:
4267 default:
4268 if(pd->pd_DeadCount)
4270 pd->pd_DeadCount >>= 1;
4271 /*psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4272 "Device %s starts recovering with %s (%ld)!",
4273 pd->pd_ProductStr,
4274 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
4277 KPRINTF(200, ("psdWaitPipe(%p)=%ld\n", pp, ioerr));
4278 --pd->pd_IOBusyCount;
4279 GetSysTime((APTR) &pd->pd_LastActivity);
4281 if((pd->pd_DeadCount > 19) || ((pd->pd_DeadCount > 14) && (pd->pd_Flags & (PDFF_HASDEVADDR|PDFF_HASDEVDESC))))
4283 if(!(pd->pd_Flags & PDFF_DEAD))
4285 pd->pd_Flags |= PDFF_DEAD;
4286 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
4287 "Device %s probably dropped dead!", pd->pd_ProductStr);
4289 psdSendEvent(EHMB_DEVICEDEAD, pp->pp_Device, NULL);
4291 } else {
4292 if((!pd->pd_DeadCount) && ((pd->pd_Flags & (PDFF_DEAD|PDFF_CONNECTED)) == (PDFF_DEAD|PDFF_CONNECTED)))
4294 pd->pd_Flags &= ~PDFF_DEAD;
4295 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
4296 "Uuuhuuuhh, the zombie %s returned from the dead!", pd->pd_ProductStr);
4299 return(ioerr);
4300 AROS_LIBFUNC_EXIT
4302 /* \\\ */
4304 /* /// "psdCheckPipe()" */
4305 AROS_LH1(struct PsdPipe *, psdCheckPipe,
4306 AROS_LHA(struct PsdPipe *, pp, A1),
4307 LIBBASETYPEPTR, ps, 71, psd)
4309 AROS_LIBFUNC_INIT
4310 KPRINTF(5, ("psdCheckPipe(%p)\n", pp));
4311 if(pp->pp_Msg.mn_Node.ln_Type == NT_MESSAGE)
4313 return(NULL);
4315 return(pp);
4316 AROS_LIBFUNC_EXIT
4318 /* \\\ */
4320 /* /// "psdGetPipeActual()" */
4321 AROS_LH1(ULONG, psdGetPipeActual,
4322 AROS_LHA(struct PsdPipe *, pp, A1),
4323 LIBBASETYPEPTR, ps, 31, psd)
4325 AROS_LIBFUNC_INIT
4326 KPRINTF(1, ("psdGetPipeActual(%p)\n", pp));
4327 return(pp->pp_IOReq.iouh_Actual);
4328 AROS_LIBFUNC_EXIT
4330 /* \\\ */
4332 /* /// "psdGetPipeError()" */
4333 AROS_LH1(LONG, psdGetPipeError,
4334 AROS_LHA(struct PsdPipe *, pp, A1),
4335 LIBBASETYPEPTR, ps, 32, psd)
4337 AROS_LIBFUNC_INIT
4338 KPRINTF(1, ("psdGetPipeError(%p)\n", pp));
4339 return((LONG) pp->pp_IOReq.iouh_Req.io_Error);
4340 AROS_LIBFUNC_EXIT
4342 /* \\\ */
4344 /* *** Streams *** */
4346 /* /// "psdOpenStreamA()" */
4347 AROS_LH2(struct PsdPipeStream *, psdOpenStreamA,
4348 AROS_LHA(struct PsdEndpoint *, pep, A0),
4349 AROS_LHA(struct TagItem *, tags, A1),
4350 LIBBASETYPEPTR, ps, 72, psd)
4352 AROS_LIBFUNC_INIT
4353 struct PsdPipeStream *pps;
4355 KPRINTF(2, ("psdOpenStream(%p, %p)\n", pep, tags));
4356 if(!pep)
4358 return(NULL);
4360 if((pps = psdAllocVec(sizeof(struct PsdPipeStream))))
4362 pps->pps_Device = pep->pep_Interface->pif_Config->pc_Device;
4363 pps->pps_Endpoint = pep;
4364 NewList(&pps->pps_FreePipes);
4365 NewList(&pps->pps_ReadyPipes);
4366 InitSemaphore(&pps->pps_AccessLock);
4367 pps->pps_NakTimeoutTime = 5000;
4368 if(pep->pep_Direction)
4370 /* Defaults for IN */
4371 pps->pps_NumPipes = 4;
4372 pps->pps_Flags = PSFF_READAHEAD|PSFF_BUFFERREAD|PSFF_ALLOWRUNT;
4373 pps->pps_BufferSize = 32*pps->pps_Endpoint->pep_MaxPktSize;
4374 } else {
4375 /* Defaults for OUT */
4376 pps->pps_NumPipes = 4;
4377 pps->pps_Flags = PSFF_NOSHORTPKT;
4378 pps->pps_BufferSize = 4*pps->pps_Endpoint->pep_MaxPktSize;
4381 psdSetAttrsA(PGA_PIPESTREAM, pps, tags);
4382 if(!pps->pps_Pipes)
4384 psdCloseStream(pps);
4385 pps = NULL;
4387 return(pps);
4389 return(NULL);
4390 AROS_LIBFUNC_EXIT
4392 /* \\\ */
4394 /* /// "psdCloseStream()" */
4395 AROS_LH1(void, psdCloseStream,
4396 AROS_LHA(struct PsdPipeStream *, pps, A1),
4397 LIBBASETYPEPTR, ps, 73, psd)
4399 AROS_LIBFUNC_INIT
4400 struct PsdPipe *pp;
4401 ULONG cnt;
4403 KPRINTF(2, ("psdCloseStream(%p)\n", pps));
4404 if(!pps)
4406 return;
4408 psdStreamFlush(pps);
4409 ObtainSemaphore(&pps->pps_AccessLock);
4410 if(pps->pps_Pipes)
4412 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4414 pp = pps->pps_Pipes[cnt];
4415 //if(pp->pp_IOReq.iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE)
4417 KPRINTF(1, ("Abort %ld\n", cnt));
4418 psdAbortPipe(pp);
4419 KPRINTF(1, ("Wait %ld\n", cnt));
4420 psdWaitPipe(pp);
4422 KPRINTF(1, ("Free %ld\n", cnt));
4423 psdFreePipe(pp);
4425 psdFreeVec(pps->pps_Pipes);
4426 if((pps->pps_Flags & PSFF_OWNMSGPORT) && pps->pps_MsgPort)
4428 DeleteMsgPort(pps->pps_MsgPort);
4431 psdFreeVec(pps->pps_Buffer);
4432 ReleaseSemaphore(&pps->pps_AccessLock);
4433 psdFreeVec(pps);
4434 AROS_LIBFUNC_EXIT
4436 /* \\\ */
4438 /* /// "psdStreamRead()" */
4439 AROS_LH3(LONG, psdStreamRead,
4440 AROS_LHA(struct PsdPipeStream *, pps, A1),
4441 AROS_LHA(UBYTE *, buffer, A0),
4442 AROS_LHA(LONG, length, D0),
4443 LIBBASETYPEPTR, ps, 74, psd)
4445 AROS_LIBFUNC_INIT
4446 struct PsdPipe *pp;
4447 ULONG cnt;
4448 LONG ioerr;
4449 LONG remlen;
4450 BOOL term = FALSE;
4451 LONG actual = 0;
4452 ULONG sigmask;
4454 UBYTE *bufptr;
4455 UBYTE *srcptr;
4456 UBYTE *tarrptr;
4457 ULONG tcnt;
4458 UBYTE cchar;
4460 KPRINTF(2, ("psdStreamRead(%p, %p, %ld)\n", pps, buffer, length));
4461 if(!pps)
4463 return(-1);
4465 ObtainSemaphore(&pps->pps_AccessLock);
4466 KPRINTF(2, ("Sema\n"));
4467 pps->pps_Error = 0;
4468 if((!pps->pps_Pipes) || (!pps->pps_Endpoint->pep_Direction))
4470 KPRINTF(2, ("Wrong direction!\n"));
4471 pps->pps_Error = UHIOERR_BADPARAMS;
4472 ReleaseSemaphore(&pps->pps_AccessLock);
4473 return(-1);
4475 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4477 if(pps->pps_Flags & PSFF_BUFFERREAD)
4479 /* buffered reading */
4482 /* check for incoming packets */
4483 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4485 KPRINTF(1, ("PktBack(%p, %p, %ld/%ld)=%ld\n",
4486 pp, pp->pp_IOReq.iouh_Data, pp->pp_IOReq.iouh_Actual,
4487 pp->pp_IOReq.iouh_Length, pp->pp_IOReq.iouh_Req.io_Error));
4489 pps->pps_ReqBytes -= pp->pp_IOReq.iouh_Length;
4490 ioerr = pp->pp_IOReq.iouh_Req.io_Error;
4491 if((ioerr == UHIOERR_NAKTIMEOUT) && pp->pp_IOReq.iouh_Actual)
4493 ioerr = 0;
4496 if(ioerr)
4498 pps->pps_Error = ioerr;
4499 term = TRUE;
4500 if(ioerr != UHIOERR_TIMEOUT)
4502 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4503 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4504 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4506 /* stop automatic queueing */
4507 pps->pps_Flags &= ~PSFF_READAHEAD;
4508 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4509 } else {
4510 /* successfully received packet */
4511 pps->pps_BytesPending += pp->pp_IOReq.iouh_Actual;
4512 AddTail(&pps->pps_ReadyPipes, &pp->pp_Msg.mn_Node);
4515 if(length == -1) /* get all that's there (STRONGLY DISCOURAGED! Might cause buffer overflows) */
4517 length = pps->pps_BytesPending;
4519 /* check for buffered data */
4520 while(length && pps->pps_BytesPending)
4522 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
4523 if(!pp->pp_Msg.mn_Node.ln_Succ) /* debug */
4525 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) "StreamRead", "Readqueue empty!");
4526 ReleaseSemaphore(&pps->pps_AccessLock);
4527 return(-1);
4529 if(pp->pp_IOReq.iouh_Actual < pps->pps_Offset)
4531 psdAddErrorMsg(RETURN_FAIL, (STRPTR) "StreamRead",
4532 "Actual %ld < offset %ld!", pp->pp_IOReq.iouh_Actual, pps->pps_Offset);
4533 ReleaseSemaphore(&pps->pps_AccessLock);
4534 return(-1);
4536 remlen = pp->pp_IOReq.iouh_Actual - pps->pps_Offset;
4537 if(length < remlen)
4539 KPRINTF(1, ("PktBit(%p, %p, %ld)\n", pp, buffer, length));
4540 remlen = length;
4541 } else {
4542 KPRINTF(1, ("PktRem(%p, %p, %ld)\n", pp, buffer, remlen));
4544 /* copy packet */
4545 if(pp->pp_Flags & PFF_INPLACE)
4547 KPRINTF(1, ("PktRemIP(%p, %p, %ld)\n", pp, buffer, remlen));
4548 } else {
4549 if(pps->pps_TermArray)
4551 /* EOF Mode */
4552 KPRINTF(1, ("PktCpyEOF(%p, %p, %ld)\n", pp, buffer, remlen));
4553 bufptr = buffer;
4554 srcptr = &(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]);
4555 tarrptr = pps->pps_TermArray;
4556 cnt = remlen;
4557 remlen = 0;
4558 if(cnt)
4562 cchar = *bufptr++ = *srcptr++;
4563 remlen++;
4564 tcnt = 0;
4567 if(cchar < tarrptr[tcnt])
4569 break;
4571 else if(cchar == tarrptr[tcnt])
4573 cnt = 1;
4574 term = TRUE;
4575 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, remlen));
4576 break;
4578 if(tcnt < 7)
4580 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4582 break;
4585 } while(++tcnt < 8);
4586 } while(--cnt);
4588 } else {
4589 KPRINTF(1, ("PktCpy(%p, %p, %ld)\n", pp, buffer, remlen));
4590 /* quick non-eof mode */
4591 CopyMem(&(((UBYTE *) pp->pp_IOReq.iouh_Data)[pps->pps_Offset]), buffer, remlen);
4594 actual += remlen;
4595 length -= remlen;
4596 buffer += remlen;
4597 pps->pps_BytesPending -= remlen;
4598 pps->pps_Offset += remlen;
4599 /* end of packet reached? */
4600 if(pps->pps_Offset == pp->pp_IOReq.iouh_Actual)
4602 pps->pps_Offset = 0;
4603 Remove(&pp->pp_Msg.mn_Node);
4604 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4605 /* check for short packet */
4606 if((pps->pps_Flags & PSFF_SHORTTERM) && (pp->pp_IOReq.iouh_Actual % pp->pp_IOReq.iouh_MaxPktSize))
4608 term = TRUE;
4611 if(term)
4613 break;
4616 /* start sending out requests */
4617 remlen = length;
4618 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4619 if(!(pps->pps_BytesPending || pps->pps_ReqBytes || pps->pps_TermArray || (length < pps->pps_BufferSize)))
4621 /* faster non-buffered mode */
4622 if(pp->pp_Msg.mn_Node.ln_Succ)
4624 pp->pp_Flags |= PFF_INPLACE;
4625 Remove(&pp->pp_Msg.mn_Node);
4626 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4627 KPRINTF(1, ("OutFast(%p, %p, %ld/%ld)\n",
4628 pp, buffer, remlen, length));
4629 psdSendPipe(pp, buffer, remlen);
4630 pps->pps_ReqBytes += remlen;
4631 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4634 /* slower buffered mode */
4635 while(pp->pp_Msg.mn_Node.ln_Succ && ((remlen > pps->pps_ReqBytes) || (pps->pps_Flags & PSFF_READAHEAD)))
4637 pp->pp_Flags &= ~PFF_INPLACE;
4638 Remove(&pp->pp_Msg.mn_Node);
4639 if((pps->pps_Flags & PSFF_READAHEAD) || (remlen % pp->pp_IOReq.iouh_MaxPktSize))
4641 KPRINTF(1, ("OutSlow(%p, %p, %ld)\n",
4642 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], pps->pps_BufferSize));
4643 remlen = pps->pps_BufferSize;
4644 } else {
4645 KPRINTF(1, ("OutExact(%p, %p, %ld)\n",
4646 pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen));
4648 psdSendPipe(pp, &pps->pps_Buffer[pp->pp_Num * pps->pps_BufferSize], remlen);
4649 pps->pps_ReqBytes += remlen;
4650 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4652 if((!length) || (pps->pps_Flags & PSFF_DONOTWAIT))
4654 term = TRUE;
4656 if(!term)
4658 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4659 KPRINTF(1, ("WaitPort (%p)\n", sigmask));
4660 sigmask = Wait(sigmask);
4661 KPRINTF(1, ("Wait back (%p)\n", sigmask));
4662 if(sigmask & pps->pps_AbortSigMask)
4664 KPRINTF(1, ("Aborted!\n"));
4665 term = TRUE;
4666 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4669 } while(!term);
4670 } else {
4671 /* plain reading (might lose data) */
4672 if(pps->pps_TermArray || (pps->pps_Flags & PSFF_READAHEAD))
4674 psdAddErrorMsg0(RETURN_WARN, (STRPTR) "StreamRead", "This mode combination for the stream is not supported!");
4676 /* start sending out requests */
4677 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4678 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4680 ioerr = psdDoPipe(pp, buffer, length);
4681 if(ioerr)
4683 pps->pps_Error = ioerr;
4684 if(ioerr != UHIOERR_TIMEOUT)
4686 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamRead",
4687 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4688 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4691 actual = pp->pp_IOReq.iouh_Actual;
4695 ReleaseSemaphore(&pps->pps_AccessLock);
4696 return(actual);
4697 AROS_LIBFUNC_EXIT
4699 /* \\\ */
4701 /* /// "psdStreamWrite()" */
4702 AROS_LH3(LONG, psdStreamWrite,
4703 AROS_LHA(struct PsdPipeStream *, pps, A1),
4704 AROS_LHA(UBYTE *, buffer, A0),
4705 AROS_LHA(LONG, length, D0),
4706 LIBBASETYPEPTR, ps, 75, psd)
4708 AROS_LIBFUNC_INIT
4709 struct PsdPipe *pp;
4710 struct PsdPipe *newpp;
4711 ULONG cnt;
4712 LONG ioerr;
4713 LONG remlen;
4714 LONG actual = 0;
4715 ULONG sigmask;
4717 UBYTE *bufptr;
4718 UBYTE *srcptr;
4719 UBYTE *tarrptr;
4720 ULONG tcnt;
4721 UBYTE cchar;
4723 KPRINTF(2, ("psdStreamWrite(%p, %p, %ld)\n", pps, buffer, length));
4724 if(!pps)
4726 return(-1);
4728 ObtainSemaphore(&pps->pps_AccessLock);
4729 pps->pps_Error = 0;
4730 if((!pps->pps_Pipes) || pps->pps_Endpoint->pep_Direction)
4732 KPRINTF(2, ("Wrong direction!\n"));
4733 pps->pps_Error = UHIOERR_BADPARAMS;
4734 ReleaseSemaphore(&pps->pps_AccessLock);
4735 return(-1);
4737 if(length == -1) /* null terminated string mode */
4739 KPRINTF(2, ("EOL mode!\n"));
4740 length = strlen(buffer);
4742 if((tarrptr = pps->pps_TermArray)) /* EOF Mode */
4744 KPRINTF(1, ("EOFSearch(%p, %ld)\n", buffer, length));
4745 srcptr = buffer;
4746 cnt = length;
4747 length = 0;
4748 if(cnt)
4752 cchar = *srcptr++;
4753 length++;
4754 tcnt = 0;
4757 if(cchar < tarrptr[tcnt])
4759 break;
4761 else if(cchar == tarrptr[tcnt])
4763 cnt = 1;
4764 KPRINTF(2, ("EOF char %02lx found, length = %ld\n", cchar, length));
4765 break;
4767 if(tcnt)
4769 if(tarrptr[tcnt] == tarrptr[tcnt+1])
4771 break;
4774 } while(++tcnt < 8);
4775 } while(--cnt);
4778 if(!(pps->pps_Flags & PSFF_ASYNCIO))
4780 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
4781 if(pp->pp_Msg.mn_Node.ln_Succ && length)
4783 if(pps->pps_Flags & PSFF_BUFFERWRITE)
4785 /* buffered writing */
4786 if(pps->pps_BytesPending)
4788 remlen = pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize;
4789 /* align to packet boundary */
4790 if(remlen + length >= pp->pp_IOReq.iouh_MaxPktSize)
4792 /* new data crosses at least on packet size */
4793 if(pps->pps_BytesPending + length <= pps->pps_BufferSize)
4795 /* copy everything up to the last (!) boundary */
4796 remlen = pps->pps_BytesPending + length;
4797 remlen = remlen - (remlen % pp->pp_IOReq.iouh_MaxPktSize);
4798 remlen -= pps->pps_BytesPending;
4799 KPRINTF(1, ("PendOptCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4800 } else {
4801 /* just calculate amount to copy to the next boundary */
4802 remlen = pp->pp_IOReq.iouh_MaxPktSize - remlen;
4803 KPRINTF(1, ("PendOneCpy(%p, %ld+%ld/%ld)\n", buffer, pps->pps_BytesPending, remlen, length));
4805 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], remlen);
4806 pps->pps_BytesPending += remlen;
4807 actual += remlen;
4808 buffer += remlen;
4809 length -= remlen;
4810 } else {
4811 KPRINTF(1, ("PendAdd(%p, %ld+%ld)\n", buffer, pps->pps_BytesPending, length));
4812 /* only a few bytes, see if we can fit them */
4813 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4814 pps->pps_BytesPending += length;
4815 actual += length;
4816 //buffer += length; /* not needed */
4817 length = 0;
4819 /* flush some buffers */
4820 if((length >= pp->pp_IOReq.iouh_MaxPktSize) ||
4821 ((pps->pps_BytesPending >= (pps->pps_BufferSize>>1)) && (pps->pps_BytesPending >= pp->pp_IOReq.iouh_MaxPktSize)))
4823 remlen = pps->pps_BytesPending - (pps->pps_BytesPending % pp->pp_IOReq.iouh_MaxPktSize);
4824 KPRINTF(1, ("PendFlush(%ld/%ld)\n", remlen, pps->pps_BytesPending));
4825 Remove(&pp->pp_Msg.mn_Node);
4826 psdSendPipe(pp, pps->pps_Buffer, remlen);
4827 pps->pps_ActivePipe = pp;
4828 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4830 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4831 sigmask = Wait(sigmask);
4832 if(sigmask & pps->pps_AbortSigMask)
4834 KPRINTF(1, ("Kill signal detected!\n"));
4835 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4836 break;
4839 if(!newpp)
4841 psdAbortPipe(pp);
4843 ioerr = psdWaitPipe(pp);
4844 pps->pps_ActivePipe = NULL;
4845 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4847 /* move end of buffer */
4848 cnt = pps->pps_BytesPending;
4849 tcnt = pp->pp_IOReq.iouh_Actual;
4850 pps->pps_BytesPending -= tcnt;
4851 bufptr = pps->pps_Buffer;
4852 srcptr = bufptr + tcnt;
4853 cnt -= tcnt;
4854 if(cnt)
4858 *bufptr++ = *srcptr++;
4859 } while(--cnt);
4861 if(ioerr)
4863 pps->pps_Error = ioerr;
4864 if(ioerr != UHIOERR_TIMEOUT)
4866 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4867 "Packet(%s) failed: %s (%ld)", (STRPTR) "b",
4868 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4870 ReleaseSemaphore(&pps->pps_AccessLock);
4871 return(actual);
4875 /* send out large chunk (avoid copying) */
4876 if(length >= pp->pp_IOReq.iouh_MaxPktSize)
4878 remlen = length - (length % pp->pp_IOReq.iouh_MaxPktSize);
4879 KPRINTF(1, ("BulkFlush(%p, %ld/%ld)\n", buffer, remlen, length));
4880 Remove(&pp->pp_Msg.mn_Node);
4881 psdSendPipe(pp, buffer, remlen);
4882 pps->pps_ActivePipe = pp;
4883 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4885 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4886 sigmask = Wait(sigmask);
4887 if(sigmask & pps->pps_AbortSigMask)
4889 KPRINTF(1, ("Kill signal detected!\n"));
4890 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4891 break;
4894 if(!newpp)
4896 psdAbortPipe(pp);
4898 ioerr = psdWaitPipe(pp);
4899 pps->pps_ActivePipe = NULL;
4900 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4902 actual += pp->pp_IOReq.iouh_Actual;
4903 buffer += pp->pp_IOReq.iouh_Actual;
4904 length -= pp->pp_IOReq.iouh_Actual;
4905 if(ioerr)
4907 pps->pps_Error = ioerr;
4908 if(ioerr != UHIOERR_TIMEOUT)
4910 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4911 "Packet(%s) failed: %s (%ld)", (STRPTR) "c",
4912 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4914 ReleaseSemaphore(&pps->pps_AccessLock);
4915 return(actual);
4918 /* buffer remaining bytes */
4919 if(length)
4921 KPRINTF(1, ("BufAdd(%p, %ld)\n", buffer, length));
4922 /* only a few bytes left, so lets buffer them */
4923 CopyMem(buffer, &pps->pps_Buffer[pps->pps_BytesPending], length);
4924 pps->pps_BytesPending += length;
4925 actual += length;
4927 } else {
4928 /* plain writing */
4929 /* start sending out requests */
4930 KPRINTF(1, ("PlainWrite(%p, %ld)\n", buffer, length));
4931 Remove(&pp->pp_Msg.mn_Node);
4932 psdSendPipe(pp, buffer, length);
4933 pps->pps_ActivePipe = pp;
4934 while(!(newpp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
4936 sigmask = (1UL<<pps->pps_MsgPort->mp_SigBit)|pps->pps_AbortSigMask;
4937 sigmask = Wait(sigmask);
4938 if(sigmask & pps->pps_AbortSigMask)
4940 KPRINTF(1, ("Kill signal detected!\n"));
4941 Signal(FindTask(NULL), pps->pps_AbortSigMask & sigmask);
4942 break;
4945 if(!newpp)
4947 psdAbortPipe(pp);
4949 ioerr = psdWaitPipe(pp);
4950 pps->pps_ActivePipe = NULL;
4951 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
4952 if(ioerr)
4954 pps->pps_Error = ioerr;
4955 if(ioerr != UHIOERR_TIMEOUT)
4957 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamWrite",
4958 "Packet(%s) failed: %s (%ld)", (STRPTR) "u",
4959 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
4962 actual = pp->pp_IOReq.iouh_Actual;
4964 } else {
4965 KPRINTF(2, ("No free pipe!\n"));
4968 ReleaseSemaphore(&pps->pps_AccessLock);
4969 return(actual);
4970 AROS_LIBFUNC_EXIT
4972 /* \\\ */
4974 /* /// "psdStreamFlush()" */
4975 AROS_LH1(LONG, psdStreamFlush,
4976 AROS_LHA(struct PsdPipeStream *, pps, A1),
4977 LIBBASETYPEPTR, ps, 76, psd)
4979 AROS_LIBFUNC_INIT
4980 struct PsdPipe *pp;
4981 ULONG cnt;
4982 LONG ioerr;
4983 LONG ret = FALSE;
4985 KPRINTF(2, ("psdStreamFlush(%p)\n", pps));
4986 if(!pps)
4988 return(-1);
4990 ObtainSemaphore(&pps->pps_AccessLock);
4991 pps->pps_Error = 0;
4992 if(pps->pps_Endpoint->pep_Direction)
4994 /* IN */
4995 KPRINTF(2, ("Flushing in...\n"));
4996 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
4998 psdAbortPipe(pps->pps_Pipes[cnt]);
5000 for(cnt = 0; cnt < pps->pps_NumPipes; cnt++)
5002 psdWaitPipe(pps->pps_Pipes[cnt]);
5004 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5005 while(pp->pp_Msg.mn_Node.ln_Succ)
5007 Remove(&pp->pp_Msg.mn_Node);
5008 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5009 pp = (struct PsdPipe *) pps->pps_ReadyPipes.lh_Head;
5011 while((pp = (struct PsdPipe *) GetMsg(pps->pps_MsgPort)))
5013 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5015 pps->pps_ReqBytes = 0;
5016 pps->pps_BytesPending = 0;
5017 pps->pps_Offset = 0;
5018 ret = TRUE;
5019 } else {
5020 /* OUT */
5021 pp = (struct PsdPipe *) pps->pps_FreePipes.lh_Head;
5022 if(pp->pp_Msg.mn_Node.ln_Succ)
5024 ret = TRUE;
5025 if(pps->pps_BytesPending)
5027 KPRINTF(2, ("Flushing out %ld...\n", pps->pps_BytesPending));
5028 Remove(&pp->pp_Msg.mn_Node);
5029 ioerr = psdDoPipe(pp, pps->pps_Buffer, pps->pps_BytesPending);
5030 AddTail(&pps->pps_FreePipes, &pp->pp_Msg.mn_Node);
5031 pps->pps_BytesPending = 0;
5032 if(ioerr)
5034 pps->pps_Error = ioerr;
5035 psdAddErrorMsg(RETURN_WARN, (STRPTR) "StreamFlush",
5036 "Packet(%s) failed: %s (%ld)", (STRPTR) "f",
5037 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5038 ret = FALSE;
5040 } else {
5041 KPRINTF(2, ("Nothing to flush\n"));
5045 ReleaseSemaphore(&pps->pps_AccessLock);
5046 return(ret);
5047 AROS_LIBFUNC_EXIT
5049 /* \\\ */
5051 /* /// "psdGetStreamError()" */
5052 AROS_LH1(LONG, psdGetStreamError,
5053 AROS_LHA(struct PsdPipeStream *, pps, A1),
5054 LIBBASETYPEPTR, ps, 77, psd)
5056 AROS_LIBFUNC_INIT
5057 KPRINTF(1, ("psdGetStreamError(%p)\n", pps));
5058 if(pps)
5060 return((LONG) pps->pps_Error);
5061 } else {
5062 return(-1);
5064 AROS_LIBFUNC_EXIT
5066 /* \\\ */
5068 /* *** Realtime Iso */
5070 /* /// "psdAllocRTIsoHandler()" */
5071 AROS_LH2(struct PsdRTIsoHandler *, psdAllocRTIsoHandlerA,
5072 AROS_LHA(struct PsdEndpoint *, pep, A0),
5073 AROS_LHA(struct TagItem *, tags, A1),
5074 LIBBASETYPEPTR, ps, 93, psd)
5076 AROS_LIBFUNC_INIT
5077 struct PsdRTIsoHandler *prt;
5078 struct PsdPipe *pp;
5079 LONG ioerr;
5081 KPRINTF(2, ("psdAllocRTIso(%p, %p)\n", pep, tags));
5082 if(!pep)
5084 return(NULL);
5086 if(pep->pep_TransType != USEAF_ISOCHRONOUS)
5088 return(NULL);
5090 if(!(pep->pep_Interface->pif_Config->pc_Device->pd_Hardware->phw_Capabilities & UHCF_RT_ISO))
5092 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Your HW controller driver does not support realtime iso transfers. Sorry.");
5093 return(NULL);
5095 if((prt = psdAllocVec(sizeof(struct PsdRTIsoHandler))))
5097 prt->prt_Device = pep->pep_Interface->pif_Config->pc_Device;
5098 prt->prt_Endpoint = pep;
5099 prt->prt_RTIso.urti_OutPrefetch = 2048;
5100 if((pp = prt->prt_Pipe = psdAllocPipe(prt->prt_Device, (struct MsgPort *) 0xffffffff, pep)))
5102 pp->pp_MsgPort = pp->pp_Msg.mn_ReplyPort = NULL;
5103 psdSetAttrsA(PGA_RTISO, prt, tags);
5104 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_ADDISOHANDLER;
5105 pp->pp_IOReq.iouh_Data = &prt->prt_RTIso;
5106 // hardware must support quick IO for this to work!
5107 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5108 if(!ioerr)
5110 Forbid();
5111 AddTail(&prt->prt_Device->pd_RTIsoHandlers, &prt->prt_Node);
5112 Permit();
5113 return(prt);
5114 } else {
5115 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5116 "Adding RT Iso Handler failed: %s (%ld)",
5117 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
5119 psdFreePipe(prt->prt_Pipe);
5121 psdFreeVec(prt);
5123 return(NULL);
5124 AROS_LIBFUNC_EXIT
5126 /* \\\ */
5128 /* /// "psdFreeRTIsoHandler()" */
5129 AROS_LH1(void, psdFreeRTIsoHandler,
5130 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5131 LIBBASETYPEPTR, ps, 94, psd)
5133 AROS_LIBFUNC_INIT
5134 struct PsdPipe *pp;
5136 if(!prt)
5138 return;
5140 Forbid();
5141 Remove(&prt->prt_Node);
5142 Permit();
5143 pp = prt->prt_Pipe;
5144 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_REMISOHANDLER;
5145 DoIO((struct IORequest *) &pp->pp_IOReq);
5146 psdFreePipe(pp);
5147 psdFreeVec(prt);
5148 AROS_LIBFUNC_EXIT
5150 /* \\\ */
5152 /* /// "psdStartRTIso()" */
5153 AROS_LH1(LONG, psdStartRTIso,
5154 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5155 LIBBASETYPEPTR, ps, 95, psd)
5157 AROS_LIBFUNC_INIT
5158 struct PsdPipe *pp;
5159 LONG ioerr;
5161 if(!prt)
5163 return UHIOERR_BADPARAMS;
5165 pp = prt->prt_Pipe;
5166 if(pp->pp_Device->pd_Flags & PDFF_SUSPENDED)
5168 // make sure the device is up and running before trying to send a new pipe
5169 psdResumeDevice(pp->pp_Device);
5171 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STARTRTISO;
5172 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5173 if(!ioerr)
5175 ++pp->pp_Device->pd_IOBusyCount;
5177 return(ioerr);
5178 AROS_LIBFUNC_EXIT
5180 /* \\\ */
5182 /* /// "psdStopRTIso()" */
5183 AROS_LH1(LONG, psdStopRTIso,
5184 AROS_LHA(struct PsdRTIsoHandler *, prt, A1),
5185 LIBBASETYPEPTR, ps, 96, psd)
5187 AROS_LIBFUNC_INIT
5188 struct PsdPipe *pp;
5189 LONG ioerr;
5191 if(!prt)
5193 return UHIOERR_BADPARAMS;
5195 pp = prt->prt_Pipe;
5196 pp->pp_IOReq.iouh_Req.io_Command = UHCMD_STOPRTISO;
5197 ioerr = DoIO((struct IORequest *) &pp->pp_IOReq);
5198 if(!ioerr)
5200 --pp->pp_Device->pd_IOBusyCount;
5202 return(ioerr);
5203 AROS_LIBFUNC_EXIT
5205 /* \\\ */
5207 /* *** Classes *** */
5209 /* /// "psdAddClass()" */
5210 AROS_LH2(struct PsdUsbClass *, psdAddClass,
5211 AROS_LHA(STRPTR, name, A1),
5212 AROS_LHA(ULONG, vers, D0),
5213 LIBBASETYPEPTR, ps, 35, psd)
5215 AROS_LIBFUNC_INIT
5216 struct Library *cls = NULL;
5217 struct PsdUsbClass *puc;
5218 IPTR pri = 0;
5219 STRPTR desc;
5220 UWORD msgoff;
5221 STRPTR origname = name;
5222 STRPTR evilmsg[8] = { "Say hello to %s V%ld.%ld (%s).",
5223 "Whoah! %s V%ld.%ld surprised as %s.",
5224 "The door bell rang for %s V%ld.%ld (%s).",
5225 "Welcome %s V%ld.%ld (%s) to the party.",
5227 "Don't laugh at %s V%ld.%ld for %s.",
5228 "Time has come for %s V%ld.%ld (%s) to join the show.",
5229 "Start blaming %s V%ld.%ld for helping at %s.",
5230 "Ain't %s V%ld.%ld useful for %s?" };
5232 KPRINTF(5, ("psdAddClass(%s, %ld)\n", name, vers));
5234 while(*name)
5236 if((cls = OpenLibrary(name, vers)))
5238 break;
5242 if((*name == '/') || (*name == ':'))
5244 ++name;
5245 break;
5247 } while(*(++name));
5249 if(cls)
5251 Forbid();
5252 if(FindName(&ps->ps_Classes, cls->lib_Node.ln_Name))
5254 Permit();
5255 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
5256 "Attempted to add class %s twice. Nothing is good enough for people like you.",
5257 name);
5258 KPRINTF(20, ("attempt to add class twice!\n"));
5259 CloseLibrary(cls);
5260 return(NULL);
5262 Permit();
5263 if((puc = psdAllocVec(sizeof(struct PsdUsbClass))))
5265 puc->puc_Base = ps;
5266 puc->puc_ClassBase = cls;
5267 puc->puc_Node.ln_Name = puc->puc_ClassName = psdCopyStr(cls->lib_Node.ln_Name);
5268 puc->puc_FullPath = psdCopyStr(origname);
5270 usbGetAttrs(UGA_CLASS, NULL,
5271 UCCA_Priority, &pri,
5272 UCCA_Description, &desc,
5273 TAG_END);
5275 puc->puc_Node.ln_Pri = pri;
5276 psdLockWritePBase();
5277 Enqueue(&ps->ps_Classes, &puc->puc_Node);
5278 psdUnlockPBase();
5279 msgoff = ps->ps_FunnyCount++ & 7;
5281 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5282 evilmsg[msgoff],
5283 cls->lib_Node.ln_Name, cls->lib_Version, cls->lib_Revision, desc);
5284 psdSendEvent(EHMB_ADDCLASS, puc, NULL);
5285 return(puc);
5287 CloseLibrary(cls);
5289 return(NULL);
5290 AROS_LIBFUNC_EXIT
5292 /* \\\ */
5294 /* /// "psdRemClass()" */
5295 AROS_LH1(void, psdRemClass,
5296 AROS_LHA(struct PsdUsbClass *, puc, A1),
5297 LIBBASETYPEPTR, ps, 36, psd)
5299 AROS_LIBFUNC_INIT
5300 KPRINTF(5, ("psdRemClass(%p)\n", puc));
5301 psdLockWritePBase();
5302 Remove(&puc->puc_Node);
5303 psdUnlockPBase();
5305 /* Check if there are still bindings remaining */
5306 while(puc->puc_UseCnt)
5308 struct PsdDevice *pd;
5309 struct PsdConfig *pc;
5310 struct PsdInterface *pif;
5312 KPRINTF(20, ("This should never happen: Class %s still in use (%ld), can't close!\n",
5313 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt));
5315 /* Well, try to release the open bindings in a best effort attempt */
5316 psdLockReadPBase();
5317 pd = NULL;
5318 while((pd = psdGetNextDevice(pd)))
5320 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
5322 psdUnlockPBase();
5323 psdReleaseDevBinding(pd);
5324 psdLockReadPBase();
5325 pd = NULL; /* restart */
5326 continue;
5328 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5329 while(pc->pc_Node.ln_Succ)
5331 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5332 while(pif->pif_Node.ln_Succ)
5334 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
5336 psdUnlockPBase();
5337 psdReleaseIfBinding(pif);
5338 psdLockReadPBase();
5339 pd = NULL; /* restart */
5340 continue;
5342 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5344 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5347 psdUnlockPBase();
5348 if(puc->puc_UseCnt)
5350 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
5351 "This should never happen! Class %s still in use (cnt=%ld). Could not get rid of it! Sorry, we're broke.",
5352 puc->puc_ClassBase->lib_Node.ln_Name, puc->puc_UseCnt);
5354 /*psdDelayMS(2000);*/
5357 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5358 "I shot class %s, but I didn't kill the deputy.",
5359 puc->puc_ClassBase->lib_Node.ln_Name);
5360 CloseLibrary(puc->puc_ClassBase);
5361 psdFreeVec(puc->puc_ClassName);
5362 psdFreeVec(puc->puc_FullPath);
5363 psdFreeVec(puc);
5364 psdSendEvent(EHMB_REMCLASS, puc, NULL);
5365 AROS_LIBFUNC_EXIT
5367 /* \\\ */
5369 /* *** Error Msgs *** */
5371 /* /// "psdAddErrorMsgA()" */
5372 AROS_LH4(struct PsdErrorMsg *, psdAddErrorMsgA,
5373 AROS_LHA(UWORD, level, D0),
5374 AROS_LHA(STRPTR, origin, A0),
5375 AROS_LHA(STRPTR, fmtstr, A1),
5376 AROS_LHA(IPTR *, fmtdata, A2),
5377 LIBBASETYPEPTR, ps, 40, psd)
5379 AROS_LIBFUNC_INIT
5380 struct PsdErrorMsg *pem;
5381 if(((!ps->ps_GlobalCfg->pgc_LogInfo) && (level < RETURN_WARN)) ||
5382 ((!ps->ps_GlobalCfg->pgc_LogWarning) && (level >= RETURN_WARN) && (level < RETURN_ERROR)) ||
5383 ((!ps->ps_GlobalCfg->pgc_LogError) && (level >= RETURN_ERROR) && (level < RETURN_FAIL)) ||
5384 ((!ps->ps_GlobalCfg->pgc_LogFailure) && (level >= RETURN_FAIL)))
5386 return(NULL);
5388 if((pem = psdAllocVec(sizeof(struct PsdErrorMsg))))
5390 pem->pem_Base = ps;
5391 pem->pem_Level = level;
5392 if((pem->pem_Origin = psdCopyStr(origin)))
5394 if((pem->pem_Msg = psdCopyStrFmtA(fmtstr, fmtdata)))
5396 if (ps->ps_Flags & PSF_KLOG) {
5397 KPrintF("[%s] %s\n", origin, pem->pem_Msg);
5400 if(pOpenDOS(ps))
5402 DateStamp(&pem->pem_DateStamp);
5403 } else {
5404 struct timerequest tr = ps->ps_TimerIOReq;
5405 tr.tr_node.io_Command = TR_GETSYSTIME;
5406 DoIO((struct IORequest *) &tr);
5407 pem->pem_DateStamp.ds_Days = tr.tr_time.tv_secs / (24*60*60);
5408 pem->pem_DateStamp.ds_Minute = (tr.tr_time.tv_secs / 60) % 60;
5409 pem->pem_DateStamp.ds_Tick = (tr.tr_time.tv_secs % 60) * 50;
5411 Forbid();
5412 AddTail(&ps->ps_ErrorMsgs, &pem->pem_Node);
5413 Permit();
5414 psdSendEvent(EHMB_ADDERRORMSG, pem, NULL);
5415 return(pem);
5417 psdFreeVec(pem->pem_Origin);
5419 psdFreeVec(pem);
5421 return(NULL);
5422 AROS_LIBFUNC_EXIT
5424 /* \\\ */
5426 /* /// "psdRemErrorMsg()" */
5427 AROS_LH1(void, psdRemErrorMsg,
5428 AROS_LHA(struct PsdErrorMsg *, pem, A0),
5429 LIBBASETYPEPTR, ps, 41, psd)
5431 AROS_LIBFUNC_INIT
5432 KPRINTF(1, ("psdRemErrorMsg()\n"));
5433 Forbid();
5434 Remove(&pem->pem_Node);
5435 Permit();
5436 psdFreeVec(pem->pem_Origin);
5437 psdFreeVec(pem->pem_Msg);
5438 psdFreeVec(pem);
5439 psdSendEvent(EHMB_REMERRORMSG, pem, NULL);
5440 AROS_LIBFUNC_EXIT
5442 /* \\\ */
5444 /* *** Bindings *** */
5446 /* /// "psdClassScan()" */
5447 AROS_LH0(void, psdClassScan,
5448 LIBBASETYPEPTR, ps, 37, psd)
5450 AROS_LIBFUNC_INIT
5451 struct PsdHardware *phw;
5452 struct PsdDevice *pd;
5453 struct PsdUsbClass *puc;
5455 psdLockReadPBase();
5457 if((FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS) && (!ps->ps_ConfigRead))
5459 // it's the first time we were reading the config and DOS was not available
5460 ps->ps_StartedAsTask = TRUE;
5463 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5464 if(!puc->puc_Node.ln_Succ)
5466 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "ClassScan attempted with no classes installed!");
5467 psdUnlockPBase();
5468 return;
5471 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5472 while(phw->phw_Node.ln_Succ)
5474 if((pd = phw->phw_RootDevice))
5476 // for the root, do it ourselves, the rest is done by each hub task
5477 psdHubClassScan(pd);
5479 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5481 psdUnlockPBase();
5482 //psdSendEvent(EHMB_CLSSCANRDY, NULL, NULL);
5483 KPRINTF(5, ("************ Scanning finished!\n"));
5484 AROS_LIBFUNC_EXIT
5486 /* \\\ */
5488 /* /// "psdDoHubMethodA()" */
5489 AROS_LH3(LONG, psdDoHubMethodA,
5490 AROS_LHA(struct PsdDevice *, pd, A0),
5491 AROS_LHA(ULONG, methodid, D0),
5492 AROS_LHA(APTR, methoddata, A1),
5493 LIBBASETYPEPTR, ps, 92, psd)
5495 AROS_LIBFUNC_INIT
5496 struct PsdUsbClass *puc;
5497 KPRINTF(2, ("psdDoHubMethodA(%p)\n", pd));
5499 if(pd)
5501 if(pd->pd_Hub)
5503 if((pd->pd_Hub->pd_DevBinding) && (puc = pd->pd_Hub->pd_ClsBinding))
5505 return(usbDoMethodA(methodid, methoddata));
5509 return 0;
5510 AROS_LIBFUNC_EXIT
5512 /* \\\ */
5514 /* /// "psdClaimAppBindingA()" */
5515 AROS_LH1(struct PsdAppBinding *, psdClaimAppBindingA,
5516 AROS_LHA(struct TagItem *, tags, A1),
5517 LIBBASETYPEPTR, ps, 45, psd)
5519 AROS_LIBFUNC_INIT
5520 struct PsdDevice *pd;
5521 struct PsdConfig *pc;
5522 struct PsdInterface *pif;
5523 struct PsdDevice *hubpd;
5524 struct PsdAppBinding tmppab;
5525 struct PsdAppBinding *pab = NULL;
5526 struct PsdUsbClass *puc;
5528 APTR binding;
5530 KPRINTF(2, ("psdClaimAppBindingA(%p)\n", tags));
5532 tmppab.pab_Device = NULL;
5533 tmppab.pab_ReleaseHook = NULL;
5534 tmppab.pab_Task = NULL;
5535 tmppab.pab_ForceRelease = FALSE;
5536 psdSetAttrsA(PGA_APPBINDING, &tmppab, tags);
5537 if(tmppab.pab_Device && tmppab.pab_ReleaseHook)
5539 pd = tmppab.pab_Device;
5541 // force release of other bindings first
5542 if(tmppab.pab_ForceRelease)
5544 /* If there are bindings, get rid of them. */
5545 if(pd->pd_DevBinding)
5547 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5548 "%s really wants to bind to %s, so I'm letting the old binding go.",
5549 FindTask(NULL)->tc_Node.ln_Name,
5550 pd->pd_ProductStr);
5552 psdReleaseDevBinding(pd);
5553 } else {
5554 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5555 while(pc->pc_Node.ln_Succ)
5557 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5558 while(pif->pif_Node.ln_Succ)
5560 if(pif->pif_IfBinding)
5562 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
5563 "%s really wants to bind to %s, so I'm letting the old binding go.",
5564 FindTask(NULL)->tc_Node.ln_Name,
5565 pd->pd_ProductStr);
5566 psdReleaseIfBinding(pif);
5568 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5570 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5574 hubpd = pd->pd_Hub;
5575 if(!hubpd) // claim app binding at the root hub -- improbable, but possible.
5577 pab = psdHubClaimAppBindingA(tags);
5578 } else {
5579 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5581 pab = (struct PsdAppBinding *) usbDoMethod(UCM_HubClaimAppBinding, binding, tags);
5584 if(pab)
5586 // fill in task names
5587 pab->pab_Task = FindTask(NULL);
5588 pab->pab_Node.ln_Name = pab->pab_Task->tc_Node.ln_Name;
5589 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5590 return(pab);
5593 return(NULL);
5594 AROS_LIBFUNC_EXIT
5596 /* \\\ */
5598 /* /// "psdReleaseAppBinding()" */
5599 AROS_LH1(void, psdReleaseAppBinding,
5600 AROS_LHA(struct PsdAppBinding *, pab, A0),
5601 LIBBASETYPEPTR, ps, 46, psd)
5603 AROS_LIBFUNC_INIT
5604 struct PsdDevice *pd;
5605 struct PsdDevice *hubpd;
5606 struct PsdUsbClass *puc;
5607 APTR binding;
5609 KPRINTF(2, ("psdReleaseAppBinding(%p)\n", pab));
5611 if(pab)
5613 pd = pab->pab_Device;
5614 hubpd = pd->pd_Hub;
5615 if(!hubpd) // release binding of hub (improbable)
5617 psdHubReleaseDevBinding(pd);
5618 return;
5620 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5622 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5625 AROS_LIBFUNC_EXIT
5627 /* \\\ */
5629 /* /// "psdReleaseDevBinding()" */
5630 AROS_LH1(void, psdReleaseDevBinding,
5631 AROS_LHA(struct PsdDevice *, pd, A0),
5632 LIBBASETYPEPTR, ps, 50, psd)
5634 AROS_LIBFUNC_INIT
5635 struct PsdUsbClass *puc;
5636 struct PsdDevice *hubpd;
5637 APTR binding;
5639 KPRINTF(5, ("psdReleaseDevBinding(%p)\n", pd));
5640 if(pd->pd_DevBinding)
5642 hubpd = pd->pd_Hub;
5643 if(!hubpd) // release binding of hub
5645 psdHubReleaseDevBinding(pd);
5646 return;
5648 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5650 usbDoMethod(UCM_HubReleaseDevBinding, binding, pd);
5653 AROS_LIBFUNC_EXIT
5655 /* \\\ */
5657 /* /// "psdReleaseIfBinding()" */
5658 AROS_LH1(void, psdReleaseIfBinding,
5659 AROS_LHA(struct PsdInterface *, pif, A0),
5660 LIBBASETYPEPTR, ps, 51, psd)
5662 AROS_LIBFUNC_INIT
5663 struct PsdUsbClass *puc;
5664 struct PsdDevice *hubpd;
5665 APTR binding;
5667 KPRINTF(5, ("psdReleaseIfBinding(%p)\n", pif));
5668 if(pif->pif_IfBinding && pif->pif_ClsBinding)
5670 hubpd = pif->pif_Config->pc_Device->pd_Hub;
5671 if(!hubpd) // release binding of hub (improbable)
5673 psdHubReleaseIfBinding(pif);
5674 return;
5676 if((binding = hubpd->pd_DevBinding) && (puc = hubpd->pd_ClsBinding))
5678 usbDoMethod(UCM_HubReleaseIfBinding, binding, pif);
5681 AROS_LIBFUNC_EXIT
5683 /* \\\ */
5685 /* /// "psdUnbindAll()" */
5686 AROS_LH0(void, psdUnbindAll,
5687 LIBBASETYPEPTR, ps, 61, psd)
5689 AROS_LIBFUNC_INIT
5690 struct PsdHardware *phw;
5691 struct PsdDevice *pd;
5692 struct PsdConfig *pc;
5693 struct PsdInterface *pif;
5694 BOOL restart;
5696 KPRINTF(10, ("pUnbindAll()\n"));
5697 /* FIXME What happens if devices or hardware gets removed during the process? Need notify semaphore */
5698 psdLockReadPBase();
5701 restart = FALSE;
5702 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
5703 while(phw->phw_Node.ln_Succ)
5705 pd = (struct PsdDevice *) phw->phw_Devices.lh_Head;
5706 while(pd->pd_Node.ln_Succ)
5708 /* If there are bindings, get rid of them. */
5709 if(pd->pd_DevBinding)
5711 psdUnlockPBase();
5712 psdReleaseDevBinding(pd);
5713 psdLockReadPBase();
5714 restart = TRUE;
5715 break;
5717 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5718 while(pc->pc_Node.ln_Succ)
5720 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5721 while(pif->pif_Node.ln_Succ)
5723 if(pif->pif_IfBinding)
5725 psdUnlockPBase();
5726 psdReleaseIfBinding(pif);
5727 psdLockReadPBase();
5728 restart = TRUE;
5729 break;
5731 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5733 if(restart)
5735 break;
5737 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5739 if(restart)
5741 break;
5743 pd = (struct PsdDevice *) pd->pd_Node.ln_Succ;
5745 if(restart)
5747 break;
5749 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
5751 } while(restart);
5752 psdUnlockPBase();
5753 AROS_LIBFUNC_EXIT
5755 /* \\\ */
5757 /* /// "psdHubClassScan()" */
5758 AROS_LH1(void, psdHubClassScan,
5759 AROS_LHA(struct PsdDevice *, pd, A0),
5760 LIBBASETYPEPTR, ps, 82, psd)
5762 AROS_LIBFUNC_INIT
5763 struct PsdUsbClass *puc;
5764 struct PsdConfig *pc;
5765 struct PsdInterface *pif;
5766 struct PsdInterface *firstpif;
5767 struct PsdPipe *pp = NULL;
5768 struct MsgPort *mp;
5769 APTR binding;
5770 UWORD hasifbinding;
5771 BOOL mainif;
5772 STRPTR owner;
5774 KPRINTF(5, ("psdClassScan()\n"));
5776 if(!(mp = CreateMsgPort()))
5778 return;
5780 psdLockReadPBase();
5781 psdLockWriteDevice(pd);
5782 while(!(pd->pd_PoPoCfg.poc_NoClassBind || pd->pd_DevBinding))
5784 if(!(pp = psdAllocPipe(pd, mp, NULL)))
5786 break;
5788 KPRINTF(5, ("Doing ClassScan on Device: %s\n", pd->pd_ProductStr));
5789 hasifbinding = 0;
5790 /* First look if there is any interface binding. We may not change
5791 the current config in this case! */
5792 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5793 while(pc->pc_Node.ln_Succ)
5795 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5797 while(pif->pif_Node.ln_Succ)
5799 if(pif->pif_IfBinding)
5801 hasifbinding = pc->pc_CfgNum;
5802 break;
5804 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5806 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5809 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5810 if((!hasifbinding) && owner)
5812 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5813 while(puc->puc_Node.ln_Succ)
5815 if(!strcmp(owner, puc->puc_ClassName))
5817 if((pd->pd_DevBinding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd)))
5819 pd->pd_ClsBinding = puc;
5820 puc->puc_UseCnt++;
5821 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5822 } else {
5823 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5824 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5826 break;
5828 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5830 /* no more scanning required, abort here */
5831 break;
5834 /* Second attempt */
5835 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
5836 while(pc->pc_Node.ln_Succ)
5838 if((!hasifbinding) || (hasifbinding == pc->pc_CfgNum))
5840 /* If the current config is not the one selected, change it */
5841 if(pd->pd_CurrCfg != pc->pc_CfgNum)
5843 psdSetDeviceConfig(pp, pc->pc_CfgNum);
5845 KPRINTF(5, (" Config %ld\n", pc->pc_CfgNum));
5846 /* If something went wrong above, we must exclude this config */
5847 if(pd->pd_CurrCfg == pc->pc_CfgNum)
5849 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5850 while(pif->pif_Node.ln_Succ)
5852 KPRINTF(5, (" Interface %ld\n", pif->pif_IfNum));
5853 firstpif = pif;
5854 mainif = TRUE;
5855 if(!pif->pif_IfBinding)
5857 binding = NULL;
5860 if(!psdSetAltInterface(pp, pif))
5862 pif->pif_IfBinding = NULL;
5863 /* Okay, this alternate setting failed. Try to get next one */
5864 if(!mainif)
5866 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5867 if(pif->pif_Node.ln_Succ)
5869 KPRINTF(5, ("CONT!\n"));
5870 continue;
5871 } else {
5872 KPRINTF(5, ("BREAK!\n"));
5873 pif = firstpif;
5874 break;
5878 owner = psdGetForcedBinding(pd->pd_IDString, pif->pif_IDString);
5879 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5880 while(puc->puc_Node.ln_Succ)
5882 KPRINTF(5, (">>>PING %s!\n", puc->puc_ClassName));
5883 if(owner)
5885 if(!strcmp(owner, puc->puc_ClassName))
5887 binding = (APTR) usbDoMethod(UCM_ForceInterfaceBinding, pif);
5888 if(!binding)
5890 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5891 "Forced interface binding of %s to %s failed.", pd->pd_ProductStr, owner);
5894 if(!binding)
5896 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5897 continue;
5899 } else {
5900 binding = (APTR) usbDoMethod(UCM_AttemptInterfaceBinding, pif);
5902 Forbid();
5903 KPRINTF(5, ("<<<PONG!!\n"));
5904 if(binding)
5906 KPRINTF(5, ("Got binding!\n"));
5907 /* Find root config structure */
5908 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5909 while(pif->pif_Node.ln_Succ)
5911 if(pif->pif_IfNum == firstpif->pif_IfNum)
5913 break;
5915 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5917 if(!pif->pif_Node.ln_Succ)
5919 KPRINTF(5, ("Fucked it up!\n"));
5920 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Something incredibly stupid happend. I've given up.");
5921 Permit();
5922 break;
5924 pif->pif_IfBinding = binding;
5925 pif->pif_ClsBinding = puc;
5926 hasifbinding = pc->pc_CfgNum;
5927 puc->puc_UseCnt++;
5928 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
5929 Permit();
5930 break;
5932 Permit();
5933 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5935 if(binding)
5937 break;
5939 //break; /* FIXME: DISABLED ALTSCANNING */
5940 /* Check alternate setting */
5941 if(pif->pif_AlterIfs.lh_Head->ln_Succ)
5943 /* There are some alternative interfaces, start at top */
5944 pif = (struct PsdInterface *) pif->pif_AlterIfs.lh_Head;
5945 mainif = FALSE;
5947 } while(pif != firstpif);
5948 //pif->pif_IfBinding = binding;
5949 if(!binding)
5951 psdSetAltInterface(pp, pif);
5953 /* Hohum, search current main interface then */
5954 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
5955 while(pif->pif_Node.ln_Succ)
5957 if(pif->pif_IfNum == firstpif->pif_IfNum)
5959 break;
5961 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5964 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
5968 KPRINTF(5, ("End, next ConfigCheck!\n"));
5969 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
5971 /* Could not establish interface binding, try device binding then */
5972 //psdUnlockPBase();
5973 if(!hasifbinding)
5975 //pd->pd_DevBinding = (APTR) ~0UL;
5976 binding = NULL;
5977 owner = psdGetForcedBinding(pd->pd_IDString, NULL);
5978 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
5979 while(puc->puc_Node.ln_Succ)
5981 binding = NULL;
5982 if(owner)
5984 if(!strcmp(owner, puc->puc_ClassName))
5986 binding = (APTR) usbDoMethod(UCM_ForceDeviceBinding, pd, TAG_END);
5987 if(!binding)
5989 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
5990 "Forced device binding of %s to %s failed.", pd->pd_ProductStr, owner);
5993 if(!binding)
5995 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
5996 continue;
5998 } else {
5999 binding = (APTR) usbDoMethod(UCM_AttemptDeviceBinding, pd);
6001 if(binding)
6003 pd->pd_DevBinding = binding;
6004 pd->pd_ClsBinding = puc;
6005 puc->puc_UseCnt++;
6006 psdSendEvent(EHMB_ADDBINDING, pd, NULL);
6007 break;
6009 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6011 pd->pd_DevBinding = binding;
6013 break;
6015 if(pp)
6017 psdFreePipe(pp);
6019 // call hub class scan code
6020 if((binding = pd->pd_DevBinding) && (puc = pd->pd_ClsBinding))
6022 usbDoMethod(UCM_HubClassScan, binding);
6024 psdUnlockDevice(pd);
6025 psdUnlockPBase();
6026 DeleteMsgPort(mp);
6027 AROS_LIBFUNC_EXIT
6029 /* \\\ */
6031 /* /// "psdHubClaimAppBindingA()" */
6032 AROS_LH1(struct PsdAppBinding *, psdHubClaimAppBindingA,
6033 AROS_LHA(struct TagItem *, tags, A1),
6034 LIBBASETYPEPTR, ps, 83, psd)
6036 AROS_LIBFUNC_INIT
6037 struct PsdDevice *pd;
6038 struct PsdAppBinding *pab;
6039 struct PsdConfig *pc;
6040 struct PsdInterface *pif;
6042 BOOL hasbinding = FALSE;
6043 KPRINTF(2, ("psdHubClaimAppBindingA(%p)\n", tags));
6045 if((pab = psdAllocVec(sizeof(struct PsdAppBinding))))
6047 psdSetAttrsA(PGA_APPBINDING, pab, tags);
6048 if(pab->pab_Device && pab->pab_ReleaseHook)
6050 pd = pab->pab_Device;
6051 if(pd->pd_DevBinding)
6053 hasbinding = TRUE;
6054 } else {
6055 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6056 while(pc->pc_Node.ln_Succ)
6058 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6060 while(pif->pif_Node.ln_Succ)
6062 if(pif->pif_IfBinding)
6064 hasbinding = TRUE;
6065 break;
6067 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6069 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6072 if(!hasbinding)
6074 pd->pd_Flags |= PDFF_APPBINDING;
6075 pd->pd_DevBinding = pab;
6076 pd->pd_ClsBinding = NULL;
6077 return(pab);
6080 psdFreeVec(pab);
6082 return(NULL);
6083 AROS_LIBFUNC_EXIT
6085 /* \\\ */
6087 /* /// "psdHubReleaseDevBinding()" */
6088 AROS_LH1(void, psdHubReleaseDevBinding,
6089 AROS_LHA(struct PsdDevice *, pd, A0),
6090 LIBBASETYPEPTR, ps, 84, psd)
6092 AROS_LIBFUNC_INIT
6093 struct PsdUsbClass *puc;
6094 APTR binding;
6095 struct PsdAppBinding *pab;
6097 KPRINTF(5, ("psdHubReleaseDevBinding(%p)\n", pd));
6098 if(pd)
6100 psdLockWriteDevice(pd);
6101 if((binding = pd->pd_DevBinding))
6103 pd->pd_DevBinding = NULL;
6104 if(pd->pd_Flags & PDFF_APPBINDING)
6106 pab = (struct PsdAppBinding *) binding;
6107 CallHookPkt(pab->pab_ReleaseHook, pab, (APTR) pab->pab_UserData);
6108 pd->pd_ClsBinding = NULL;
6109 pd->pd_Flags &= ~PDFF_APPBINDING;
6110 psdFreeVec(pab);
6111 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6112 } else {
6113 puc = pd->pd_ClsBinding;
6114 if(puc)
6116 pd->pd_ClsBinding = NULL;
6117 usbDoMethod(UCM_ReleaseDeviceBinding, binding);
6118 puc->puc_UseCnt--;
6119 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6123 psdUnlockDevice(pd);
6125 AROS_LIBFUNC_EXIT
6127 /* \\\ */
6129 /* /// "psdHubReleaseIfBinding()" */
6130 AROS_LH1(void, psdHubReleaseIfBinding,
6131 AROS_LHA(struct PsdInterface *, pif, A0),
6132 LIBBASETYPEPTR, ps, 85, psd)
6134 AROS_LIBFUNC_INIT
6135 struct PsdUsbClass *puc;
6136 struct PsdDevice *pd;
6137 APTR binding;
6139 KPRINTF(5, ("psdHubReleaseIfBinding(%p)\n", pif));
6141 if(pif)
6143 pd = pif->pif_Config->pc_Device;
6144 psdLockWriteDevice(pd);
6145 if((binding = pif->pif_IfBinding))
6147 pif->pif_IfBinding = NULL;
6148 puc = pif->pif_ClsBinding;
6149 if(puc)
6151 pif->pif_ClsBinding = NULL;
6152 usbDoMethod(UCM_ReleaseInterfaceBinding, binding);
6153 puc->puc_UseCnt--;
6155 psdSendEvent(EHMB_REMBINDING, pd, NULL);
6157 psdUnlockDevice(pd);
6159 AROS_LIBFUNC_EXIT
6161 /* \\\ */
6163 /* *** Events *** */
6165 /* /// "psdAddEventHandler()" */
6166 AROS_LH2(struct PsdEventHook *, psdAddEventHandler,
6167 AROS_LHA(struct MsgPort *, mp, A1),
6168 AROS_LHA(ULONG, msgmask, D0),
6169 LIBBASETYPEPTR, ps, 47, psd)
6171 AROS_LIBFUNC_INIT
6172 struct PsdEventHook *peh = NULL;
6174 KPRINTF(5, ("psdAddEventHandler(%p, %p)\n", mp, msgmask));
6176 if(mp)
6178 ObtainSemaphore(&ps->ps_ReentrantLock);
6179 if((peh = psdAllocVec(sizeof(struct PsdEventHook))))
6181 peh->peh_MsgPort = mp;
6182 peh->peh_MsgMask = msgmask;
6183 AddTail(&ps->ps_EventHooks, &peh->peh_Node);
6185 ReleaseSemaphore(&ps->ps_ReentrantLock);
6187 return(peh);
6188 AROS_LIBFUNC_EXIT
6190 /* \\\ */
6192 /* /// "psdRemEventHandler()" */
6193 AROS_LH1(void, psdRemEventHandler,
6194 AROS_LHA(struct PsdEventHook *, peh, A0),
6195 LIBBASETYPEPTR, ps, 48, psd)
6197 AROS_LIBFUNC_INIT
6198 struct Message *msg;
6200 KPRINTF(5, ("psdRemEventHandler(%p)\n", peh));
6201 if(!peh)
6203 return;
6205 ObtainSemaphore(&ps->ps_ReentrantLock);
6206 Remove(&peh->peh_Node);
6207 while((msg = GetMsg(peh->peh_MsgPort)))
6209 ReplyMsg(msg);
6211 ReleaseSemaphore(&ps->ps_ReentrantLock);
6212 pGarbageCollectEvents(ps);
6213 psdFreeVec(peh);
6214 AROS_LIBFUNC_EXIT
6216 /* \\\ */
6218 /* /// "psdSendEvent()" */
6219 AROS_LH3(void, psdSendEvent,
6220 AROS_LHA(ULONG, ehmt, D0),
6221 AROS_LHA(APTR, param1, A0),
6222 AROS_LHA(APTR, param2, A1),
6223 LIBBASETYPEPTR, ps, 49, psd)
6225 AROS_LIBFUNC_INIT
6226 struct PsdEventNote *pen;
6227 struct PsdEventHook *peh;
6228 ULONG msgmask = (1L<<ehmt);
6230 KPRINTF(1, ("psdSendEvent(%p, %p, %p)\n", ehmt, param1, param2));
6232 pGarbageCollectEvents(ps);
6233 ObtainSemaphore(&ps->ps_ReentrantLock);
6234 peh = (struct PsdEventHook *) ps->ps_EventHooks.lh_Head;
6235 while(peh->peh_Node.ln_Succ)
6237 if(peh->peh_MsgMask & msgmask)
6239 if((pen = psdAllocVec(sizeof(struct PsdEventNote))))
6241 pen->pen_Msg.mn_ReplyPort = &ps->ps_EventReplyPort;
6242 pen->pen_Msg.mn_Length = sizeof(struct PsdEventNote);
6243 pen->pen_Event = ehmt;
6244 pen->pen_Param1 = param1;
6245 pen->pen_Param2 = param2;
6246 PutMsg(peh->peh_MsgPort, &pen->pen_Msg);
6249 peh = (struct PsdEventHook *) peh->peh_Node.ln_Succ;
6251 ReleaseSemaphore(&ps->ps_ReentrantLock);
6252 AROS_LIBFUNC_EXIT
6254 /* \\\ */
6256 /* *** Configuration *** */
6258 /* /// "psdReadCfg()" */
6259 AROS_LH2(BOOL, psdReadCfg,
6260 AROS_LHA(struct PsdIFFContext *, pic, A0),
6261 AROS_LHA(APTR, formdata, A1),
6262 LIBBASETYPEPTR, ps, 52, psd)
6264 AROS_LIBFUNC_INIT
6265 struct PsdIFFContext *subpic;
6266 LONG len;
6267 ULONG chlen;
6268 ULONG *buf = formdata;
6269 BOOL res = TRUE;
6270 KPRINTF(10, ("psdReadCfg(%p, %p)\n", pic, formdata));
6272 pLockSemExcl(ps, &ps->ps_ConfigLock);
6273 if(!pic)
6275 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6276 if(!(pic->pic_Node.ln_Succ))
6278 pUnlockSem(ps, &ps->ps_ConfigLock);
6279 return(FALSE);
6282 if((AROS_LONG2BE(*buf) != ID_FORM) || (AROS_LONG2BE(buf[2]) != pic->pic_FormID))
6284 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to replace a cfg form with a chunk or with an alien form!");
6285 pUnlockSem(ps, &ps->ps_ConfigLock);
6286 return(FALSE);
6288 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6289 while(subpic->pic_Node.ln_Succ)
6291 pFreeForm(ps, subpic);
6292 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6294 pic->pic_ChunksLen = 0;
6295 len = (AROS_LONG2BE(buf[1]) - 3) & ~1UL;
6296 buf += 3;
6297 while(len >= 8)
6299 if(!(pAddCfgChunk(ps, pic, buf)))
6301 break;
6303 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
6304 len -= chlen;
6305 buf = (ULONG *) (((UBYTE *) buf) + chlen);
6307 if(len)
6309 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
6310 res = 0;
6313 pUnlockSem(ps, &ps->ps_ConfigLock);
6314 ps->ps_CheckConfigReq = TRUE;
6315 return(res);
6316 AROS_LIBFUNC_EXIT
6318 /* \\\ */
6320 /* /// "psdLoadCfgFromDisk()" */
6321 AROS_LH1(BOOL, psdLoadCfgFromDisk,
6322 AROS_LHA(STRPTR, filename, A1),
6323 LIBBASETYPEPTR, ps, 79, psd)
6325 AROS_LIBFUNC_INIT
6326 ULONG *buf;
6327 BOOL loaded = FALSE;
6328 BPTR filehandle;
6329 ULONG formhead[3];
6330 ULONG formlen;
6332 XPRINTF(10, ("Loading config file: %s\n", filename));
6334 if(!filename)
6336 loaded = psdLoadCfgFromDisk("ENV:Sys/poseidon.prefs");
6337 if(loaded)
6339 return(TRUE);
6342 loaded = psdLoadCfgFromDisk("ENVARC:Sys/poseidon.prefs");
6344 return(loaded);
6347 if(!pOpenDOS(ps))
6349 KPRINTF(1, ("dos.library not available yet\n"));
6350 return(FALSE);
6353 filehandle = Open(filename, MODE_OLDFILE);
6354 KPRINTF(1, ("File handle 0x%p\n", filehandle));
6355 if(filehandle)
6357 if(Read(filehandle, formhead, 12) == 12)
6359 KPRINTF(1, ("Read header\n"));
6360 if((AROS_LONG2BE(formhead[0]) == ID_FORM) && (AROS_LONG2BE(formhead[2]) == IFFFORM_PSDCFG))
6362 formlen = AROS_LONG2BE(formhead[1]);
6363 KPRINTF(1, ("Header OK, %lu bytes\n", formlen));
6365 buf = (ULONG *) psdAllocVec(formlen + 8);
6366 if(buf)
6368 buf[0] = formhead[0];
6369 buf[1] = formhead[1];
6370 buf[2] = formhead[2];
6371 if(Read(filehandle, &buf[3], formlen - 4) == formlen - 4)
6373 KPRINTF(1, ("Data read OK\n"));
6375 psdReadCfg(NULL, buf);
6376 psdParseCfg();
6378 KPRINTF(1, ("All done\n"));
6379 loaded = TRUE;
6381 psdFreeVec(buf);
6385 Close(filehandle);
6386 } else {
6387 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6388 "Failed to load config from '%s'!",
6389 filename);
6391 if(loaded)
6393 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6395 return(loaded);
6396 AROS_LIBFUNC_EXIT
6398 /* \\\ */
6400 /* /// "psdSaveCfgToDisk()" */
6401 AROS_LH2(BOOL, psdSaveCfgToDisk,
6402 AROS_LHA(STRPTR, filename, A1),
6403 AROS_LHA(BOOL, executable, D0),
6404 LIBBASETYPEPTR, ps, 80, psd)
6406 AROS_LIBFUNC_INIT
6407 ULONG *buf;
6408 BOOL saved = FALSE;
6409 BPTR filehandle;
6411 if(!filename)
6413 saved = psdSaveCfgToDisk("ENVARC:Sys/poseidon.prefs", FALSE);
6414 saved &= psdSaveCfgToDisk("ENV:Sys/poseidon.prefs", FALSE);
6415 return(saved);
6418 if(!pOpenDOS(ps))
6420 return(FALSE);
6422 pLockSemShared(ps, &ps->ps_ConfigLock);
6424 buf = (ULONG *) psdWriteCfg(NULL);
6425 if(buf)
6427 /* Write file */
6428 filehandle = Open(filename, MODE_NEWFILE);
6429 if(filehandle)
6431 Write(filehandle, buf, (AROS_LONG2BE(buf[1])+9) & ~1UL);
6432 Close(filehandle);
6433 saved = TRUE;
6434 } else {
6435 psdAddErrorMsg(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname),
6436 "Failed to write config to '%s'!",
6437 filename);
6439 psdFreeVec(buf);
6441 pUnlockSem(ps, &ps->ps_ConfigLock);
6442 if(saved)
6444 ps->ps_SavedConfigHash = ps->ps_ConfigHash;
6446 return(saved);
6447 AROS_LIBFUNC_EXIT
6449 /* \\\ */
6451 /* /// "psdWriteCfg()" */
6452 AROS_LH1(APTR, psdWriteCfg,
6453 AROS_LHA(struct PsdIFFContext *, pic, A0),
6454 LIBBASETYPEPTR, ps, 53, psd)
6456 AROS_LIBFUNC_INIT
6457 ULONG len;
6458 APTR buf = NULL;
6460 KPRINTF(10, ("psdWriteCfg(%p)\n", pic));
6462 pLockSemShared(ps, &ps->ps_ConfigLock);
6463 if(!pic)
6465 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6466 if(!(pic->pic_Node.ln_Succ))
6468 pUnlockSem(ps, &ps->ps_ConfigLock);
6469 return(NULL);
6472 pUpdateGlobalCfg(ps, pic);
6473 ps->ps_CheckConfigReq = TRUE;
6474 len = pGetFormLength(pic);
6475 if((buf = psdAllocVec(len)))
6477 pInternalWriteForm(pic, buf);
6479 pUnlockSem(ps, &ps->ps_ConfigLock);
6480 return(buf);
6481 AROS_LIBFUNC_EXIT
6483 /* \\\ */
6485 /* /// "psdFindCfgForm()" */
6486 AROS_LH2(struct PsdIFFContext *, psdFindCfgForm,
6487 AROS_LHA(struct PsdIFFContext *, pic, A0),
6488 AROS_LHA(ULONG, formid, D0),
6489 LIBBASETYPEPTR, ps, 54, psd)
6491 AROS_LIBFUNC_INIT
6492 struct PsdIFFContext *subpic;
6494 KPRINTF(160, ("psdFindCfgForm(0x%p, 0x%08lx)\n", pic, formid));
6495 pLockSemShared(ps, &ps->ps_ConfigLock);
6496 if(!pic)
6498 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6499 if(!(pic->pic_Node.ln_Succ))
6501 pUnlockSem(ps, &ps->ps_ConfigLock);
6502 return(NULL);
6505 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6506 while(subpic->pic_Node.ln_Succ)
6508 if(subpic->pic_FormID == formid)
6510 pUnlockSem(ps, &ps->ps_ConfigLock);
6511 return(subpic);
6513 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
6515 pUnlockSem(ps, &ps->ps_ConfigLock);
6516 return(NULL);
6517 AROS_LIBFUNC_EXIT
6519 /* \\\ */
6521 /* /// "psdNextCfgForm()" */
6522 AROS_LH1(struct PsdIFFContext *, psdNextCfgForm,
6523 AROS_LHA(struct PsdIFFContext *, pic, A0),
6524 LIBBASETYPEPTR, ps, 55, psd)
6526 AROS_LIBFUNC_INIT
6527 ULONG formid;
6528 KPRINTF(160, ("psdNextCfgForm(%p)\n", pic));
6530 if(!pic)
6532 return(NULL);
6534 pLockSemShared(ps, &ps->ps_ConfigLock);
6535 formid = pic->pic_FormID;
6536 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6537 while(pic->pic_Node.ln_Succ)
6539 if(pic->pic_FormID == formid)
6541 pUnlockSem(ps, &ps->ps_ConfigLock);
6543 KPRINTF(1, ("Found context 0x%p\n", pic));
6544 return(pic);
6546 pic = (struct PsdIFFContext *) pic->pic_Node.ln_Succ;
6548 pUnlockSem(ps, &ps->ps_ConfigLock);
6549 return(NULL);
6550 AROS_LIBFUNC_EXIT
6552 /* \\\ */
6554 /* /// "psdAllocCfgForm()" */
6555 AROS_LH1(struct PsdIFFContext *, psdAllocCfgForm,
6556 AROS_LHA(ULONG, formid, D0),
6557 LIBBASETYPEPTR, ps, 86, psd)
6559 AROS_LIBFUNC_INIT
6560 struct PsdIFFContext *pic;
6561 KPRINTF(10, ("psdAllocCfgForm(%p)\n", formid));
6562 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
6564 NewList(&pic->pic_SubForms);
6565 //pic->pic_Parent = parent;
6566 pic->pic_FormID = formid;
6567 pic->pic_FormLength = 4;
6568 pic->pic_Chunks = NULL;
6569 pic->pic_ChunksLen = 0;
6570 pic->pic_BufferLen = 0;
6571 Forbid();
6572 AddTail(&ps->ps_AlienConfigs, &pic->pic_Node);
6573 Permit();
6575 return(pic);
6576 AROS_LIBFUNC_EXIT
6578 /* \\\ */
6580 /* /// "psdRemCfgForm()" */
6581 AROS_LH1(void, psdRemCfgForm,
6582 AROS_LHA(struct PsdIFFContext *, pic, A0),
6583 LIBBASETYPEPTR, ps, 56, psd)
6585 AROS_LIBFUNC_INIT
6586 KPRINTF(10, ("psdRemCfgForm(%p)\n", pic));
6588 pLockSemExcl(ps, &ps->ps_ConfigLock);
6589 if(!pic)
6591 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6592 if(!(pic->pic_Node.ln_Succ))
6594 pUnlockSem(ps, &ps->ps_ConfigLock);
6595 return;
6598 pFreeForm(ps, pic);
6599 pUnlockSem(ps, &ps->ps_ConfigLock);
6600 ps->ps_CheckConfigReq = TRUE;
6601 AROS_LIBFUNC_EXIT
6603 /* \\\ */
6605 /* /// "psdAddCfgEntry()" */
6606 AROS_LH2(struct PsdIFFContext *, psdAddCfgEntry,
6607 AROS_LHA(struct PsdIFFContext *, pic, A0),
6608 AROS_LHA(APTR, formdata, A1),
6609 LIBBASETYPEPTR, ps, 57, psd)
6611 AROS_LIBFUNC_INIT
6612 struct PsdIFFContext *res;
6614 KPRINTF(10, ("psdAddCfgEntry(%p, %p)\n", pic, formdata));
6615 pLockSemExcl(ps, &ps->ps_ConfigLock);
6616 if(!pic)
6618 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6619 if(!(pic->pic_Node.ln_Succ))
6621 pUnlockSem(ps, &ps->ps_ConfigLock);
6622 return(NULL);
6625 res = pAddCfgChunk(ps, pic, formdata);
6626 pUnlockSem(ps, &ps->ps_ConfigLock);
6627 ps->ps_CheckConfigReq = TRUE;
6628 return(res);
6629 AROS_LIBFUNC_EXIT
6631 /* \\\ */
6633 /* /// "psdRemCfgChunk()" */
6634 AROS_LH2(BOOL, psdRemCfgChunk,
6635 AROS_LHA(struct PsdIFFContext *, pic, A0),
6636 AROS_LHA(ULONG, chnkid, D0),
6637 LIBBASETYPEPTR, ps, 58, psd)
6639 AROS_LIBFUNC_INIT
6640 BOOL res = FALSE;
6642 KPRINTF(10, ("psdRemCfgChunk(%p, %p)\n", pic, chnkid));
6643 pLockSemExcl(ps, &ps->ps_ConfigLock);
6644 if(!pic)
6646 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6647 if(!(pic->pic_Node.ln_Succ))
6649 pUnlockSem(ps, &ps->ps_ConfigLock);
6650 return(FALSE);
6653 if(chnkid)
6655 res = pRemCfgChunk(ps, pic, chnkid);
6656 } else {
6657 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6658 while(subpic->pic_Node.ln_Succ)
6660 pFreeForm(ps, subpic);
6661 res = TRUE;
6662 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
6664 if(pic->pic_ChunksLen)
6666 res = TRUE;
6668 pic->pic_ChunksLen = 0;
6669 pic->pic_FormLength = 4;
6672 pUnlockSem(ps, &ps->ps_ConfigLock);
6673 ps->ps_CheckConfigReq = TRUE;
6674 return(res);
6675 AROS_LIBFUNC_EXIT
6677 /* \\\ */
6679 /* /// "psdGetCfgChunk()" */
6680 AROS_LH2(APTR, psdGetCfgChunk,
6681 AROS_LHA(struct PsdIFFContext *, pic, A0),
6682 AROS_LHA(ULONG, chnkid, D0),
6683 LIBBASETYPEPTR, ps, 59, psd)
6685 AROS_LIBFUNC_INIT
6686 ULONG *chnk;
6687 ULONG *res = NULL;
6689 KPRINTF(10, ("psdGetCfgChunk(%p, 0x%08lx)\n", pic, chnkid));
6691 pLockSemShared(ps, &ps->ps_ConfigLock);
6692 if(!pic)
6694 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
6695 if(!(pic->pic_Node.ln_Succ))
6697 pUnlockSem(ps, &ps->ps_ConfigLock);
6698 return(NULL);
6701 pUpdateGlobalCfg(ps, pic);
6702 chnk = pFindCfgChunk(ps, pic, chnkid);
6703 if(chnk)
6705 res = psdAllocVec(AROS_LONG2BE(chnk[1])+8);
6706 if(res)
6708 memcpy(res, chnk, AROS_LONG2BE(chnk[1])+8);
6711 pUnlockSem(ps, &ps->ps_ConfigLock);
6712 return(res);
6713 AROS_LIBFUNC_EXIT
6715 /* \\\ */
6717 /* /// "psdParseCfg()" */
6718 AROS_LH0(void, psdParseCfg,
6719 LIBBASETYPEPTR, ps, 60, psd)
6721 AROS_LIBFUNC_INIT
6722 struct PsdIFFContext *pic;
6723 struct PsdIFFContext *subpic;
6724 ULONG *chnk;
6725 STRPTR name;
6726 ULONG unit;
6727 struct PsdHardware *phw;
6728 struct PsdUsbClass *puc;
6729 BOOL removeall = TRUE;
6730 BOOL nodos = (FindTask(NULL)->tc_Node.ln_Type != NT_PROCESS);
6731 IPTR restartme;
6733 XPRINTF(10, ("psdParseCfg()\n"));
6735 pLockSemShared(ps, &ps->ps_ConfigLock);
6736 pCheckCfgChanged(ps);
6737 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6738 if(!pic)
6740 pUnlockSem(ps, &ps->ps_ConfigLock);
6741 return;
6744 // if no config for hardware is found, we don't remove the devices,
6745 // because this could render the system useless (no USB mice or
6746 // keyboards to configure the hardware!)
6747 if(!psdFindCfgForm(pic, IFFFORM_UHWDEVICE))
6749 XPRINTF(10, ("No hardware data present\n"));
6750 removeall = FALSE;
6753 psdLockReadPBase();
6755 /* select all hardware devices for removal */
6756 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6757 while(phw->phw_Node.ln_Succ)
6759 phw->phw_RemoveMe = removeall;
6760 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6763 /* select all classes for removal */
6764 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6765 while(puc->puc_Node.ln_Succ)
6768 * For kickstart-resident classes we check usage count, and
6769 * remove them only if it's zero.
6770 * These classes can be responsible for devices which we can use
6771 * at boot time. If we happen to remove them, we can end up with
6772 * no input or storage devices at all.
6774 if (FindResident(puc->puc_ClassName))
6775 puc->puc_RemoveMe = (puc->puc_UseCnt == 0);
6776 else
6777 puc->puc_RemoveMe = TRUE;
6779 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6782 psdUnlockPBase();
6784 /* Get Hardware config */
6785 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6786 while(subpic)
6788 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6789 if(chnk)
6791 name = (STRPTR) &chnk[2];
6792 unit = 0;
6793 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6794 if(chnk)
6796 unit = chnk[2];
6798 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6800 phw = pFindHardware(ps, name, unit);
6801 XPRINTF(5, ("Have configuration for device 0x%p (%s unit %u)\n", phw, name, unit));
6802 if(phw)
6804 phw->phw_RemoveMe = FALSE;
6808 subpic = psdNextCfgForm(subpic);
6811 /* Get Class config */
6812 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6813 while(subpic)
6815 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6816 if(chnk)
6818 name = (STRPTR) &chnk[2];
6819 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6820 XPRINTF(5, ("Have configuration for class 0x%p (%s)\n", puc, name));
6821 if(puc)
6823 puc->puc_RemoveMe = FALSE;
6826 subpic = psdNextCfgForm(subpic);
6829 // unlock config while removing to avoid deadlocks.
6830 pUnlockSem(ps, &ps->ps_ConfigLock);
6832 /* now remove remaining classes not found in the config */
6833 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6834 while(puc->puc_Node.ln_Succ)
6836 if(puc->puc_RemoveMe)
6838 XPRINTF(5, ("Removing class %s\n", puc->puc_ClassName));
6839 psdRemClass(puc);
6840 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6841 } else {
6842 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6846 /* now remove all remaining hardware not found in the config */
6847 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6848 while(phw->phw_Node.ln_Succ)
6850 if(phw->phw_RemoveMe)
6852 XPRINTF(5, ("Removing device %s unit %u\n", phw->phw_DevName, phw->phw_Unit));
6853 psdRemHardware(phw);
6854 phw = (struct PsdHardware *) ps->ps_Hardware.lh_Head;
6855 } else {
6856 phw = (struct PsdHardware *) phw->phw_Node.ln_Succ;
6860 pLockSemShared(ps, &ps->ps_ConfigLock);
6861 pic = psdFindCfgForm(NULL, IFFFORM_STACKCFG);
6862 if(!pic)
6864 pUnlockSem(ps, &ps->ps_ConfigLock);
6865 // oops!
6866 return;
6869 /* Add missing Classes */
6870 subpic = psdFindCfgForm(pic, IFFFORM_USBCLASS);
6871 while(subpic)
6873 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6874 if(chnk)
6876 /* *** FIXME *** POSSIBLE DEADLOCK WHEN CLASS TRIES TO DO CONFIG STUFF IN
6877 AN EXTERNAL TASK INSIDE LIBOPEN CODE */
6878 name = (STRPTR) &chnk[2];
6879 puc = (struct PsdUsbClass *) pFindName(ps, &ps->ps_Classes, name);
6880 if(!puc)
6882 psdAddClass(name, 0);
6885 subpic = psdNextCfgForm(subpic);
6888 /* Now really mount Hardware found in config */
6889 subpic = psdFindCfgForm(pic, IFFFORM_UHWDEVICE);
6890 while(subpic)
6892 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_NAME);
6893 if(chnk)
6895 name = (STRPTR) &chnk[2];
6896 unit = 0;
6897 chnk = pFindCfgChunk(ps, subpic, IFFCHNK_UNIT);
6898 if(chnk)
6900 unit = chnk[2];
6902 if(!pFindCfgChunk(ps, subpic, IFFCHNK_OFFLINE))
6904 phw = pFindHardware(ps, name, unit);
6905 if(!phw)
6907 phw = psdAddHardware(name, unit);
6908 if(phw)
6910 psdEnumerateHardware(phw);
6915 subpic = psdNextCfgForm(subpic);
6917 pUnlockSem(ps, &ps->ps_ConfigLock);
6919 if(!nodos && ps->ps_StartedAsTask)
6921 // last time we were reading the config before DOS, so maybe we need to
6922 // unbind some classes that need to be overruled by newly available classes,
6923 // such as hid.class overruling bootmouse & bootkeyboard.
6924 // so unbind those classes that promote themselves as AfterDOS
6926 psdLockReadPBase();
6927 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Checking AfterDOS...");
6928 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
6929 while(puc->puc_Node.ln_Succ)
6931 restartme = FALSE;
6932 usbGetAttrs(UGA_CLASS, NULL,
6933 UCCA_AfterDOSRestart, &restartme,
6934 TAG_END);
6936 if(restartme && puc->puc_UseCnt)
6938 struct PsdDevice *pd;
6939 struct PsdConfig *pc;
6940 struct PsdInterface *pif;
6942 /* Well, try to release the open bindings in a best effort attempt */
6943 pd = NULL;
6944 while((pd = psdGetNextDevice(pd)))
6946 if(pd->pd_DevBinding && (pd->pd_ClsBinding == puc) && (!(pd->pd_Flags & PDFF_APPBINDING)))
6948 psdUnlockPBase();
6949 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6950 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6951 puc->puc_ClassName, "device", pd->pd_ProductStr);
6952 psdReleaseDevBinding(pd);
6953 psdLockReadPBase();
6954 pd = NULL; /* restart */
6955 continue;
6957 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
6958 while(pc->pc_Node.ln_Succ)
6960 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
6961 while(pif->pif_Node.ln_Succ)
6963 if(pif->pif_IfBinding && (pif->pif_ClsBinding == puc))
6965 psdUnlockPBase();
6966 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
6967 "AfterDOS: Temporarily releasing %s %s binding to %s.",
6968 puc->puc_ClassName, "interface", pd->pd_ProductStr);
6969 psdReleaseIfBinding(pif);
6970 psdLockReadPBase();
6971 pd = NULL; /* restart */
6972 continue;
6974 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
6976 pc = (struct PsdConfig *) pc->pc_Node.ln_Succ;
6980 usbDoMethodA(UCM_DOSAvailableEvent, NULL);
6981 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
6983 ps->ps_StartedAsTask = FALSE;
6984 psdUnlockPBase();
6987 if(nodos && (!ps->ps_ConfigRead))
6989 // it's the first time we were reading the config and DOS was not available
6990 ps->ps_StartedAsTask = TRUE;
6992 ps->ps_ConfigRead = TRUE;
6993 ps->ps_SavedConfigHash = ps->ps_ConfigHash; // update saved hash
6995 /* do a class scan */
6996 psdClassScan();
6998 if(nodos && ps->ps_GlobalCfg->pgc_BootDelay)
7000 // wait for hubs to settle
7001 psdDelayMS(1000);
7002 puc = (struct PsdUsbClass *) FindName(&ps->ps_Classes, "massstorage.class");
7003 if(puc && puc->puc_UseCnt)
7005 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
7006 "Delaying further execution by %ld second(s) (boot delay).",
7007 ps->ps_GlobalCfg->pgc_BootDelay);
7008 if(ps->ps_GlobalCfg->pgc_BootDelay >= 1);
7010 psdDelayMS((ps->ps_GlobalCfg->pgc_BootDelay-1)*1000);
7012 } else {
7013 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Boot delay skipped, no mass storage devices found.");
7016 AROS_LIBFUNC_EXIT
7018 /* \\\ */
7020 /* /// "psdSetClsCfg()" */
7021 AROS_LH2(BOOL, psdSetClsCfg,
7022 AROS_LHA(STRPTR, owner, A0),
7023 AROS_LHA(APTR, form, A1),
7024 LIBBASETYPEPTR, ps, 62, psd)
7026 AROS_LIBFUNC_INIT
7027 struct PsdIFFContext *pic;
7028 BOOL result = FALSE;
7030 KPRINTF(10, ("psdSetClsCfg(%s, %p)\n", owner, form));
7031 pLockSemExcl(ps, &ps->ps_ConfigLock);
7032 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7033 while(pic)
7035 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7037 pic = psdFindCfgForm(pic, IFFFORM_CLASSDATA);
7038 if(pic)
7040 if(form)
7042 result = psdReadCfg(pic, form);
7043 } else {
7044 psdRemCfgChunk(pic, 0);
7045 result = TRUE;
7047 break;
7048 } else {
7049 break;
7052 pic = psdNextCfgForm(pic);
7054 if(result)
7056 pUnlockSem(ps, &ps->ps_ConfigLock);
7057 pCheckCfgChanged(ps);
7058 return(result);
7060 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7061 if(pic->pic_Node.ln_Succ)
7063 pic = pAllocForm(ps, pic, IFFFORM_CLASSCFG);
7064 if(pic)
7066 if(pAddStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7068 if(form)
7070 if(pAddCfgChunk(ps, pic, form))
7072 pUnlockSem(ps, &ps->ps_ConfigLock);
7073 pCheckCfgChanged(ps);
7074 return(TRUE);
7076 } else {
7077 ULONG buf[3];
7078 buf[0] = AROS_LONG2BE(ID_FORM);
7079 buf[1] = AROS_LONG2BE(4);
7080 buf[2] = AROS_LONG2BE(IFFFORM_CLASSDATA);
7081 if(pAddCfgChunk(ps, pic, buf))
7083 pUnlockSem(ps, &ps->ps_ConfigLock);
7084 pCheckCfgChanged(ps);
7085 return(TRUE);
7091 pUnlockSem(ps, &ps->ps_ConfigLock);
7092 pCheckCfgChanged(ps);
7093 return(FALSE);
7094 AROS_LIBFUNC_EXIT
7096 /* \\\ */
7098 /* /// "psdGetClsCfg()" */
7099 AROS_LH1(struct PsdIFFContext *, psdGetClsCfg,
7100 AROS_LHA(STRPTR, owner, A0),
7101 LIBBASETYPEPTR, ps, 63, psd)
7103 AROS_LIBFUNC_INIT
7104 struct PsdIFFContext *pic;
7106 KPRINTF(10, ("psdGetClsCfg(%s)\n", owner));
7107 pic = psdFindCfgForm(NULL, IFFFORM_CLASSCFG);
7108 while(pic)
7110 if(pMatchStringChunk(ps, pic, IFFCHNK_OWNER, owner))
7112 return(psdFindCfgForm(pic, IFFFORM_CLASSDATA));
7114 pic = psdNextCfgForm(pic);
7116 return(NULL);
7117 AROS_LIBFUNC_EXIT
7119 /* \\\ */
7121 /* /// "psdSetUsbDevCfg()" */
7122 AROS_LH4(BOOL, psdSetUsbDevCfg,
7123 AROS_LHA(STRPTR, owner, A0),
7124 AROS_LHA(STRPTR, devid, A2),
7125 AROS_LHA(STRPTR, ifid, A3),
7126 AROS_LHA(APTR, form, A1),
7127 LIBBASETYPEPTR, ps, 64, psd)
7129 AROS_LIBFUNC_INIT
7130 struct PsdIFFContext *pic;
7131 struct PsdIFFContext *cpic = NULL;
7132 struct PsdIFFContext *mpic = NULL;
7133 BOOL result = FALSE;
7135 KPRINTF(10, ("psdSetUsbDevCfg(%s, %s, %s, %p)\n", owner, devid, ifid, form));
7136 pLockSemExcl(ps, &ps->ps_ConfigLock);
7137 /* Find device config form. It contains all device config data */
7138 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7139 while(pic)
7141 /* Find DEVID-Chunk. Check if it matches our device id */
7142 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7144 cpic = NULL;
7145 /* We found the correct device. Now if we need to store interface data, find the interface first */
7146 if(ifid)
7148 /* Search interface config form */
7149 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7150 while(mpic)
7152 /* Found the form. Find the the ID String for the interface */
7153 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7155 /* ID did match, now check for owner */
7156 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7158 /* found it! So there is already a config saved in there. Search for dev config data form */
7159 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7160 if(!cpic)
7162 /* not found, generate it */
7163 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7165 break;
7168 mpic = psdNextCfgForm(mpic);
7170 if(!cpic)
7172 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7174 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7176 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7178 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7183 } else {
7184 /* Search for device config */
7185 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7186 while(mpic)
7188 /* search for the right owner */
7189 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7191 /* found it! So there is already a config saved in there. Search for dev config data form */
7192 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7193 if(!cpic)
7195 /* not found, generate it */
7196 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7198 break;
7200 mpic = psdNextCfgForm(mpic);
7202 if(!cpic) /* no device config form */
7204 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7206 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7208 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7213 if(cpic)
7215 if(form)
7217 result = psdReadCfg(cpic, form);
7218 } else {
7219 psdRemCfgChunk(cpic, 0);
7220 result = TRUE;
7222 break;
7225 pic = psdNextCfgForm(pic);
7227 if(result)
7229 pUnlockSem(ps, &ps->ps_ConfigLock);
7230 pCheckCfgChanged(ps);
7231 return(result);
7233 cpic = NULL;
7234 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7235 if(pic->pic_Node.ln_Succ)
7237 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7238 if(pic)
7240 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7242 if(ifid)
7244 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7246 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7248 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7250 cpic = pAllocForm(ps, mpic, IFFFORM_IFCLSDATA);
7254 } else {
7255 if((mpic = pAllocForm(ps, pic, IFFFORM_DEVCFGDATA)))
7257 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7259 cpic = pAllocForm(ps, mpic, IFFFORM_DEVCLSDATA);
7263 if(cpic)
7265 if(form)
7267 result = psdReadCfg(cpic, form);
7268 } else {
7269 psdRemCfgChunk(cpic, 0);
7270 result = TRUE;
7276 pUnlockSem(ps, &ps->ps_ConfigLock);
7277 pCheckCfgChanged(ps);
7278 return(result);
7279 AROS_LIBFUNC_EXIT
7281 /* \\\ */
7283 /* /// "psdGetUsbDevCfg()" */
7284 AROS_LH3(struct PsdIFFContext *, psdGetUsbDevCfg,
7285 AROS_LHA(STRPTR, owner, A0),
7286 AROS_LHA(STRPTR, devid, A2),
7287 AROS_LHA(STRPTR, ifid, A3),
7288 LIBBASETYPEPTR, ps, 65, psd)
7290 AROS_LIBFUNC_INIT
7291 struct PsdIFFContext *pic;
7292 struct PsdIFFContext *cpic = NULL;
7293 struct PsdIFFContext *mpic = NULL;
7295 KPRINTF(10, ("psdGetUsbDevCfg(%s, %s, %s)\n", owner, devid, ifid));
7296 pLockSemShared(ps, &ps->ps_ConfigLock);
7297 /* Find device config form. It contains all device config data */
7298 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7299 while(pic)
7301 /* Find DEVID-Chunk. Check if it matches our device id */
7302 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7304 cpic = NULL;
7305 /* We found the correct device. Now if we need to store interface data, find the interface first */
7306 if(ifid)
7308 /* Search interface config form */
7309 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7310 while(mpic)
7312 /* Found the form. Find the the ID String for the interface */
7313 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7315 /* ID did match, now check for owner */
7316 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7318 /* found it! So there is already a config saved in there. Search for dev config data form */
7319 cpic = psdFindCfgForm(mpic, IFFFORM_IFCLSDATA);
7320 break;
7323 mpic = psdNextCfgForm(mpic);
7325 } else {
7326 /* Search for device config */
7327 mpic = psdFindCfgForm(pic, IFFFORM_DEVCFGDATA);
7328 while(mpic)
7330 /* search for the right owner */
7331 if(pMatchStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7333 /* found it! So there is already a config saved in there. Search for dev config data form */
7334 cpic = psdFindCfgForm(mpic, IFFFORM_DEVCLSDATA);
7335 break;
7337 mpic = psdNextCfgForm(mpic);
7340 break;
7342 pic = psdNextCfgForm(pic);
7344 pUnlockSem(ps, &ps->ps_ConfigLock);
7345 KPRINTF(1, ("Result %p\n", cpic));
7346 return(cpic);
7347 AROS_LIBFUNC_EXIT
7349 /* \\\ */
7351 /* /// "psdSetForcedBinding()" */
7352 AROS_LH3(BOOL, psdSetForcedBinding,
7353 AROS_LHA(STRPTR, owner, A2),
7354 AROS_LHA(STRPTR, devid, A0),
7355 AROS_LHA(STRPTR, ifid, A1),
7356 LIBBASETYPEPTR, ps, 69, psd)
7358 AROS_LIBFUNC_INIT
7359 struct PsdIFFContext *pic;
7360 struct PsdIFFContext *mpic = NULL;
7361 ULONG olen = 0;
7362 BOOL result = FALSE;
7364 if(owner)
7366 olen = strlen(owner);
7368 pLockSemExcl(ps, &ps->ps_ConfigLock);
7369 /* Find device config form. It contains all device config data */
7370 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7371 while(pic)
7373 /* Find DEVID-Chunk. Check if it matches our device id */
7374 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7376 /* We found the correct device. Now if we need to store interface data, find the interface first */
7377 if(ifid)
7379 /* Search interface config form */
7380 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7381 while(mpic)
7383 /* Found the form. Find the the ID String for the interface */
7384 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7386 /* ID did match, insert/replace forced binding */
7387 if(olen)
7389 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7391 result = TRUE;
7393 } else {
7394 pRemCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7395 result = TRUE;
7398 mpic = psdNextCfgForm(mpic);
7400 if(!olen)
7402 result = TRUE;
7404 if((!result) && olen)
7406 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7408 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7410 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7412 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7414 result = TRUE;
7420 } else {
7421 /* Add FBND chunk */
7422 if(olen)
7424 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7426 result = TRUE;
7428 } else {
7429 pRemCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7430 result = TRUE;
7433 break;
7435 pic = psdNextCfgForm(pic);
7437 if(!olen)
7439 result = TRUE;
7441 if(result)
7443 pUnlockSem(ps, &ps->ps_ConfigLock);
7444 pCheckCfgChanged(ps);
7445 return(result);
7447 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7448 if(pic->pic_Node.ln_Succ)
7450 pic = pAllocForm(ps, pic, IFFFORM_DEVICECFG);
7451 if(pic)
7453 if(pAddStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7455 if(ifid)
7457 if((mpic = pAllocForm(ps, pic, IFFFORM_IFCFGDATA)))
7459 if(pAddStringChunk(ps, mpic, IFFCHNK_OWNER, owner))
7461 if(pAddStringChunk(ps, mpic, IFFCHNK_FORCEDBIND, owner))
7463 if(pAddStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7465 result = TRUE;
7470 } else {
7471 /* Add FBND chunk */
7472 if(pAddStringChunk(ps, pic, IFFCHNK_FORCEDBIND, owner))
7474 result = TRUE;
7480 pUnlockSem(ps, &ps->ps_ConfigLock);
7481 pCheckCfgChanged(ps);
7482 return(result);
7483 AROS_LIBFUNC_EXIT
7485 /* \\\ */
7487 /* /// "psdGetForcedBinding()" */
7488 AROS_LH2(STRPTR, psdGetForcedBinding,
7489 AROS_LHA(STRPTR, devid, A0),
7490 AROS_LHA(STRPTR, ifid, A1),
7491 LIBBASETYPEPTR, ps, 70, psd)
7493 AROS_LIBFUNC_INIT
7494 struct PsdIFFContext *pic;
7495 struct PsdIFFContext *mpic = NULL;
7496 ULONG *chunk;
7497 STRPTR owner = NULL;
7499 pLockSemShared(ps, &ps->ps_ConfigLock);
7500 /* Find device config form. It contains all device config data */
7501 pic = psdFindCfgForm(NULL, IFFFORM_DEVICECFG);
7502 while(pic)
7504 /* Find DEVID-Chunk. Check if it matches our device id */
7505 if(pMatchStringChunk(ps, pic, IFFCHNK_DEVID, devid))
7507 /* We found the correct device. Now if we need to store interface data, find the interface first */
7508 if(ifid)
7510 /* Search interface config form */
7511 mpic = psdFindCfgForm(pic, IFFFORM_IFCFGDATA);
7512 while(mpic)
7514 /* Found the form. Find the the ID String for the interface */
7515 if(pMatchStringChunk(ps, mpic, IFFCHNK_IFID, ifid))
7517 /* ID did match, now check for forced binding */
7518 chunk = pFindCfgChunk(ps, mpic, IFFCHNK_FORCEDBIND);
7519 if(chunk)
7521 owner = (STRPTR) &chunk[2];
7522 break;
7525 mpic = psdNextCfgForm(mpic);
7527 } else {
7528 /* Search for device forced binding */
7529 chunk = pFindCfgChunk(ps, pic, IFFCHNK_FORCEDBIND);
7530 if(chunk)
7532 owner = (STRPTR) &chunk[2];
7533 break;
7536 break;
7538 pic = psdNextCfgForm(pic);
7540 pUnlockSem(ps, &ps->ps_ConfigLock);
7541 return(owner);
7542 AROS_LIBFUNC_EXIT
7544 /* \\\ */
7546 /* /// "psdAddStringChunk()" */
7547 AROS_LH3(BOOL, psdAddStringChunk,
7548 AROS_LHA(struct PsdIFFContext *, pic, A0),
7549 AROS_LHA(ULONG, chunkid, D0),
7550 AROS_LHA(CONST_STRPTR, str, A1),
7551 LIBBASETYPEPTR, ps, 87, psd)
7553 AROS_LIBFUNC_INIT
7554 BOOL res;
7555 KPRINTF(10, ("psdAddStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7556 pLockSemExcl(ps, &ps->ps_ConfigLock);
7557 res = pAddStringChunk(ps, pic, chunkid, str);
7558 pUnlockSem(ps, &ps->ps_ConfigLock);
7559 return(res);
7560 AROS_LIBFUNC_EXIT
7562 /* \\\ */
7564 /* /// "psdMatchStringChunk()" */
7565 AROS_LH3(BOOL, psdMatchStringChunk,
7566 AROS_LHA(struct PsdIFFContext *, pic, A0),
7567 AROS_LHA(ULONG, chunkid, D0),
7568 AROS_LHA(CONST_STRPTR, str, A1),
7569 LIBBASETYPEPTR, ps, 88, psd)
7571 AROS_LIBFUNC_INIT
7572 BOOL res;
7573 KPRINTF(10, ("psdMatchStringChunk(%p, %p, %s)\n", pic, chunkid, str));
7574 pLockSemShared(ps, &ps->ps_ConfigLock);
7575 res = pMatchStringChunk(ps, pic, chunkid, str);
7576 pUnlockSem(ps, &ps->ps_ConfigLock);
7577 return(res);
7578 AROS_LIBFUNC_EXIT
7580 /* \\\ */
7582 /* /// "psdGetStringChunk()" */
7583 AROS_LH2(STRPTR, psdGetStringChunk,
7584 AROS_LHA(struct PsdIFFContext *, pic, A0),
7585 AROS_LHA(ULONG, chunkid, D0),
7586 LIBBASETYPEPTR, ps, 89, psd)
7588 AROS_LIBFUNC_INIT
7589 STRPTR str;
7590 KPRINTF(10, ("psdGetStringChunk(%p, %p)\n", pic, chunkid));
7591 pLockSemShared(ps, &ps->ps_ConfigLock);
7592 str = pGetStringChunk(ps, pic, chunkid);
7593 pUnlockSem(ps, &ps->ps_ConfigLock);
7594 return(str);
7595 AROS_LIBFUNC_EXIT
7597 /* \\\ */
7599 /* *** Configuration (non-library subroutines) *** */
7601 /* /// "pAllocForm()" */
7602 struct PsdIFFContext * pAllocForm(LIBBASETYPEPTR ps, struct PsdIFFContext *parent, ULONG formid)
7604 struct PsdIFFContext *pic;
7605 KPRINTF(10, ("pAllocForm(%p, %p)\n", parent, formid));
7606 if((pic = psdAllocVec(sizeof(struct PsdIFFContext))))
7608 NewList(&pic->pic_SubForms);
7609 //pic->pic_Parent = parent;
7610 pic->pic_FormID = formid;
7611 pic->pic_FormLength = 4;
7612 pic->pic_Chunks = NULL;
7613 pic->pic_ChunksLen = 0;
7614 pic->pic_BufferLen = 0;
7615 Forbid();
7616 if(parent)
7618 AddTail(&parent->pic_SubForms, &pic->pic_Node);
7619 } else {
7620 AddTail(&ps->ps_ConfigRoot, &pic->pic_Node);
7622 Permit();
7624 return(pic);
7626 /* \\\ */
7628 /* /// "pFreeForm()" */
7629 void pFreeForm(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7631 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7632 KPRINTF(10, ("pFreeForm(%p)\n", pic));
7633 Remove(&pic->pic_Node);
7634 while(subpic->pic_Node.ln_Succ)
7636 pFreeForm(ps, subpic);
7637 subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7639 psdFreeVec(pic->pic_Chunks);
7640 psdFreeVec(pic);
7642 /* \\\ */
7644 /* /// "pGetFormLength()" */
7645 ULONG pGetFormLength(struct PsdIFFContext *pic)
7647 ULONG len = (5 + pic->pic_ChunksLen) & ~1UL;
7648 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7649 //KPRINTF(10, ("pGetFormLength(%p)\n", pic));
7650 while(subpic->pic_Node.ln_Succ)
7652 len += pGetFormLength(subpic);
7653 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7655 pic->pic_FormLength = len;
7656 //KPRINTF(10, ("FormLen=%ld\n", len+8));
7657 return(len + 8);
7659 /* \\\ */
7661 /* /// "pFindCfgChunk()" */
7662 APTR pFindCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7664 ULONG *buf = pic->pic_Chunks;
7665 ULONG len = pic->pic_ChunksLen;
7666 ULONG chlen;
7667 KPRINTF(10, ("pFindCfgChunk(%p, %p)\n", pic, chnkid));
7669 while(len)
7671 if(AROS_LONG2BE(*buf) == chnkid)
7673 KPRINTF(10, ("Found at %p\n", buf));
7674 return(buf);
7676 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7677 len -= chlen;
7678 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7680 KPRINTF(10, ("Not found!\n"));
7681 return(NULL);
7683 /* \\\ */
7685 /* /// "pRemCfgChunk()" */
7686 BOOL pRemCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chnkid)
7688 ULONG *buf = pic->pic_Chunks;
7689 ULONG len = pic->pic_ChunksLen;
7690 ULONG chlen;
7691 KPRINTF(10, ("pRemCfgChunk(%p, %p)\n", pic, chnkid));
7693 while(len)
7695 chlen = ((AROS_LONG2BE(buf[1])) + 9) & ~1UL;
7696 if(AROS_LONG2BE(*buf) == chnkid)
7698 len -= chlen;
7699 if(len)
7701 memcpy(buf, &((UBYTE *) buf)[chlen], (size_t) len);
7703 pic->pic_ChunksLen -= chlen;
7704 KPRINTF(10, ("Deleted %ld bytes to %ld chunk len\n", chlen, pic->pic_ChunksLen));
7705 return(TRUE);
7707 len -= chlen;
7708 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7710 KPRINTF(10, ("Not found!\n"));
7711 return(FALSE);
7713 /* \\\ */
7715 /* /// "pAddCfgChunk()" */
7716 struct PsdIFFContext * pAddCfgChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, APTR chunk)
7718 LONG len;
7719 LONG chlen;
7720 ULONG *buf = chunk;
7721 ULONG *newbuf;
7722 struct PsdIFFContext *subpic;
7723 KPRINTF(10, ("pAddCfgChunk(%p, %p)\n", pic, chunk));
7724 if(AROS_LONG2BE(*buf) == ID_FORM)
7726 buf++;
7727 len = ((AROS_LONG2BE(*buf)) - 3) & ~1UL;
7728 buf++;
7729 if((subpic = pAllocForm(ps, pic, AROS_LONG2BE(*buf))))
7731 buf++;
7732 while(len >= 8)
7734 if(!(pAddCfgChunk(ps, subpic, buf)))
7736 break;
7738 chlen = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7739 len -= chlen;
7740 buf = (ULONG *) (((UBYTE *) buf) + chlen);
7742 if(len)
7744 psdAddErrorMsg0(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname), "Tried to add a nasty corrupted FORM chunk! Configuration is probably b0rken!");
7745 return(NULL);
7747 } else {
7748 return(NULL);
7750 return(subpic);
7751 } else {
7752 pRemCfgChunk(ps, pic, AROS_LONG2BE(*buf));
7753 len = (AROS_LONG2BE(buf[1]) + 9) & ~1UL;
7754 if(pic->pic_ChunksLen+len > pic->pic_BufferLen)
7756 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));
7758 /* Expand buffer */
7759 if((newbuf = psdAllocVec((pic->pic_ChunksLen+len)<<1)))
7761 if(pic->pic_ChunksLen)
7763 memcpy(newbuf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7764 psdFreeVec(pic->pic_Chunks);
7766 pic->pic_Chunks = newbuf;
7767 pic->pic_BufferLen = (pic->pic_ChunksLen+len)<<1;
7768 } else {
7769 return(NULL);
7772 memcpy(&(((UBYTE *) pic->pic_Chunks)[pic->pic_ChunksLen]), chunk, (size_t) len);
7773 pic->pic_ChunksLen += len;
7774 return(pic);
7777 /* \\\ */
7779 /* /// "pInternalWriteForm()" */
7780 ULONG * pInternalWriteForm(struct PsdIFFContext *pic, ULONG *buf)
7782 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7783 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7784 *buf++ = AROS_LONG2BE(ID_FORM);
7785 *buf++ = AROS_LONG2BE(pic->pic_FormLength);
7786 *buf++ = AROS_LONG2BE(pic->pic_FormID);
7787 if(pic->pic_ChunksLen)
7789 memcpy(buf, pic->pic_Chunks, (size_t) pic->pic_ChunksLen);
7790 buf = (ULONG *) (((UBYTE *) buf) + pic->pic_ChunksLen);
7792 while(subpic->pic_Node.ln_Succ)
7794 buf = pInternalWriteForm(subpic, buf);
7795 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7797 return(buf);
7799 /* \\\ */
7801 /* /// "pCalcCfgCRC()" */
7802 ULONG pCalcCfgCRC(struct PsdIFFContext *pic)
7804 struct PsdIFFContext *subpic = (struct PsdIFFContext *) pic->pic_SubForms.lh_Head;
7805 ULONG len;
7806 ULONG crc = pic->pic_FormID;
7807 UWORD *ptr;
7809 //KPRINTF(10, ("pInternalWriteForm(%p, %p)", pic, buf));
7810 if(pic->pic_ChunksLen)
7812 len = pic->pic_ChunksLen>>1;
7813 if(len)
7815 ptr = (UWORD *) pic->pic_Chunks;
7818 crc = ((crc<<1)|(crc>>31))^(*ptr++);
7819 } while(--len);
7822 while(subpic->pic_Node.ln_Succ)
7824 crc ^= pCalcCfgCRC(subpic);
7825 subpic = (struct PsdIFFContext *) subpic->pic_Node.ln_Succ;
7827 return(crc);
7829 /* \\\ */
7831 /* /// "pCheckCfgChanged()" */
7832 BOOL pCheckCfgChanged(LIBBASETYPEPTR ps)
7834 ULONG crc;
7835 struct PsdIFFContext *pic;
7836 struct PsdIFFContext *subpic;
7837 STRPTR tmpstr;
7839 pLockSemShared(ps, &ps->ps_ConfigLock);
7840 ps->ps_CheckConfigReq = FALSE;
7841 pic = (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head;
7842 if(!(pic->pic_Node.ln_Succ))
7844 pUnlockSem(ps, &ps->ps_ConfigLock);
7845 return(FALSE);
7847 crc = pCalcCfgCRC(pic);
7848 if(crc != ps->ps_ConfigHash)
7850 ULONG *chnk;
7851 ps->ps_ConfigHash = crc;
7852 /* Get Global config */
7853 if((subpic = psdFindCfgForm(pic, IFFFORM_STACKCFG)))
7855 if((chnk = pFindCfgChunk(ps, subpic, IFFCHNK_GLOBALCFG)))
7857 CopyMem(&chnk[2], ((UBYTE *) ps->ps_GlobalCfg) + 8, min(AROS_LONG2BE(chnk[1]), AROS_LONG2BE(ps->ps_GlobalCfg->pgc_Length)));
7859 if(!pMatchStringChunk(ps, subpic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile))
7861 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_INSERTSND)))
7863 psdFreeVec(ps->ps_PoPo.po_InsertSndFile);
7864 ps->ps_PoPo.po_InsertSndFile = tmpstr;
7867 if(!pMatchStringChunk(ps, subpic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile))
7869 if((tmpstr = pGetStringChunk(ps, subpic, IFFCHNK_REMOVESND)))
7871 psdFreeVec(ps->ps_PoPo.po_RemoveSndFile);
7872 ps->ps_PoPo.po_RemoveSndFile = tmpstr;
7876 pUnlockSem(ps, &ps->ps_ConfigLock);
7877 psdSendEvent(EHMB_CONFIGCHG, NULL, NULL);
7878 return(TRUE);
7880 pUnlockSem(ps, &ps->ps_ConfigLock);
7881 return(FALSE);
7883 /* \\\ */
7885 /* /// "pAddStringChunk()" */
7886 BOOL pAddStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7888 BOOL res = FALSE;
7889 ULONG len = strlen(str);
7890 ULONG *chnk = (ULONG *) psdAllocVec((ULONG) len+8+2);
7891 if(chnk)
7893 chnk[0] = AROS_LONG2BE(chunkid);
7894 chnk[1] = AROS_LONG2BE(len+1);
7895 strcpy((STRPTR) &chnk[2], str);
7896 if(pAddCfgChunk(ps, pic, chnk))
7898 res = TRUE;
7900 psdFreeVec(chnk);
7902 return(res);
7904 /* \\\ */
7906 /* /// "pMatchStringChunk()" */
7907 BOOL pMatchStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid, CONST_STRPTR str)
7909 ULONG *chunk;
7910 ULONG len;
7911 STRPTR srcptr;
7912 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7914 srcptr = (STRPTR) &chunk[2];
7915 len = AROS_LONG2BE(chunk[1]);
7916 while(len-- && *srcptr)
7918 if(*str++ != *srcptr++)
7920 return(FALSE);
7923 if(!*str)
7925 return(TRUE);
7928 return(FALSE);
7930 /* \\\ */
7932 /* /// "pGetStringChunk()" */
7933 STRPTR pGetStringChunk(LIBBASETYPEPTR ps, struct PsdIFFContext *pic, ULONG chunkid)
7935 ULONG *chunk;
7936 STRPTR str;
7937 if((chunk = pFindCfgChunk(ps, pic, chunkid)))
7939 if((str = (STRPTR) psdAllocVec(AROS_LONG2BE(chunk[1]) + 1)))
7941 memcpy(str, &chunk[2], (size_t) AROS_LONG2BE(chunk[1]));
7942 return(str);
7945 return(NULL);
7947 /* \\\ */
7949 /* /// "pUpdateGlobalCfg()" */
7950 void pUpdateGlobalCfg(LIBBASETYPEPTR ps, struct PsdIFFContext *pic)
7952 struct PsdIFFContext *tmppic;
7953 /* Set Global config */
7954 if(pic == (struct PsdIFFContext *) ps->ps_ConfigRoot.lh_Head)
7956 if((tmppic = psdFindCfgForm(NULL, IFFFORM_STACKCFG)))
7958 pAddCfgChunk(ps, tmppic, ps->ps_GlobalCfg);
7959 pAddStringChunk(ps, tmppic, IFFCHNK_INSERTSND, ps->ps_PoPo.po_InsertSndFile);
7960 pAddStringChunk(ps, tmppic, IFFCHNK_REMOVESND, ps->ps_PoPo.po_RemoveSndFile);
7964 /* \\\ */
7966 /* *** Misc (non library functions) ***/
7968 /* /// "pGetDevConfig()" */
7969 BOOL pGetDevConfig(struct PsdPipe *pp)
7971 struct PsdDevice *pd = pp->pp_Device;
7972 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
7973 UBYTE *tempbuf;
7974 struct UsbStdCfgDesc uscd;
7975 ULONG len;
7976 LONG ioerr;
7977 STRPTR classname;
7978 UWORD curcfg = 0;
7980 KPRINTF(1, ("Getting configuration descriptor...\n"));
7981 psdLockWriteDevice(pd);
7982 while(curcfg < pd->pd_NumCfgs)
7984 psdPipeSetup(pp, URTF_IN|URTF_STANDARD|URTF_DEVICE,
7985 USR_GET_DESCRIPTOR, (UDT_CONFIGURATION<<8)|curcfg, 0);
7987 /*tempbuf = psdAllocVec(256);
7988 ioerr = psdDoPipe(pp, tempbuf, 34);
7989 if(ioerr == UHIOERR_RUNTPACKET)
7991 ioerr = 0;
7993 memcpy(&uscd, tempbuf, 9);*/
7994 ioerr = psdDoPipe(pp, &uscd, 9);//sizeof(struct UsbStdCfgDesc));
7995 if(!ioerr)
7997 KPRINTF(1, ("Config type: %ld\n", (ULONG) uscd.bDescriptorType));
7998 len = (ULONG) AROS_WORD2LE(uscd.wTotalLength);
7999 KPRINTF(1, ("Configsize %ld, total size %ld\n", (ULONG) uscd.bLength, len));
8000 if((tempbuf = psdAllocVec(len)))
8001 //if(1)
8003 KPRINTF(1, ("Getting whole configuration descriptor...\n"));
8004 ioerr = psdDoPipe(pp, tempbuf, len);
8005 if(!ioerr)
8007 struct PsdConfig *pc = NULL;
8008 struct PsdInterface *pif = NULL;
8009 struct PsdInterface *altif = NULL;
8010 struct PsdEndpoint *pep = NULL;
8011 struct PsdDescriptor *pdd = NULL;
8012 UBYTE *dbuf = tempbuf;
8013 UBYTE *bufend;
8014 ULONG dlen;
8015 bufend = &dbuf[len];
8016 while(dbuf < bufend)
8018 dlen = dbuf[0]; /* bLength */
8019 if(dlen < 2)
8021 break;
8023 if(&dbuf[dlen] > bufend)
8025 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "End of descriptor past buffer!");
8027 switch(dbuf[1]) /* bDescriptorType */
8029 case UDT_CONFIGURATION:
8031 struct UsbStdCfgDesc *usc = (struct UsbStdCfgDesc *) dbuf;
8032 pif = NULL;
8033 altif = NULL;
8034 pep = NULL;
8035 if((pc = pAllocConfig(pd)))
8037 pd->pd_Flags |= PDFF_CONFIGURED;
8038 pc->pc_NumIfs = usc->bNumInterfaces;
8039 pc->pc_CfgNum = usc->bConfigurationValue;
8040 pc->pc_Attr = usc->bmAttributes;
8041 pc->pc_MaxPower = usc->bMaxPower<<1;
8043 KPRINTF(1, (" Config %ld\n", pc->pc_CfgNum));
8044 if(usc->iConfiguration)
8046 pc->pc_CfgStr = psdGetStringDescriptor(pp, usc->iConfiguration);
8048 if(!pc->pc_CfgStr)
8050 pc->pc_CfgStr = psdCopyStrFmt("Configuration %ld", pc->pc_CfgNum);
8052 } else {
8053 KPRINTF(20, (" Config allocation failed\n"));
8055 break;
8058 case UDT_INTERFACE:
8060 struct UsbStdIfDesc *usif = (struct UsbStdIfDesc *) dbuf;
8061 pep = NULL;
8062 if(pc)
8064 if((altif = pAllocInterface(pc)))
8066 altif->pif_IfNum = usif->bInterfaceNumber;
8067 altif->pif_Alternate = usif->bAlternateSetting;
8068 altif->pif_NumEPs = usif->bNumEndpoints;
8069 altif->pif_IfClass = usif->bInterfaceClass;
8070 altif->pif_IfSubClass = usif->bInterfaceSubClass;
8071 altif->pif_IfProto = usif->bInterfaceProtocol;
8072 KPRINTF(2, (" Interface %ld\n", altif->pif_IfNum));
8073 if(usif->iInterface)
8075 altif->pif_IfStr = psdGetStringDescriptor(pp, usif->iInterface);
8077 if(!altif->pif_IfStr)
8079 classname = psdNumToStr(NTS_CLASSCODE, (LONG) altif->pif_IfClass, NULL);
8080 if(classname)
8082 altif->pif_IfStr = psdCopyStrFmt("%s interface (%ld)", classname, altif->pif_IfNum);
8083 } else {
8084 altif->pif_IfStr = psdCopyStrFmt("Interface %ld", altif->pif_IfNum);
8087 KPRINTF(2, (" IfName : %s\n"
8088 " Alternate : %ld\n"
8089 " NumEPs : %ld\n"
8090 " IfClass : %ld\n"
8091 " IfSubClass: %ld\n"
8092 " IfProto : %ld\n",
8093 altif->pif_IfStr, altif->pif_Alternate,
8094 altif->pif_NumEPs,
8095 altif->pif_IfClass,
8096 altif->pif_IfSubClass, altif->pif_IfProto));
8097 if(pc->pc_CfgNum == 1)
8099 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx",
8100 altif->pif_IfNum, altif->pif_Alternate,
8101 altif->pif_IfClass, altif->pif_IfSubClass,
8102 altif->pif_IfProto);
8103 } else {
8104 // for more than one config, add config number (retain backwards compatibility with most devices)
8105 altif->pif_IDString = psdCopyStrFmt("%02lx-%02lx-%02lx-%02lx-%02lx-%02lx",
8106 pc->pc_CfgNum,
8107 altif->pif_IfNum, altif->pif_Alternate,
8108 altif->pif_IfClass, altif->pif_IfSubClass,
8109 altif->pif_IfProto);
8112 /* Move the interface to the alternatives if possible */
8113 if(altif->pif_Alternate)
8115 if(!pif)
8117 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Alternate interface without prior main interface!");
8118 KPRINTF(20, (" Alternate interface without prior main interface\n"));
8119 pif = altif;
8120 } else {
8121 Remove(&altif->pif_Node);
8122 AddTail(&pif->pif_AlterIfs, &altif->pif_Node);
8123 altif->pif_ParentIf = pif;
8125 } else {
8126 altif->pif_ParentIf = NULL;
8127 pif = altif;
8129 } else {
8130 KPRINTF(20, (" Interface allocation failed\n"));
8132 } else {
8133 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Interface without prior config descriptor!");
8134 KPRINTF(20, (" Interface descriptor without Config\n"));
8136 break;
8139 case UDT_ENDPOINT:
8141 struct UsbStdEPDesc *usep = (struct UsbStdEPDesc *) dbuf;
8142 if(altif)
8144 if((pep = pAllocEndpoint(altif)))
8146 STRPTR eptype;
8147 pep->pep_EPNum = usep->bEndpointAddress & 0x0f;
8148 pep->pep_Direction = usep->bEndpointAddress>>7;
8149 pep->pep_TransType = usep->bmAttributes & 0x03;
8150 pep->pep_SyncType = (usep->bmAttributes>>2) & 0x03;
8151 pep->pep_UsageType = (usep->bmAttributes>>4) & 0x03;
8152 eptype = (pep->pep_TransType == USEAF_INTERRUPT) ? "int" : "iso";
8154 pep->pep_MaxPktSize = AROS_WORD2LE(usep->wMaxPacketSize) & 0x07ff;
8155 pep->pep_NumTransMuFr = ((AROS_WORD2LE(usep->wMaxPacketSize)>>11) & 3) + 1;
8156 if(pep->pep_NumTransMuFr == 4)
8158 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains illegal Num Trans µFrame value!");
8159 pep->pep_NumTransMuFr = 1;
8162 pep->pep_Interval = usep->bInterval;
8163 if(pd->pd_Flags & PDFF_HIGHSPEED)
8165 switch(pep->pep_TransType)
8167 case USEAF_CONTROL:
8168 case USEAF_BULK:
8169 //pep->pep_Interval = 0; // no use here, NAK rate not of interest
8170 break;
8172 case USEAF_ISOCHRONOUS:
8173 if(pep->pep_MaxPktSize > 1024)
8175 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8176 "Endpoint contains %s (%ld) MaxPktSize value!",
8177 (STRPTR) "too high", pep->pep_MaxPktSize);
8178 pep->pep_MaxPktSize = 1024;
8181 case USEAF_INTERRUPT:
8182 if(!pep->pep_Interval)
8184 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8185 "%sspeed %s endpoint contains %s interval value! Fixing.",
8186 (STRPTR) "High", eptype, (STRPTR) "zero");
8187 pep->pep_Interval = 1;
8189 else if(pep->pep_Interval > 16)
8191 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8192 "%sspeed %s endpoint contains %s interval value! Fixing.",
8193 (STRPTR) "High", eptype, (STRPTR) "too high");
8194 pep->pep_Interval = 16;
8196 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8197 break;
8200 else if(pd->pd_Flags & PDFF_LOWSPEED)
8202 switch(pep->pep_TransType)
8204 case USEAF_INTERRUPT:
8205 if(pep->pep_Interval < 8)
8207 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8208 (STRPTR) "Low", eptype, (STRPTR) "too low");
8209 pep->pep_Interval = 8;
8211 break;
8213 case USEAF_CONTROL:
8214 case USEAF_BULK:
8215 pep->pep_Interval = 0; // no use here
8216 break;
8218 case USEAF_ISOCHRONOUS:
8219 psdAddErrorMsg0(RETURN_ERROR, (STRPTR) GM_UNIQUENAME(libname), "Lowspeed devices cannot have isochronous endpoints!");
8220 break;
8222 } else {
8223 switch(pep->pep_TransType)
8225 case USEAF_INTERRUPT:
8226 if(!pep->pep_Interval)
8228 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8229 (STRPTR) "Full", eptype, (STRPTR) "zero");
8230 pep->pep_Interval = 1;
8232 break;
8234 case USEAF_CONTROL:
8235 case USEAF_BULK:
8236 pep->pep_Interval = 0; // no use here
8237 break;
8239 case USEAF_ISOCHRONOUS:
8240 if(pep->pep_MaxPktSize > 1023)
8242 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint contains too high (%ld) MaxPktSize value! Fixing.", pep->pep_MaxPktSize);
8243 pep->pep_MaxPktSize = 1023;
8245 if(!pep->pep_Interval)
8247 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8248 (STRPTR) "Full", eptype, (STRPTR) "zero");
8249 pep->pep_Interval = 1;
8251 else if(pep->pep_Interval > 16)
8253 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "%sspeed %s endpoint contains %s interval value! Fixing.",
8254 (STRPTR) "Full", eptype, (STRPTR) "too high");
8255 pep->pep_Interval = 16;
8257 pep->pep_Interval = 1<<(pep->pep_Interval-1);
8258 break;
8262 KPRINTF(2, (" Endpoint %ld\n", pep->pep_EPNum));
8263 KPRINTF(2, (" Direction : %s\n"
8264 " TransType : %ld\n"
8265 " MaxPktSize: %ld\n"
8266 " Interval : %ld\n",
8267 (pep->pep_Direction ? "IN" : "OUT"),
8268 pep->pep_TransType, pep->pep_MaxPktSize,
8269 pep->pep_Interval));
8271 } else {
8272 KPRINTF(20, (" Endpoint allocation failed\n"));
8274 } else {
8275 psdAddErrorMsg0(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Endpoint without prior interface descriptor!");
8276 KPRINTF(20, (" Endpoint descriptor without Interface\n"));
8278 break;
8281 case UDT_DEVICE:
8282 case UDT_HUB:
8283 case UDT_HID:
8284 case UDT_REPORT:
8285 case UDT_PHYSICAL:
8286 case UDT_CS_INTERFACE:
8287 case UDT_CS_ENDPOINT:
8288 case UDT_DEVICE_QUALIFIER:
8289 case UDT_OTHERSPEED_QUALIFIER:
8290 case UDT_INTERFACE_POWER:
8291 case UDT_OTG:
8292 //psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping descriptor %02lx (pc=%p, pif=%p altpif=%p).", dbuf[1], pc, pif, altif);
8293 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8294 break;
8296 default:
8297 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Skipping unknown descriptor %02lx.", dbuf[1]);
8298 KPRINTF(1, ("Skipping unknown descriptor %ld.\n", dbuf[1]));
8299 break;
8301 // add descriptor to device
8302 pdd = pAllocDescriptor(pd, dbuf);
8303 if(pdd)
8305 STRPTR descname = NULL;
8307 pdd->pdd_Config = pc;
8308 pdd->pdd_Interface = altif;
8309 pdd->pdd_Endpoint = pep;
8310 if(pdd->pdd_Interface)
8312 if((pdd->pdd_Type >= UDT_CS_UNDEFINED) && (pdd->pdd_Type <= UDT_CS_ENDPOINT))
8314 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8315 if(!descname)
8317 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pdd->pdd_CSSubType<<24)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8320 if(!descname)
8322 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfSubClass<<16)|(pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8324 if(!descname)
8326 descname = psdNumToStr(NTS_DESCRIPTOR, (LONG) (pif->pif_IfClass<<8)|pdd->pdd_Type, NULL);
8329 if(descname)
8331 pdd->pdd_Name = descname;
8334 dbuf += dlen;
8336 KPRINTF(1, ("Configuration acquired!\n"));
8337 psdFreeVec(tempbuf);
8338 curcfg++;
8339 continue;
8340 //psdUnlockDevice(pd);
8341 //return(TRUE);
8342 } else {
8343 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8344 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8345 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8346 KPRINTF(15, ("GET_DESCRIPTOR failed %ld!\n", ioerr));
8348 psdFreeVec(tempbuf);
8349 } else {
8350 KPRINTF(20, ("No memory for %ld bytes config temp buffer!\n", len));
8352 } else {
8353 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8354 "GET_DESCRIPTOR (len %ld) failed: %s (%ld)",
8355 9, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8356 KPRINTF(15, ("GET_DESCRIPTOR (9) failed %ld!\n", ioerr));
8358 psdUnlockDevice(pd);
8359 return(FALSE);
8361 psdUnlockDevice(pd);
8362 return(TRUE);
8364 /* \\\ */
8366 /* /// "pPowerRecurseDrain()" */
8367 ULONG pPowerRecurseDrain(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8369 struct PsdDevice *nextpd;
8370 struct PsdConfig *pc;
8371 UWORD maxdrain = 666;
8372 UWORD childdrain;
8373 BOOL selfpwd = TRUE;
8374 pd->pd_PowerDrain = 0;
8376 /* look at config */
8377 if((pc = pd->pd_CurrentConfig))
8380 /* if suspended, no more than 500µA are drained */
8381 if(pd->pd_Flags & PDFF_SUSPENDED)
8383 pd->pd_PowerDrain = (pc->pc_MaxPower >= 100) ? 3 : 1;
8384 return(pd->pd_PowerDrain);
8386 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8387 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8388 maxdrain = selfpwd ? 500 : 100;
8391 /* examine children */
8392 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8393 while(nextpd->pd_Node.ln_Succ)
8395 if(nextpd->pd_Hub == pd)
8397 childdrain = pPowerRecurseDrain(ps, nextpd);
8398 // limit the drain to the maximum power suckage
8399 pd->pd_PowerDrain += (childdrain > maxdrain) ? maxdrain : childdrain;
8401 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8404 /* look at config */
8405 if(selfpwd)
8407 pd->pd_PowerDrain = 0;
8408 } else {
8409 pd->pd_PowerDrain += pc->pc_MaxPower;
8411 return(pd->pd_PowerDrain);
8413 /* \\\ */
8415 /* /// "pPowerRecurseSupply()" */
8416 void pPowerRecurseSupply(LIBBASETYPEPTR ps, struct PsdDevice *pd)
8418 struct PsdDevice *nextpd;
8419 struct PsdConfig *pc;
8420 UWORD ports = 0;
8421 UWORD supply = 666;
8422 BOOL selfpwd = TRUE;
8424 /* look at config */
8425 if((pc = pd->pd_CurrentConfig))
8427 selfpwd = ((pc->pc_Attr & USCAF_SELF_POWERED) && (pd->pd_PoPoCfg.poc_OverridePowerInfo != POCP_BUS_POWERED)) ||
8428 (pd->pd_PoPoCfg.poc_OverridePowerInfo == POCP_SELF_POWERED);
8431 /* count children */
8432 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8433 while(nextpd->pd_Node.ln_Succ)
8435 if(nextpd->pd_Hub == pd) // this device is a child of us (we're a hub!)
8437 ports++;
8439 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8442 /* look at config */
8443 if(selfpwd)
8445 if(pc)
8447 pd->pd_PowerSupply = ports ? 500*ports + pc->pc_MaxPower : pc->pc_MaxPower;
8449 supply = 500; // each downstream port gets the full monty
8450 } else {
8451 // the parent hub has already set the amount of supply for this port
8452 if(pd->pd_PowerSupply >= pc->pc_MaxPower)
8454 // the downstream ports get the remaining divided attention
8455 if(ports)
8457 // avoid division by zero
8458 supply = (pd->pd_PowerSupply - pc->pc_MaxPower) / ports;
8459 if(supply > 100)
8461 // limit to 100 mA per port
8462 supply = 100;
8465 } else {
8466 supply = 1; // bad luck, out of power
8470 /* set supply */
8471 if(ports) /* needs to be a hub */
8473 // propagate supply down to the children
8474 nextpd = (struct PsdDevice *) pd->pd_Hardware->phw_Devices.lh_Head;
8475 while(nextpd->pd_Node.ln_Succ)
8477 if(nextpd->pd_Hub == pd)
8479 nextpd->pd_PowerSupply = supply;
8480 pPowerRecurseSupply(ps, nextpd);
8482 nextpd = (struct PsdDevice *) nextpd->pd_Node.ln_Succ;
8485 if(pd->pd_PowerDrain > pd->pd_PowerSupply)
8487 if(!(pd->pd_Flags & PDFF_LOWPOWER))
8489 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8490 "Detected low power condition for '%s'.", pd->pd_ProductStr);
8491 pd->pd_Flags |= PDFF_LOWPOWER;
8492 psdSendEvent(EHMB_DEVICELOWPW, pd, NULL);
8494 } else {
8495 if(pd->pd_Flags & PDFF_LOWPOWER)
8497 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname),
8498 "Low power condition resolved for '%s'.", pd->pd_ProductStr);
8499 pd->pd_Flags &= ~PDFF_LOWPOWER;
8503 /* \\\ */
8505 /* /// "pGarbageCollectEvents()" */
8506 void pGarbageCollectEvents(LIBBASETYPEPTR ps)
8508 struct PsdEventNote *pen;
8509 while((pen = (struct PsdEventNote *) GetMsg(&ps->ps_EventReplyPort)))
8511 psdFreeVec(pen);
8514 /* \\\ */
8516 /* /// "pFindName()" */
8517 struct Node * pFindName(LIBBASETYPEPTR ps, struct List *list, STRPTR name)
8519 struct Node *res = NULL;
8521 Forbid();
8522 while(*name)
8524 res = FindName(list, name);
8525 if(res)
8527 break;
8531 if((*name == '/') || (*name == ':'))
8533 ++name;
8534 break;
8536 } while(*(++name));
8538 Permit();
8539 return(res);
8541 /* \\\ */
8543 /* /// "pStripString()" */
8544 void pStripString(LIBBASETYPEPTR ps, STRPTR str)
8546 STRPTR srcptr = str;
8547 STRPTR tarptr = str;
8548 STRPTR lastgoodchar = str;
8549 BOOL leadingspaces = TRUE;
8550 UBYTE ch;
8551 ULONG len = 0;
8553 while((ch = *srcptr++))
8555 len++;
8556 if(ch == ' ')
8558 if(!leadingspaces)
8560 *tarptr++ = ch;
8562 } else {
8563 *tarptr++ = ch;
8564 lastgoodchar = tarptr;
8565 leadingspaces = FALSE;
8568 *lastgoodchar = 0;
8569 // empty string?
8570 if((str == lastgoodchar) && (len > 6))
8572 strcpy(str, "<empty>");
8575 /* \\\ */
8577 /* /// "pFixBrokenConfig()" */
8578 BOOL pFixBrokenConfig(struct PsdPipe *pp)
8580 struct PsdDevice *pd = pp->pp_Device;
8581 LIBBASETYPEPTR ps = pd->pd_Hardware->phw_Base;
8582 struct PsdConfig *pc;
8583 struct PsdInterface *pif;
8584 BOOL fixed = FALSE;
8586 switch(pd->pd_VendorID)
8588 case 0x03eb: /* Atmel */
8589 if(pd->pd_ProductID == 0x3312)
8591 psdFreeVec(pd->pd_ProductStr);
8592 pd->pd_ProductStr = psdCopyStr("Highway/Subway Root Hub");
8594 break;
8596 case 0x04e6: /* E-Shuttle */
8597 if(pd->pd_ProductID == 0x0001) /* LS120 */
8599 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8600 /* Get msd interface and fix it */
8601 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8602 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8604 fixed = TRUE;
8605 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "E-Shuttle LS120");
8606 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8607 pif->pif_IfSubClass = MS_ATAPI_SUBCLASS;
8608 pif->pif_IfProto = MS_PROTO_CB;
8611 break;
8613 case 0x054C: /* Sony */
8614 if((pd->pd_ProductID == 0x002E) || (pd->pd_ProductID == 0x0010)) /* Handycam */
8616 fixed = TRUE;
8617 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Sony MSD");
8618 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8619 /* Get msd interface and fix it */
8620 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8621 pif->pif_IfSubClass = MS_RBC_SUBCLASS;
8623 break;
8625 case 0x057b: /* Y-E Data */
8626 if(pd->pd_ProductID == 0x0000) /* Flashbuster U */
8628 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8629 /* Get msd interface and fix it */
8630 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8631 if(pif->pif_IfClass != MASSSTORE_CLASSCODE)
8633 fixed = TRUE;
8634 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Y-E Data USB Floppy");
8635 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8636 pif->pif_IfSubClass = MS_UFI_SUBCLASS;
8637 pif->pif_IfProto = (pd->pd_DevVers < 0x0300) ? MS_PROTO_CB : MS_PROTO_CBI;
8640 break;
8642 case 0x04ce: /* ScanLogic */
8643 if(pd->pd_ProductID == 0x0002)
8645 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "ScanLogic");
8646 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8647 /* Get msd interface and fix it */
8648 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8649 fixed = TRUE;
8650 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8652 break;
8654 case 0x0584: /* Ratoc cardreader */
8655 if(pd->pd_ProductID == 0x0008)
8657 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "RATOC");
8658 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8659 /* Get msd interface and fix it */
8660 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8661 fixed = TRUE;
8662 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8663 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8664 pif->pif_IfProto = MS_PROTO_BULK;
8666 break;
8668 case 0x04b8: /* Epson */
8669 if(pd->pd_ProductID == 0x0602) /* EPX Storage device (Card slot in Printer) */
8671 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname), "Fixing broken %s interface descriptor!", (STRPTR) "Epson storage");
8672 pc = (struct PsdConfig *) pd->pd_Configs.lh_Head;
8673 /* Get msd interface and fix it */
8674 pif = (struct PsdInterface *) pc->pc_Interfaces.lh_Head;
8675 fixed = TRUE;
8676 pif->pif_IfClass = MASSSTORE_CLASSCODE;
8677 pif->pif_IfSubClass = MS_SCSI_SUBCLASS;
8678 pif->pif_IfProto = MS_PROTO_BULK;
8680 break;
8682 default:
8683 break;
8685 return(fixed);
8687 /* \\\ */
8689 /* /// "pOpenDOS()" */
8690 BOOL pOpenDOS(LIBBASETYPEPTR ps)
8692 if(DOSBase)
8694 return TRUE;
8696 if((DOSBase = OpenLibrary("dos.library", 39)))
8698 return TRUE;
8700 return FALSE;
8702 /* \\\ */
8704 /* *** Class Scan Task *** */
8706 /* /// "pStartEventHandler()" */
8707 BOOL pStartEventHandler(LIBBASETYPEPTR ps)
8709 struct PsdHandlerTask *ph = &ps->ps_EventHandler;
8711 ObtainSemaphore(&ps->ps_PoPoLock);
8712 if(ph->ph_Task)
8714 ReleaseSemaphore(&ps->ps_PoPoLock);
8715 return(TRUE);
8717 ph->ph_ReadySignal = SIGB_SINGLE;
8718 ph->ph_ReadySigTask = FindTask(NULL);
8719 SetSignal(0, SIGF_SINGLE); // clear single bit
8720 if(psdSpawnSubTask("Poseidon Event Broadcast", pEventHandlerTask, ps))
8722 Wait(1UL<<ph->ph_ReadySignal);
8724 ph->ph_ReadySigTask = NULL;
8725 //FreeSignal(ph->ph_ReadySignal);
8726 if(ph->ph_Task)
8728 ReleaseSemaphore(&ps->ps_PoPoLock);
8729 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Event broadcaster started.");
8730 return(TRUE);
8732 ReleaseSemaphore(&ps->ps_PoPoLock);
8733 return(FALSE);
8735 /* \\\ */
8737 /* *** Hardware Driver Task *** */
8739 /* /// "pQuickForwardRequest()" */
8740 AROS_UFH1(void, pQuickForwardRequest,
8741 AROS_UFHA(struct MsgPort *, msgport, A1))
8743 AROS_USERFUNC_INIT
8744 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8745 struct PsdPipe *pp;
8747 while((pp = (struct PsdPipe *) RemHead(&msgport->mp_MsgList)))
8749 if(pp->pp_AbortPipe)
8751 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8752 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8753 ReplyMsg(&pp->pp_Msg);
8754 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8755 } else {
8756 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8757 pp->pp_IOReq.iouh_UserData = pp;
8758 SendIO((struct IORequest *) &pp->pp_IOReq);
8759 ++phw->phw_MsgCount;
8762 AROS_USERFUNC_EXIT
8764 /* \\\ */
8766 /* /// "pQuickReplyRequest()" */
8767 AROS_UFH1(void, pQuickReplyRequest,
8768 AROS_UFHA(struct MsgPort *, msgport, A1))
8770 AROS_USERFUNC_INIT
8771 struct PsdHardware *phw = (struct PsdHardware *) msgport->mp_Node.ln_Name;
8772 struct IOUsbHWReq *ioreq;
8774 while((ioreq = (struct IOUsbHWReq *) RemHead(&msgport->mp_MsgList)))
8776 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8777 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8778 --phw->phw_MsgCount;
8780 AROS_USERFUNC_EXIT
8782 /* \\\ */
8784 /* /// "pDeviceTask()" */
8785 AROS_UFH0(void, pDeviceTask)
8787 AROS_USERFUNC_INIT
8788 LIBBASETYPEPTR ps;
8789 struct PsdHardware *phw;
8790 struct Task *thistask;
8791 ULONG sigs;
8792 ULONG sigmask;
8793 LONG ioerr;
8794 struct TagItem taglist[11];
8795 struct TagItem *tag;
8796 struct PsdPipe *pp;
8797 struct IOUsbHWReq *ioreq;
8799 STRPTR prodname = NULL;
8800 STRPTR manufacturer = NULL;
8801 STRPTR description = NULL;
8802 STRPTR copyright = NULL;
8803 ULONG version = 0;
8804 ULONG revision = 0;
8805 ULONG driververs = 0x0100;
8806 ULONG caps = UHCF_ISO;
8807 STRPTR devname;
8808 ULONG cnt;
8810 if(!(ps = (LIBBASETYPEPTR) OpenLibrary("poseidon.library", 4)))
8812 Alert(AG_OpenLib);
8813 return;
8815 thistask = FindTask(NULL);
8816 SetTaskPri(thistask, 21);
8817 phw = thistask->tc_UserData;
8819 #ifndef PA_CALLBACK // undocumented exec feature
8820 #define PA_CALLBACK 3
8821 #endif
8823 phw->phw_TaskMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8824 phw->phw_TaskMsgPort.mp_Node.ln_Name = (APTR) phw;
8825 phw->phw_TaskMsgPort.mp_Flags = PA_SIGNAL;
8826 phw->phw_TaskMsgPort.mp_SigTask = thistask;
8827 phw->phw_TaskMsgPort.mp_SigBit = AllocSignal(-1L);
8828 NewList(&phw->phw_TaskMsgPort.mp_MsgList);
8830 phw->phw_DevMsgPort.mp_Node.ln_Type = NT_MSGPORT;
8831 phw->phw_DevMsgPort.mp_Node.ln_Name = (APTR) phw;
8832 phw->phw_DevMsgPort.mp_Flags = PA_SIGNAL;
8833 phw->phw_DevMsgPort.mp_SigTask = thistask;
8834 phw->phw_DevMsgPort.mp_SigBit = AllocSignal(-1L);
8835 NewList(&phw->phw_DevMsgPort.mp_MsgList);
8837 if((phw->phw_RootIOReq = (struct IOUsbHWReq *) CreateIORequest(&phw->phw_DevMsgPort, sizeof(struct IOUsbHWReq))))
8839 devname = phw->phw_DevName;
8840 ioerr = -1;
8841 while(*devname)
8843 if(!(ioerr = OpenDevice(devname, phw->phw_Unit, (struct IORequest *) phw->phw_RootIOReq, 0)))
8845 break;
8849 if((*devname == '/') || (*devname == ':'))
8851 ++devname;
8852 break;
8854 } while(*(++devname));
8857 if(!ioerr)
8859 phw->phw_Node.ln_Name = phw->phw_RootIOReq->iouh_Req.io_Device->dd_Library.lib_Node.ln_Name;
8860 tag = taglist;
8861 tag->ti_Tag = UHA_ProductName;
8862 tag->ti_Data = (IPTR) &prodname;
8863 ++tag;
8864 tag->ti_Tag = UHA_Manufacturer;
8865 tag->ti_Data = (IPTR) &manufacturer;
8866 ++tag;
8867 tag->ti_Tag = UHA_Description;
8868 tag->ti_Data = (IPTR) &description;
8869 ++tag;
8870 tag->ti_Tag = UHA_Version;
8871 tag->ti_Data = (IPTR) &version;
8872 ++tag;
8873 tag->ti_Tag = UHA_Revision;
8874 tag->ti_Data = (IPTR) &revision;
8875 ++tag;
8876 tag->ti_Tag = UHA_Copyright;
8877 tag->ti_Data = (IPTR) &copyright;
8878 ++tag;
8879 tag->ti_Tag = UHA_DriverVersion;
8880 tag->ti_Data = (IPTR) &driververs;
8881 ++tag;
8882 tag->ti_Tag = UHA_Capabilities;
8883 tag->ti_Data = (IPTR) &caps;
8884 ++tag;
8885 tag->ti_Tag = TAG_END;
8886 phw->phw_RootIOReq->iouh_Data = taglist;
8887 phw->phw_RootIOReq->iouh_Req.io_Command = UHCMD_QUERYDEVICE;
8888 DoIO((struct IORequest *) phw->phw_RootIOReq);
8890 phw->phw_ProductName = psdCopyStr(prodname ? prodname : (STRPTR) "n/a");
8891 phw->phw_Manufacturer = psdCopyStr(manufacturer ? manufacturer : (STRPTR) "n/a");
8892 phw->phw_Description = psdCopyStr(description ? description : (STRPTR) "n/a");
8893 phw->phw_Copyright = psdCopyStr(copyright ? copyright : (STRPTR) "n/a");
8894 phw->phw_Version = version;
8895 phw->phw_Revision = revision;
8896 phw->phw_DriverVers = driververs;
8897 phw->phw_Capabilities = caps;
8899 sigmask = SIGBREAKF_CTRL_C;
8900 if(caps & UHCF_QUICKIO)
8902 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Enabling QuickIO for %s.", prodname);
8903 phw->phw_TaskMsgPort.mp_Flags = PA_CALLBACK;
8904 phw->phw_TaskMsgPort.mp_SigTask = (APTR) pQuickForwardRequest;
8906 phw->phw_DevMsgPort.mp_Flags = PA_CALLBACK;
8907 phw->phw_DevMsgPort.mp_SigTask = (APTR) pQuickReplyRequest;
8908 } else {
8909 sigmask |= (1UL<<phw->phw_DevMsgPort.mp_SigBit)|(1UL<<phw->phw_TaskMsgPort.mp_SigBit);
8912 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
8913 phw->phw_Task = thistask;
8915 psdLockWritePBase();
8916 AddTail(&ps->ps_Hardware, &phw->phw_Node);
8917 psdUnlockPBase();
8919 Forbid();
8920 if(phw->phw_ReadySigTask)
8922 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
8924 Permit();
8927 KPRINTF(1, ("Main loop wait.\n"));
8928 while((pp = (struct PsdPipe *) GetMsg(&phw->phw_TaskMsgPort)))
8930 if(pp->pp_AbortPipe)
8932 KPRINTF(2, ("Abort pipe %p\n", pp->pp_AbortPipe));
8933 AbortIO((struct IORequest *) &pp->pp_AbortPipe->pp_IOReq);
8934 ReplyMsg(&pp->pp_Msg);
8935 KPRINTF(2, ("Replying evil pipe %p\n", pp));
8936 } else {
8937 KPRINTF(1, ("Forwarding pipe %p\n", pp));
8938 pp->pp_IOReq.iouh_UserData = pp;
8939 SendIO((struct IORequest *) &pp->pp_IOReq);
8940 ++phw->phw_MsgCount;
8943 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8945 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8946 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8947 --phw->phw_MsgCount;
8949 sigs = Wait(sigmask);
8950 } while(!(sigs & SIGBREAKF_CTRL_C));
8951 /* Flush all pending IO Requests */
8952 phw->phw_RootIOReq->iouh_Req.io_Command = CMD_FLUSH;
8953 DoIO((struct IORequest *) phw->phw_RootIOReq);
8954 cnt = 0;
8955 while(phw->phw_MsgCount)
8957 KPRINTF(20, ("Still %ld iorequests pending!\n", phw->phw_MsgCount));
8958 psdDelayMS(100);
8959 if(++cnt == 50)
8961 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8962 "There are still %ld IORequests pending, before unit can go down. Driver buggy?",
8963 phw->phw_MsgCount);
8965 if(cnt == 300)
8967 psdAddErrorMsg(RETURN_WARN, (STRPTR) GM_UNIQUENAME(libname),
8968 "Okay, I've waited long enough, sod these %ld IORequests.",
8969 phw->phw_MsgCount);
8970 phw->phw_MsgCount = 0;
8971 break;
8973 while((ioreq = (struct IOUsbHWReq *) GetMsg(&phw->phw_DevMsgPort)))
8975 KPRINTF(1, ("Replying pipe %p\n", ioreq->iouh_UserData));
8976 ReplyMsg(&((struct PsdPipe *) ioreq->iouh_UserData)->pp_Msg);
8977 --phw->phw_MsgCount;
8980 psdLockWritePBase();
8981 Remove(&phw->phw_Node);
8982 psdUnlockPBase();
8983 CloseDevice((struct IORequest *) phw->phw_RootIOReq);
8984 } else {
8985 psdAddErrorMsg(RETURN_FAIL, (STRPTR) GM_UNIQUENAME(libname),
8986 "Opening %s unit %ld failed %s (%ld).",
8987 phw->phw_DevName, phw->phw_Unit, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
8989 DeleteIORequest((struct IORequest *) phw->phw_RootIOReq);
8990 phw->phw_RootIOReq = NULL;
8992 FreeSignal((LONG) phw->phw_TaskMsgPort.mp_SigBit);
8993 FreeSignal((LONG) phw->phw_DevMsgPort.mp_SigBit);
8995 CloseLibrary((struct Library *) ps);
8996 phw->phw_Task = NULL;
8998 Forbid();
8999 if(phw->phw_ReadySigTask)
9001 Signal(phw->phw_ReadySigTask, 1L<<phw->phw_ReadySignal);
9003 AROS_USERFUNC_EXIT
9005 /* \\\ */
9007 /* /// "pEventHandlerTask()" */
9008 AROS_UFH0(void, pEventHandlerTask)
9010 AROS_USERFUNC_INIT
9011 LIBBASETYPEPTR ps;
9012 struct Task *thistask;
9013 struct timeval currtime;
9014 ULONG sigs;
9015 ULONG sigmask;
9016 struct PsdUsbClass *puc;
9017 struct PsdHandlerTask *ph;
9018 struct PsdEventNote *pen;
9019 ULONG counter;
9020 ULONG cfgchanged;
9022 thistask = FindTask(NULL);
9023 ps = thistask->tc_UserData;
9024 ph = &ps->ps_EventHandler;
9025 SetTaskPri(thistask, 0);
9027 if((ph->ph_MsgPort = CreateMsgPort()))
9029 if((ph->ph_TimerMsgPort = CreateMsgPort()))
9031 if((ph->ph_TimerIOReq = (struct timerequest *) CreateIORequest(ph->ph_TimerMsgPort, sizeof(struct timerequest))))
9033 if(!(OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) ph->ph_TimerIOReq, 0)))
9035 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
9036 ph->ph_TimerIOReq->tr_node.io_Message.mn_Node.ln_Name = "EventHandler";
9037 ph->ph_TimerIOReq->tr_node.io_Command = TR_ADDREQUEST;
9039 ph->ph_EventHandler = psdAddEventHandler(ph->ph_MsgPort, EHMF_CONFIGCHG);
9040 if(ph->ph_EventHandler)
9042 ph->ph_Task = thistask;
9043 Forbid();
9044 if(ph->ph_ReadySigTask)
9046 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9048 Permit();
9050 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9051 SendIO(&ph->ph_TimerIOReq->tr_node);
9052 sigmask = (1UL<<ph->ph_MsgPort->mp_SigBit)|(1UL<<ph->ph_TimerMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
9053 counter = 0;
9054 cfgchanged = 0;
9057 if(ps->ps_CheckConfigReq)
9059 pCheckCfgChanged(ps);
9061 while((pen = (struct PsdEventNote *) GetMsg(ph->ph_MsgPort)))
9063 switch(pen->pen_Event)
9065 case EHMB_CONFIGCHG:
9066 if(!cfgchanged)
9068 cfgchanged = counter;
9070 break;
9073 ReplyMsg(&pen->pen_Msg);
9075 if(CheckIO(&ph->ph_TimerIOReq->tr_node))
9077 BOOL startpopo;
9078 WaitIO(&ph->ph_TimerIOReq->tr_node);
9079 ph->ph_TimerIOReq->tr_time.tv_micro = 500*1000;
9080 SendIO(&ph->ph_TimerIOReq->tr_node);
9081 counter++;
9082 startpopo = !((counter & 3) || ps->ps_PoPo.po_Task);
9083 if((ps->ps_GlobalCfg->pgc_PopupDeviceNew == PGCP_NEVER) &&
9084 (!ps->ps_GlobalCfg->pgc_PopupDeviceDeath) &&
9085 (!ps->ps_GlobalCfg->pgc_PopupDeviceGone))
9087 startpopo = FALSE; // no need to start popo, no windows wanted
9089 if(startpopo)
9091 struct PsdPoPo *po = &ps->ps_PoPo;
9093 po->po_ReadySignal = SIGB_SINGLE;
9094 po->po_ReadySigTask = FindTask(NULL);
9095 SetSignal(0, SIGF_SINGLE); // clear single bit
9096 if(psdSpawnSubTask("PoPo (Poseidon Popups)", pPoPoGUITask, ps))
9098 Wait(1UL<<po->po_ReadySignal);
9100 po->po_ReadySigTask = NULL;
9101 //FreeSignal(po->po_ReadySignal);
9102 if(po->po_Task)
9104 psdAddErrorMsg0(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "PoPo kicks ass.");
9107 if((cfgchanged + 2) == counter)
9109 KPRINTF(10, ("Sending information about config changed to all classes.\n"));
9110 /* Inform all classes */
9111 psdLockReadPBase();
9112 puc = (struct PsdUsbClass *) ps->ps_Classes.lh_Head;
9113 while(puc->puc_Node.ln_Succ)
9115 usbDoMethod(UCM_ConfigChangedEvent);
9116 puc = (struct PsdUsbClass *) puc->puc_Node.ln_Succ;
9118 psdUnlockPBase();
9119 cfgchanged = 0;
9121 // power saving stuff, check every second
9122 if((counter & 1) && ps->ps_GlobalCfg->pgc_PowerSaving)
9124 struct PsdDevice *pd = NULL;
9125 struct PsdInterface *pif;
9126 GetSysTime((APTR) &currtime);
9127 while((pd = psdGetNextDevice(pd)))
9129 if((pd->pd_DevClass != HUB_CLASSCODE) &&
9130 ((pd->pd_Flags & (PDFF_CONFIGURED|PDFF_DEAD|PDFF_SUSPENDED|PDFF_APPBINDING|PDFF_DELEXPUNGE)) == PDFF_CONFIGURED))
9132 if(pd->pd_LastActivity.tv_secs && ((currtime.tv_secs - pd->pd_LastActivity.tv_secs) > ps->ps_GlobalCfg->pgc_SuspendTimeout))
9134 BOOL doit = TRUE;
9135 IPTR suspendable;
9136 if(!((pd->pd_CurrentConfig->pc_Attr & USCAF_REMOTE_WAKEUP) && ps->ps_GlobalCfg->pgc_ForceSuspend))
9138 if(pd->pd_DevBinding && ((puc = pd->pd_ClsBinding)))
9140 suspendable = 0;
9141 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9142 if(!suspendable)
9144 doit = FALSE;
9147 pif = (struct PsdInterface *) pd->pd_CurrentConfig->pc_Interfaces.lh_Head;
9148 while(pif->pif_Node.ln_Succ)
9150 if(pif->pif_IfBinding && ((puc = pif->pif_ClsBinding)))
9152 suspendable = 0;
9153 usbGetAttrs(UGA_CLASS, NULL, UCCA_SupportsSuspend, &suspendable, TAG_END);
9154 if(!suspendable)
9156 doit = FALSE;
9157 break;
9160 pif = (struct PsdInterface *) pif->pif_Node.ln_Succ;
9163 if(doit)
9165 psdAddErrorMsg(RETURN_OK, (STRPTR) GM_UNIQUENAME(libname), "Suspending '%s'.", pd->pd_ProductStr);
9166 psdSuspendDevice(pd);
9168 pd->pd_LastActivity.tv_secs = 0;
9174 sigs = Wait(sigmask);
9175 } while(!(sigs & SIGBREAKF_CTRL_C));
9176 psdRemEventHandler(ph->ph_EventHandler);
9177 ph->ph_EventHandler = NULL;
9178 AbortIO(&ph->ph_TimerIOReq->tr_node);
9179 WaitIO(&ph->ph_TimerIOReq->tr_node);
9181 CloseDevice((struct IORequest *) ph->ph_TimerIOReq);
9183 DeleteIORequest((struct IORequest *) ph->ph_TimerIOReq);
9185 DeleteMsgPort(ph->ph_TimerMsgPort);
9187 DeleteMsgPort(ph->ph_MsgPort);
9188 ph->ph_MsgPort = NULL;
9190 Forbid();
9191 ph->ph_Task = NULL;
9192 if(ph->ph_ReadySigTask)
9194 Signal(ph->ph_ReadySigTask, 1L<<ph->ph_ReadySignal);
9196 AROS_USERFUNC_EXIT
9198 /* \\\ */
9200 /*****************************************************************/
9202 /* /// "Packtables for psdGetAttrs() and psdSetAttrs() " */
9203 /* Pack table for PsdBase */
9204 static const ULONG PsdBasePT[] =
9206 PACK_STARTTABLE(PA_Dummy),
9207 PACK_ENTRY(PA_Dummy, PA_ConfigRead, PsdBase, ps_ConfigRead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9208 PACK_ENTRY(PA_Dummy, PA_GlobalConfig, PsdBase, ps_GlobalCfg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9209 PACK_ENTRY(PA_Dummy, PA_MemPoolUsage, PsdBase, ps_MemAllocated, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9210 PACK_ENTRY(PA_Dummy, PA_CurrConfigHash, PsdBase, ps_ConfigHash, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9211 PACK_ENTRY(PA_Dummy, PA_SavedConfigHash, PsdBase, ps_SavedConfigHash, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9212 PACK_ENTRY(PA_Dummy, PA_ReleaseVersion, PsdBase, ps_ReleaseVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9213 PACK_ENTRY(PA_Dummy, PA_OSVersion, PsdBase, ps_OSVersion, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9214 PACK_ENDTABLE
9217 /* Pack table for PsdErrorMsg */
9218 static const ULONG PsdErrorMsgPT[] =
9220 PACK_STARTTABLE(EMA_Dummy),
9221 PACK_ENTRY(EMA_Dummy, EMA_Level, PsdErrorMsg, pem_Level, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9222 PACK_ENTRY(EMA_Dummy, EMA_Origin, PsdErrorMsg, pem_Origin, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9223 PACK_ENTRY(EMA_Dummy, EMA_Msg, PsdErrorMsg, pem_Msg, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9224 PACK_ENDTABLE
9227 /* Pack table for PsdUsbClass */
9228 static const ULONG PsdUsbClassPT[] =
9230 PACK_STARTTABLE(UCA_Dummy),
9231 PACK_ENTRY(UCA_Dummy, UCA_ClassBase, PsdUsbClass, puc_ClassBase, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9232 PACK_ENTRY(UCA_Dummy, UCA_ClassName, PsdUsbClass, puc_ClassName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9233 PACK_ENTRY(UCA_Dummy, UCA_FullPath, PsdUsbClass, puc_FullPath, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9234 PACK_ENTRY(UCA_Dummy, UCA_UseCount, PsdUsbClass, puc_UseCnt, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9235 PACK_ENDTABLE
9238 /* Pack table for PsdHardware */
9239 static const ULONG PsdHardwarePT[] =
9241 PACK_STARTTABLE(HA_Dummy),
9242 PACK_ENTRY(HA_Dummy, HA_DeviceName, PsdHardware, phw_DevName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9243 PACK_ENTRY(HA_Dummy, HA_DeviceUnit, PsdHardware, phw_Unit, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9244 PACK_ENTRY(HA_Dummy, HA_ProductName, PsdHardware, phw_ProductName, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9245 PACK_ENTRY(HA_Dummy, HA_Manufacturer, PsdHardware, phw_Manufacturer, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9246 PACK_ENTRY(HA_Dummy, HA_Description, PsdHardware, phw_Description, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9247 PACK_ENTRY(HA_Dummy, HA_Copyright, PsdHardware, phw_Copyright, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9248 PACK_ENTRY(HA_Dummy, HA_Version, PsdHardware, phw_Version, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9249 PACK_ENTRY(HA_Dummy, HA_Revision, PsdHardware, phw_Revision, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9250 PACK_ENTRY(HA_Dummy, HA_DriverVersion, PsdHardware, phw_DriverVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9251 PACK_ENDTABLE
9254 /* Pack table for PsdDevice */
9255 static const ULONG PsdDevicePT[] =
9257 PACK_STARTTABLE(DA_Dummy),
9258 PACK_ENTRY(DA_Dummy, DA_Address, PsdDevice, pd_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9259 PACK_ENTRY(DA_Dummy, DA_NumConfigs, PsdDevice, pd_NumCfgs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9260 PACK_ENTRY(DA_Dummy, DA_CurrConfig, PsdDevice, pd_CurrCfg, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9261 PACK_ENTRY(DA_Dummy, DA_Config, PsdDevice, pd_CurrentConfig, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9262 PACK_ENTRY(DA_Dummy, DA_HubDevice, PsdDevice, pd_Hub, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9263 PACK_ENTRY(DA_Dummy, DA_UsbVersion, PsdDevice, pd_USBVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9264 PACK_ENTRY(DA_Dummy, DA_Class, PsdDevice, pd_DevClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9265 PACK_ENTRY(DA_Dummy, DA_SubClass, PsdDevice, pd_DevSubClass, PKCTRL_WORD|PKCTRL_UNPACKONLY),
9266 PACK_ENTRY(DA_Dummy, DA_Protocol, PsdDevice, pd_DevProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9267 PACK_ENTRY(DA_Dummy, DA_VendorID, PsdDevice, pd_VendorID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9268 PACK_ENTRY(DA_Dummy, DA_MaxPktSize0, PsdDevice, pd_MaxPktSize0, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9269 PACK_ENTRY(DA_Dummy, DA_ProductID, PsdDevice, pd_ProductID, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9270 PACK_ENTRY(DA_Dummy, DA_Version, PsdDevice, pd_DevVers, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9271 PACK_ENTRY(DA_Dummy, DA_Manufacturer, PsdDevice, pd_MnfctrStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9272 PACK_ENTRY(DA_Dummy, DA_ProductName, PsdDevice, pd_ProductStr, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9273 PACK_ENTRY(DA_Dummy, DA_OrigProductName, PsdDevice, pd_OldProductStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9274 PACK_ENTRY(DA_Dummy, DA_SerialNumber, PsdDevice, pd_SerNumStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9275 PACK_ENTRY(DA_Dummy, DA_Hardware, PsdDevice, pd_Hardware, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9276 PACK_ENTRY(DA_Dummy, DA_Binding, PsdDevice, pd_DevBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9277 PACK_ENTRY(DA_Dummy, DA_BindingClass, PsdDevice, pd_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9278 PACK_ENTRY(DA_Dummy, DA_LangIDArray, PsdDevice, pd_LangIDArray, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9279 PACK_ENTRY(DA_Dummy, DA_CurrLangID, PsdDevice, pd_CurrLangID, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9280 PACK_ENTRY(DA_Dummy, DA_IDString, PsdDevice, pd_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9281 PACK_ENTRY(DA_Dummy, DA_CloneCount, PsdDevice, pd_CloneCount, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9282 PACK_ENTRY(DA_Dummy, DA_AtHubPortNumber, PsdDevice, pd_HubPort, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9283 PACK_ENTRY(DA_Dummy, DA_PowerDrained, PsdDevice, pd_PowerDrain, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9284 PACK_ENTRY(DA_Dummy, DA_PowerSupply, PsdDevice, pd_PowerSupply, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9285 PACK_ENTRY(DA_Dummy, DA_IsNewToMe, PsdDevice, pd_IsNewToMe, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9286 PACK_ENTRY(DA_Dummy, DA_InhibitPopup, PsdDevice, pd_PoPoCfg.poc_InhibitPopup, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9287 PACK_ENTRY(DA_Dummy, DA_InhibitClassBind, PsdDevice, pd_PoPoCfg.poc_NoClassBind, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9288 PACK_ENTRY(DA_Dummy, DA_OverridePowerInfo, PsdDevice, pd_PoPoCfg.poc_OverridePowerInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9289 PACK_ENTRY(DA_Dummy, DA_HubThinkTime, PsdDevice, pd_HubThinkTime, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9290 PACK_WORDBIT(DA_Dummy, DA_IsLowspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_LOWSPEED),
9291 PACK_WORDBIT(DA_Dummy, DA_IsHighspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HIGHSPEED),
9292 PACK_WORDBIT(DA_Dummy, DA_IsConnected, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONNECTED),
9293 PACK_WORDBIT(DA_Dummy, DA_HasAddress, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVADDR),
9294 PACK_WORDBIT(DA_Dummy, DA_HasDevDesc, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_HASDEVDESC),
9295 PACK_WORDBIT(DA_Dummy, DA_IsConfigured, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_CONFIGURED),
9296 PACK_WORDBIT(DA_Dummy, DA_IsDead, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_DEAD),
9297 PACK_WORDBIT(DA_Dummy, DA_IsSuspended, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUSPENDED),
9298 PACK_WORDBIT(DA_Dummy, DA_HasAppBinding, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_APPBINDING),
9299 PACK_WORDBIT(DA_Dummy, DA_NeedsSplitTrans, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_NEEDSSPLIT),
9300 PACK_WORDBIT(DA_Dummy, DA_LowPower, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_UNPACKONLY, PDFF_LOWPOWER),
9301 #ifdef AROS_USB30_CODE
9302 PACK_WORDBIT(DA_Dummy, DA_IsSuperspeed, PsdDevice, pd_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PDFF_SUPERSPEED),
9303 #endif
9304 PACK_ENDTABLE
9307 /* Pack table for PsdConfig */
9308 static const ULONG PsdConfigPT[] =
9310 PACK_STARTTABLE(CA_Dummy),
9311 PACK_ENTRY(CA_Dummy, CA_ConfigNum, PsdConfig, pc_CfgNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9312 PACK_ENTRY(CA_Dummy, CA_MaxPower, PsdConfig, pc_MaxPower, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9313 PACK_ENTRY(CA_Dummy, CA_ConfigName, PsdConfig, pc_CfgStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9314 PACK_ENTRY(CA_Dummy, CA_NumInterfaces, PsdConfig, pc_NumIfs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9315 PACK_ENTRY(CA_Dummy, CA_Attrs, PsdConfig, pc_Attr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9316 PACK_ENTRY(CA_Dummy, CA_Device, PsdConfig, pc_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9317 PACK_WORDBIT(CA_Dummy, CA_SelfPowered, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_PACKUNPACK, USCAF_SELF_POWERED),
9318 PACK_WORDBIT(CA_Dummy, CA_RemoteWakeup, PsdConfig, pc_Attr, PKCTRL_BIT|PKCTRL_UNPACKONLY, USCAF_REMOTE_WAKEUP),
9319 PACK_ENDTABLE
9322 /* Pack table for PsdDescriptor */
9323 static const ULONG PsdDescriptorPT[] =
9325 PACK_STARTTABLE(DDA_Dummy),
9326 PACK_ENTRY(DDA_Dummy, DDA_Device, PsdDescriptor, pdd_Device, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9327 PACK_ENTRY(DDA_Dummy, DDA_Config, PsdDescriptor, pdd_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9328 PACK_ENTRY(DDA_Dummy, DDA_Interface, PsdDescriptor, pdd_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9329 PACK_ENTRY(DDA_Dummy, DDA_Endpoint, PsdDescriptor, pdd_Endpoint, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9330 PACK_ENTRY(DDA_Dummy, DDA_Name, PsdDescriptor, pdd_Name, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9331 PACK_ENTRY(DDA_Dummy, DDA_DescriptorType, PsdDescriptor, pdd_Type, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9332 PACK_ENTRY(DDA_Dummy, DDA_CS_SubType, PsdDescriptor, pdd_CSSubType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9333 PACK_ENTRY(DDA_Dummy, DDA_DescriptorData, PsdDescriptor, pdd_Data, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9334 PACK_ENTRY(DDA_Dummy, DDA_DescriptorLength, PsdDescriptor, pdd_Length, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9335 PACK_ENDTABLE
9338 /* Pack table for PsdInterface */
9339 static const ULONG PsdInterfacePT[] =
9341 PACK_STARTTABLE(IFA_Dummy),
9342 PACK_ENTRY(IFA_Dummy, IFA_InterfaceNum, PsdInterface, pif_IfNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9343 PACK_ENTRY(IFA_Dummy, IFA_AlternateNum, PsdInterface, pif_Alternate, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9344 PACK_ENTRY(IFA_Dummy, IFA_NumEndpoints, PsdInterface, pif_NumEPs, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9345 PACK_ENTRY(IFA_Dummy, IFA_Class, PsdInterface, pif_IfClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9346 PACK_ENTRY(IFA_Dummy, IFA_SubClass, PsdInterface, pif_IfSubClass, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9347 PACK_ENTRY(IFA_Dummy, IFA_Protocol, PsdInterface, pif_IfProto, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9348 PACK_ENTRY(IFA_Dummy, IFA_InterfaceName, PsdInterface, pif_IfStr, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9349 PACK_ENTRY(IFA_Dummy, IFA_Config, PsdInterface, pif_Config, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9350 PACK_ENTRY(IFA_Dummy, IFA_Binding, PsdInterface, pif_IfBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9351 PACK_ENTRY(IFA_Dummy, IFA_BindingClass, PsdInterface, pif_ClsBinding, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9352 PACK_ENTRY(IFA_Dummy, IFA_IDString, PsdInterface, pif_IDString, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9353 PACK_ENDTABLE
9356 /* Pack table for PsdEndpoint */
9357 static const ULONG PsdEndpointPT[] =
9359 PACK_STARTTABLE(EA_Dummy),
9360 PACK_ENTRY(EA_Dummy, EA_EndpointNum, PsdEndpoint, pep_EPNum, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9361 PACK_ENTRY(EA_Dummy, EA_TransferType, PsdEndpoint, pep_TransType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9362 PACK_ENTRY(EA_Dummy, EA_MaxPktSize, PsdEndpoint, pep_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9363 PACK_ENTRY(EA_Dummy, EA_Interval, PsdEndpoint, pep_Interval, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9364 PACK_ENTRY(EA_Dummy, EA_NumTransMuFrame, PsdEndpoint, pep_NumTransMuFr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9365 PACK_ENTRY(EA_Dummy, EA_SyncType, PsdEndpoint, pep_SyncType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9366 PACK_ENTRY(EA_Dummy, EA_UsageType, PsdEndpoint, pep_UsageType, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9367 PACK_ENTRY(EA_Dummy, EA_Interface, PsdEndpoint, pep_Interface, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9368 PACK_WORDBIT(EA_Dummy, EA_IsIn, PsdEndpoint, pep_Direction, PKCTRL_BIT|PKCTRL_UNPACKONLY, 1),
9369 PACK_ENDTABLE
9372 /* Pack table for PsdPipe */
9373 static const ULONG PsdPipePT[] =
9375 PACK_STARTTABLE(PPA_Dummy),
9376 PACK_ENTRY(PPA_Dummy, PPA_Endpoint, PsdPipe, pp_Endpoint, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9377 PACK_ENTRY(PPA_Dummy, PPA_Error, PsdPipe, pp_IOReq.iouh_Req.io_Error, PKCTRL_BYTE|PKCTRL_UNPACKONLY),
9378 PACK_ENTRY(PPA_Dummy, PPA_Actual, PsdPipe, pp_IOReq.iouh_Actual, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9379 PACK_ENTRY(PPA_Dummy, PPA_EndpointNum, PsdPipe, pp_IOReq.iouh_Endpoint, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9380 PACK_ENTRY(PPA_Dummy, PPA_DeviceAddress, PsdPipe, pp_IOReq.iouh_DevAddr, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9381 PACK_ENTRY(PPA_Dummy, PPA_MaxPktSize, PsdPipe, pp_IOReq.iouh_MaxPktSize, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9382 PACK_ENTRY(PPA_Dummy, PPA_NakTimeoutTime, PsdPipe, pp_IOReq.iouh_NakTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9383 PACK_ENTRY(PPA_Dummy, PPA_Interval, PsdPipe, pp_IOReq.iouh_Interval, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9384 PACK_WORDBIT(PPA_Dummy, PPA_NoShortPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NOSHORTPKT),
9385 PACK_WORDBIT(PPA_Dummy, PPA_NakTimeout, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_NAKTIMEOUT),
9386 PACK_WORDBIT(PPA_Dummy, PPA_AllowRuntPackets, PsdPipe, pp_IOReq.iouh_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, UHFF_ALLOWRUNTPKTS),
9387 PACK_ENDTABLE
9390 /* Pack table for PsdAppBinding */
9391 static const ULONG PsdAppBindingPT[] =
9393 PACK_STARTTABLE(ABA_Dummy),
9394 PACK_ENTRY(ABA_Dummy, ABA_ReleaseHook, PsdAppBinding, pab_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9395 PACK_ENTRY(ABA_Dummy, ABA_Device, PsdAppBinding, pab_Device, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9396 PACK_ENTRY(ABA_Dummy, ABA_UserData, PsdAppBinding, pab_UserData, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9397 PACK_ENTRY(ABA_Dummy, ABA_Task, PsdAppBinding, pab_Task, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9398 PACK_ENTRY(ABA_Dummy, ABA_ForceRelease, PsdAppBinding, pab_ForceRelease, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9399 PACK_ENDTABLE
9402 /* Pack table for PsdAppBinding */
9403 static const ULONG PsdEventNotePT[] =
9405 PACK_STARTTABLE(ENA_Dummy),
9406 PACK_ENTRY(ENA_Dummy, ENA_EventID, PsdEventNote, pen_Event, PKCTRL_UWORD|PKCTRL_UNPACKONLY),
9407 PACK_ENTRY(ENA_Dummy, ENA_Param1, PsdEventNote, pen_Param1, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9408 PACK_ENTRY(ENA_Dummy, ENA_Param2, PsdEventNote, pen_Param2, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9409 PACK_ENDTABLE
9412 /* Pack table for PsdGlobalCfg */
9413 static const ULONG PsdGlobalCfgPT[] =
9415 PACK_STARTTABLE(GCA_Dummy),
9416 PACK_ENTRY(GCA_Dummy, GCA_LogInfo, PsdGlobalCfg, pgc_LogInfo, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9417 PACK_ENTRY(GCA_Dummy, GCA_LogWarning, PsdGlobalCfg, pgc_LogWarning, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9418 PACK_ENTRY(GCA_Dummy, GCA_LogError, PsdGlobalCfg, pgc_LogError, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9419 PACK_ENTRY(GCA_Dummy, GCA_LogFailure, PsdGlobalCfg, pgc_LogFailure, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9420 PACK_ENTRY(GCA_Dummy, GCA_BootDelay, PsdGlobalCfg, pgc_BootDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9421 PACK_ENTRY(GCA_Dummy, GCA_SubTaskPri, PsdGlobalCfg, pgc_SubTaskPri, PKCTRL_WORD|PKCTRL_PACKUNPACK),
9422 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceNew, PsdGlobalCfg, pgc_PopupDeviceNew, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9423 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceGone, PsdGlobalCfg, pgc_PopupDeviceGone, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9424 PACK_ENTRY(GCA_Dummy, GCA_PopupDeviceDeath, PsdGlobalCfg, pgc_PopupDeviceDeath, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9425 PACK_ENTRY(GCA_Dummy, GCA_PopupCloseDelay, PsdGlobalCfg, pgc_PopupCloseDelay, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9426 PACK_ENTRY(GCA_Dummy, GCA_PopupActivateWin, PsdGlobalCfg, pgc_PopupActivateWin, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9427 PACK_ENTRY(GCA_Dummy, GCA_PopupWinToFront, PsdGlobalCfg, pgc_PopupWinToFront, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9428 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableLP, PsdGlobalCfg, pgc_AutoDisableLP, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9429 PACK_ENTRY(GCA_Dummy, GCA_AutoDisableDead, PsdGlobalCfg, pgc_AutoDisableDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9430 PACK_ENTRY(GCA_Dummy, GCA_AutoRestartDead, PsdGlobalCfg, pgc_AutoRestartDead, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9431 PACK_ENTRY(GCA_Dummy, GCA_PowerSaving, PsdGlobalCfg, pgc_PowerSaving, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9432 PACK_ENTRY(GCA_Dummy, GCA_ForceSuspend, PsdGlobalCfg, pgc_ForceSuspend, PKCTRL_UWORD|PKCTRL_PACKUNPACK),
9433 PACK_ENTRY(GCA_Dummy, GCA_SuspendTimeout, PsdGlobalCfg, pgc_SuspendTimeout, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9434 PACK_ENTRY(GCA_Dummy, GCA_PrefsVersion, PsdGlobalCfg, pgc_PrefsVersion, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9435 PACK_ENDTABLE
9438 /* Pack table for PsdPipeStream */
9439 static const ULONG PsdPipeStreamPT[] =
9441 PACK_STARTTABLE(PSA_Dummy),
9442 PACK_ENTRY(PSA_Dummy, PSA_MessagePort, PsdPipeStream, pps_MsgPort, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9443 PACK_ENTRY(PSA_Dummy, PSA_NumPipes, PsdPipeStream, pps_NumPipes, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9444 PACK_ENTRY(PSA_Dummy, PSA_BufferSize, PsdPipeStream, pps_BufferSize, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9445 PACK_ENTRY(PSA_Dummy, PSA_NakTimeoutTime, PsdPipeStream, pps_NakTimeoutTime, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9446 PACK_ENTRY(PSA_Dummy, PSA_BytesPending, PsdPipeStream, pps_BytesPending, PKCTRL_ULONG|PKCTRL_UNPACKONLY),
9447 PACK_ENTRY(PSA_Dummy, PSA_Error, PsdPipeStream, pps_Error, PKCTRL_LONG|PKCTRL_PACKUNPACK),
9448 PACK_ENTRY(PSA_Dummy, PSA_TermArray, PsdPipeStream, pps_TermArray, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9449 PACK_ENTRY(PSA_Dummy, PSA_AbortSigMask, PsdPipeStream, pps_AbortSigMask, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9450 PACK_ENTRY(PSA_Dummy, PSA_ActivePipe, PsdPipeStream, pps_ActivePipe, PKCTRL_IPTR|PKCTRL_UNPACKONLY),
9451 PACK_WORDBIT(PSA_Dummy, PSA_AsyncIO, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ASYNCIO),
9452 PACK_WORDBIT(PSA_Dummy, PSA_ShortPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_SHORTTERM),
9453 PACK_WORDBIT(PSA_Dummy, PSA_ReadAhead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_READAHEAD),
9454 PACK_WORDBIT(PSA_Dummy, PSA_BufferedRead, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERREAD),
9455 PACK_WORDBIT(PSA_Dummy, PSA_BufferedWrite, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_BUFFERWRITE),
9456 PACK_WORDBIT(PSA_Dummy, PSA_NoZeroPktTerm, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NOSHORTPKT),
9457 PACK_WORDBIT(PSA_Dummy, PSA_NakTimeout, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_NAKTIMEOUT),
9458 PACK_WORDBIT(PSA_Dummy, PSA_AllowRuntPackets, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_ALLOWRUNT),
9459 PACK_WORDBIT(PSA_Dummy, PSA_DoNotWait, PsdPipeStream, pps_Flags, PKCTRL_BIT|PKCTRL_PACKUNPACK, PSFF_DONOTWAIT),
9460 PACK_ENDTABLE
9463 /* Pack table for PsdRTIsoHandler */
9464 static const ULONG PsdRTIsoHandlerPT[] =
9466 PACK_STARTTABLE(RTA_Dummy),
9467 PACK_ENTRY(RTA_Dummy, RTA_InRequestHook, PsdRTIsoHandler, prt_RTIso.urti_InReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9468 PACK_ENTRY(RTA_Dummy, RTA_OutRequestHook, PsdRTIsoHandler, prt_RTIso.urti_OutReqHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9469 PACK_ENTRY(RTA_Dummy, RTA_InDoneHook, PsdRTIsoHandler, prt_RTIso.urti_InDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9470 PACK_ENTRY(RTA_Dummy, RTA_OutDoneHook, PsdRTIsoHandler, prt_RTIso.urti_OutDoneHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9471 PACK_ENTRY(RTA_Dummy, RTA_ReleaseHook, PsdRTIsoHandler, prt_ReleaseHook, PKCTRL_IPTR|PKCTRL_PACKUNPACK),
9472 PACK_ENTRY(RTA_Dummy, RTA_OutPrefetchSize, PsdRTIsoHandler, prt_RTIso.urti_OutPrefetch, PKCTRL_ULONG|PKCTRL_PACKUNPACK),
9473 PACK_ENDTABLE
9476 /* PGA assignment table */
9477 static const ULONG *PsdPTArray[] =
9479 NULL,
9480 PsdBasePT,
9481 PsdUsbClassPT,
9482 PsdHardwarePT,
9483 PsdDevicePT,
9484 PsdConfigPT,
9485 PsdInterfacePT,
9486 PsdEndpointPT,
9487 PsdErrorMsgPT,
9488 PsdPipePT,
9489 PsdAppBindingPT,
9490 PsdEventNotePT,
9491 PsdGlobalCfgPT,
9492 PsdPipeStreamPT,
9493 PsdDescriptorPT,
9494 PsdRTIsoHandlerPT
9496 /* \\\ */