top logo menu kitty mascot
AROS.ORG Developers Localization Bounties

poseidon

Index


psdAbortPipe() psdAddCfgEntry() psdAddClass() psdAddErrorMsgA()
psdAddEventHandler() psdAddHardware() psdAddStringChunk() psdAllocCfgForm()
psdAllocDevice() psdAllocPipe() psdAllocRTIsoHandlerA() psdAllocVec()
psdBorrowLocksWait() psdCalculatePower() psdCheckPipe() psdClaimAppBindingA()
psdClassScan() psdCloseStream() psdCopyStr() psdCopyStrFmtA()
psdDebugSemaphores() psdDelayMS() psdDoHubMethodA() psdDoPipe()
psdEnumerateDevice() psdEnumerateHardware() psdFindCfgForm() psdFindDescriptorA()
psdFindDeviceA() psdFindEndpointA() psdFindInterfaceA() psdFreeDevice()
psdFreePipe() psdFreeRTIsoHandler() psdFreeVec() psdGetAttrsA()
psdGetCfgChunk() psdGetClsCfg() psdGetForcedBinding() psdGetNextDevice()
psdGetPipeActual() psdGetPipeError() psdGetStreamError() psdGetStringChunk()
psdGetStringDescriptor() psdGetUsbDevCfg() psdHubClaimAppBindingA() psdHubClassScan()
psdHubReleaseDevBinding() psdHubReleaseIfBinding() psdLoadCfgFromDisk() psdLockReadDevice()
psdLockReadPBase() psdLockWriteDevice() psdLockWritePBase() psdMatchStringChunk()
psdNextCfgForm() psdNumToStr() psdOpenStreamA() psdParseCfg()
psdPipeSetup() psdReadCfg() psdReleaseAppBinding() psdReleaseDevBinding()
psdReleaseIfBinding() psdRemCfgChunk() psdRemCfgForm() psdRemClass()
psdRemErrorMsg() psdRemEventHandler() psdRemHardware() psdResumeBindings()
psdResumeDevice() psdSafeRawDoFmtA() psdSaveCfgToDisk() psdSendEvent()
psdSendPipe() psdSetAltInterface() psdSetAttrsA() psdSetClsCfg()
psdSetDeviceConfig() psdSetForcedBinding() psdSetUsbDevCfg() psdSpawnSubTask()
psdStartRTIso() psdStopRTIso() psdStreamFlush() psdStreamRead()
psdStreamWrite() psdSuspendBindings() psdSuspendDevice() psdUnbindAll()
psdUnlockDevice() psdUnlockPBase() psdWaitPipe() psdWriteCfg()

psdAbortPipe()

Synopsis

void psdAbortPipe(
         struct PsdPipe * pp );

Function

Request cancellation of an outstanding pipe transfer.

Inputs

pp - Valid pipe with a possible pending transfer.

Notes

The function has no effect unless the pipe message is pending.
When pending, it allocates a temporary pipe-like request referring
to the original pipe, sends it to the hardware task, waits for the
cancellation request to complete and releases the temporary object.
It does not wait for or remove the original pipe's completion reply.
Call psdWaitPipe() before reusing or releasing the original pipe.

Bugs

If allocation of the temporary cancellation request fails, no
cancellation request is sent and the caller receives no error.

psdAddCfgEntry()

Synopsis

struct PsdIFFContext * psdAddCfgEntry(
         struct PsdIFFContext * pic,
         APTR formdata );

Function

Add an IFF FORM or data chunk to an existing configuration context.

Inputs

pic      - Parent context, or NULL for the configuration root.
formdata - Valid serialized IFF FORM or chunk to incorporate.

Result

Resulting configuration context from the internal addition
routine, or NULL on failure.

Notes

Takes the configuration write lock, delegates parsing and
insertion to pAddCfgChunk(), and marks configuration for checking.
Form and chunk replacement rules are those of the internal IFF
context implementation, not those of a general-purpose IFF parser.

psdAddClass()

Synopsis

struct PsdUsbClass * psdAddClass(
         STRPTR name,
         ULONG vers );

Function

Open a USB class library and register it with Poseidon.

Inputs

name - Valid class library name or pathname.
vers - Minimum version passed to OpenLibrary().

Result

Registered class record, or NULL if the library cannot be opened,
is already registered, or record allocation fails.

Notes

Attempts the supplied path and progressively shorter path
components when opening the library. Rejects duplicate class
names. On success, reads class attributes, adds the class to the
priority-ordered list and emits EHMB_ADDCLASS. Call psdRemClass()
to unregister the class.

psdAddErrorMsgA()

Synopsis

struct PsdErrorMsg * psdAddErrorMsgA(
         UWORD level,
         STRPTR origin,
         STRPTR fmtstr,
         RAWARG fmtdata );

struct PsdErrorMsg * psdAddErrorMsg(
         UWORD level,
         STRPTR origin,
         STRPTR fmtstr,
         ... );

Function

Append a formatted diagnostic message to Poseidon's error log.

Inputs

level   - Severity compared with the current logging preferences.
origin  - Valid source name copied into the error record.
fmtstr  - RawDoFmt() format string.
fmtdata - Matching RawDoFmt() argument stream.

Result

New error-message record, or NULL if logging at this severity is
disabled or a required allocation fails.

Notes

Applies the configured info, warning, error and failure filters
before allocating or formatting a message. Depending on stack
flags, the text can also be sent to the kernel log. The record
becomes part of the Poseidon message list; callers must not free
its fields independently.

psdAddEventHandler()

Synopsis

APTR psdAddEventHandler(
   struct MsgPort *mp, ULONG msgmask)

Function

Subscribe a message port to Poseidon events.

Inputs

mp - Live message port dedicated to this registration.
msgmask - Bitwise OR of EHMF_* masks from <libraries/poseidon.h>.
    Zero registers a handler that receives no events.

Result

An opaque registration handle, or NULL for a NULL port or allocation
failure. Remove a successful registration with psdRemEventHandler().

Notes

Call in task context; registration may wait for a semaphore. The
port is retained, not copied or owned. Keep it alive until removal
completes and coordinate removal with the receiving task.

Each notification is a PsdEventNote message. Read ENA_EventID,
ENA_Param1 and ENA_Param2 with psdGetAttrsA(PGA_EVENTNOTE, ...), then
ReplyMsg() exactly once. Do not free the message or use it after reply.
Parameter pointers do not pin their objects; removal notifications
can refer to objects that are no longer safe to dereference.

There is no initial state snapshot. Allocation failure can silently
drop individual notifications; use events as change notifications,
not as a guaranteed transaction log.

psdAddHardware()

Synopsis

struct PsdHardware * psdAddHardware(
         STRPTR name,
         ULONG unit );

Function

Open a USB controller and register it with the Poseidon stack.

Inputs

name - Controller device name used for OpenDevice().
unit - Controller device unit number.

Result

Initialized controller handle, or NULL if allocation, startup or
controller initialization fails.

Notes

Allocates controller state and a dedicated device task, and waits
for its initialization signal. Successful registration emits
EHMB_ADDHARDWARE. Attached USB devices are not enumerated by this
call; use psdEnumerateHardware() afterwards. The returned state
belongs to the stack and is released by psdRemHardware().

psdAddStringChunk()

Synopsis

BOOL psdAddStringChunk(
   APTR pic, ULONG chunkid, CONST_STRPTR contents)

Function

Store a string chunk in a configuration form.

Inputs

pic - Valid, non-NULL form handle.
chunkid - Numeric chunk identifier in host byte order; must not be FORM.
contents - Non-NULL, NUL-terminated string. Keep it valid until return.
    Its length and allocation overhead must fit in ULONG.

Result

TRUE if the string was stored; FALSE if allocation fails. Failure
while expanding the form buffer can leave the previous chunk removed.

Notes

Copies the string, including its terminator, into the form. Replaces
the first existing chunk with the same identifier. The source is not
retained. Uses the configuration write lock and may wait; call in task
context. Coordinate form lifetime separately.

Does not save preferences, apply configuration or set the configuration
recheck request. Use the appropriate configuration operation afterward.

Bugs

Replacement removes the old chunk before securing expansion memory.
Input sizes and the reserved FORM identifier are not validated.

psdAllocCfgForm()

Synopsis

APTR psdAllocCfgForm(
   ULONG formid)

Function

Allocate an empty, detached configuration form.

Inputs

formid - Numeric four-character form identifier in host byte order.

Result

An opaque form handle, or NULL if allocation fails.

Notes

The form starts with no chunks or child forms and with a
four-byte payload for its type identifier. It is tracked
separately from the active configuration tree.
Allocation alone neither installs configuration nor saves it to disk.
Release the form and its contents with psdRemCfgForm(); do not free
the handle with psdFreeVec(). Coordinate its lifetime with all users.

psdAllocDevice()

Synopsis

struct PsdDevice * psdAllocDevice(
         struct PsdHardware * phw );

Function

Allocate and register a device record under a USB controller.

Inputs

phw - Valid controller owning the new device record.

Result

Initialized device record, or NULL on allocation failure.

Notes

Initializes device locks, descriptor/configuration lists,
real-time isochronous-handler list, and default device options.
Inserts the record into the controller's device list under the
Poseidon base write lock. The record is not enumerated or assigned
an address by this call.

psdAllocPipe()

Synopsis

struct PsdPipe * psdAllocPipe(
         struct PsdDevice * pd,
         struct MsgPort * mp,
         struct PsdEndpoint * pep );

Function

Allocate a transfer pipe for a USB device endpoint or endpoint zero.

Inputs

pd  - Valid Poseidon device with an initialized hardware controller.
mp  - Message port receiving completed transfers; must not be NULL.
pep - Endpoint to address, or NULL for the default control endpoint.

Result

Allocated pipe, or NULL on invalid input, allocation failure,
unsupported transfer type or controller capability, or failed
endpoint preparation. Release it with psdFreePipe().

Notes

The IO request inherits the hardware-controller request template.
The function sets device address, endpoint parameters, speed flags,
root-port routing and, where required, split-transaction details.
Isochronous endpoints require UHCF_ISO. A successful allocation
increments the device use count. The caller must retain a valid
message port for pending transfers and must not reuse a pending pipe.

psdAllocRTIsoHandlerA()

Synopsis

APTR psdAllocRTIsoHandlerA(
   APTR pep, struct TagItem *taglist)

Function

Register a real-time isochronous endpoint handler with its controller.

Inputs

pep - Live isochronous endpoint. NULL is rejected.
taglist - RTA_* attributes, or NULL for defaults.

Tags

RTA_InRequestHook, RTA_OutRequestHook - Buffer request hooks for
    input or output, using struct IOUsbHWBufferReq.
RTA_InDoneHook, RTA_OutDoneHook - Buffer completion hooks.
RTA_ReleaseHook - Device-removal notification hook, called with the
    handler as object and NULL as message.
RTA_OutPrefetchSize - Maximum output prefetch in bytes; default 2048.

Result

A registered handler, or NULL if the endpoint is unsuitable, the
controller lacks UHCF_RT_ISO, allocation fails or registration fails.
Allocation does not start transfers. Release with psdFreeRTIsoHandler().

Notes

Call in task context and coordinate endpoint lifetime. Hook pointers
are retained, not copied; keep hook structures, code and associated
state valid until the controller no longer uses them. The tag list
itself is not retained. No hook is installed by default.

Data hooks follow <devices/usbhardware.h>. They may run with interrupts
disabled; do not wait, perform DOS I/O or call these lifecycle functions
from a data hook. The callback object is controller-private, not the
Poseidon handler. Request buffers and completion semantics must satisfy
the selected controller; do not release buffers while it can use them.

The release hook runs during device removal with the device write lock
held. Arrange cleanup without waiting for a task that needs that lock.
Registration uses synchronous controller I/O with no reply port and
requires quick completion support; there is no library-level timeout.

Bugs

The endpoint ownership chain is dereferenced without separate
validation. Controller quick-I/O support is required by the
synchronous calls but is not independently verified here.

psdAllocVec()

Synopsis

APTR psdAllocVec(
         ULONG size );

Function

Allocate an aligned block from the Poseidon memory pool.

Inputs

size - Requested number of usable bytes.

Result

Allocated block aligned to AROS_WORSTALIGN, or NULL on pool
allocation failure. Release it with psdFreeVec().

Notes

An allocation header immediately preceding the returned pointer
records the original pool pointer and requested size. Successful
allocations increase the library's allocated-byte counter by size.
MEMDEBUG builds reserve an additional 1024-byte overrun area.
The requested allocation is not explicitly zero-initialized here.

Bugs

The calculation adding the header, alignment padding and optional
debugging area does not check for ULONG overflow.

psdBorrowLocksWait()

Synopsis

ULONG psdBorrowLocksWait(
   struct Task *task, ULONG signals)

Function

Temporarily lend the caller's registered Poseidon locks to another
task while waiting for signals, then reclaim them.

Inputs

task - Valid, non-NULL cooperating task distinct from the caller.
    Keep it alive throughout the wait and lock reclamation.
signals - Exec signal mask for completion. The caller must arrange for
    the cooperating operation to signal it.

Result

The signal mask returned by Wait(signals), after lock reclamation.
This is not a lock-transfer status or a count of transferred locks.

Notes

Used when a cooperating task must access Poseidon state protected by
locks held by the caller. Only locks registered with Poseidon's lock
implementation participate; ordinary Exec semaphores are unaffected.
With no caller-held registered locks, behaves as Wait(signals).

The cooperating task must balance its own lock acquisitions and must
not consume the caller's borrowed lock counts. Keep all participating
lock objects alive until reclamation finishes. Do not use this operation
as permission to destroy or replace protected objects.

Transfers or temporarily releases exclusive and shared ownership,
including recursive counts. A waiting recipient can be moved to the
front of a wait queue and its shared request promoted to exclusive.
After receiving a signal, restores ownership directly where possible
and otherwise reacquires the saved lock counts.

Reclamation can block after the requested signal arrives. There is no
timeout or cancellation result. A completion signal should represent
a point at which the cooperating operation can release its locks.

Bugs

The recipient task is dereferenced without NULL validation.
Transfer bookkeeping allocation can fail without an error result.
Some locks can remain with the caller while others have been lent;
waiting can then deadlock. Queue reordering or promotion can precede
the failed allocation. This function does not guarantee deadlock
avoidance or an all-or-nothing transfer.

psdCalculatePower()

Synopsis

VOID psdCalculatePower(
   APTR phw)

Function

Recalculate the stored power estimates for a hardware device tree.

Inputs

phw - Valid, non-NULL hardware handle. Keep the hardware and its
    device topology alive and stable until return.

Result

None. Read device estimates through DA_PowerSupply and DA_PowerDrained.

Notes

Visits every root device of this hardware and recursively updates
supply and drain estimates in milliamperes. Uses current configurations,
self-powered status, power overrides and the suspended flag.

The model starts roots at 500 mA, allows 500 mA per downstream connection
from self-powered devices, and caps downstream supply from bus-powered
devices at 100 mA after accounting for their own demand. Suspended
configured devices use a 1 or 3 mA drain estimate.

A newly detected deficit sets the low-power flag, logs a warning and
sends EHMB_DEVICELOWPW. A resolved deficit clears the flag and logs a
message; it does not send a matching recovery event.

May wait for the base read lock and perform logging and event allocation.
It does not measure current, negotiate power, switch ports or reject
configurations. Coordinate concurrent configuration and power-state
changes; the read lock does not serialize these stored-value updates.

Bugs

A NULL hardware pointer is dereferenced without validation.
The fixed 500/100 mA model is not a speed-specific USB power budget.
Suspended devices stop drain recursion, so descendants can retain old
drain values. Self-powered devices report zero upstream drain. Treat
these values as implementation estimates, not electrical guarantees.

psdCheckPipe()

Synopsis

APTR psdCheckPipe(
   APTR pp)

Function

Test whether a pipe is marked as pending.

Inputs

pp - Valid, non-NULL pipe handle.

Result

NULL while the pipe message has type NT_MESSAGE; otherwise pp.
A non-NULL result does not mean that the transfer succeeded, and an
idle pipe need not have completed a transfer at all.

Notes

Does not wait, remove a reply message or inspect transfer status.
Use psdWaitPipe() for the normal completion path and inspect its result
and the actual byte count before reusing transfer data. Serialize
submission, completion and freeing of the pipe with this check.
The returned handle is the original pipe, not a new allocation.

Bugs

The implementation dereferences pp without checking for NULL.

psdClaimAppBindingA()

Synopsis

struct PsdAppBinding * psdClaimAppBindingA(
         struct TagItem * tags );

struct PsdAppBinding * psdClaimAppBinding(
         TAG tag, ... );

Function

Claim a USB device for an application, bypassing normal class
ownership where the hub accepts the request.

Inputs

tags - ABA_* binding attributes, including ABA_Device and
       ABA_ReleaseHook; both are required.

Result

Application-binding handle, or NULL if required attributes are
absent or the hub declines the claim.

Notes

ABA_ForceRelease requests release of existing class bindings
before attempting the claim. Root-hub claims are handled locally;
downstream devices delegate through the parent hub's class method.
On success the binding records the current task and an
EHMB_ADDBINDING event is sent. The supplied release hook is called
during release; the handle must not be used after that callback.

psdClassScan()

Synopsis

void psdClassScan();

Function

Ask USB class drivers to bind devices found by Poseidon.

Notes

On the first process-driven scan after early task-based startup,
releases provisional boot-class bindings before selecting normal
drivers. Takes the base read lock and scans root devices through
psdHubClassScan(); downstream hub tasks handle their own devices.
If no class is registered, reports a warning and returns. No
binding count or completion status is returned.

psdCloseStream()

Synopsis

VOID psdCloseStream(
   APTR pps)

Function

Flush a stream, stop its pipes and release its storage.

Inputs

pps - Live stream returned by psdOpenStreamA(), or NULL.

Notes

NULL is ignored. Call in task context after excluding other users.
Flushes first, then aborts, waits for and frees each pipe. Releases
internal buffers and an internally created message port. A supplied
port and terminator table remain caller-owned. The handle is invalid
after return. Close can wait for controller completion.

For output, explicitly flush and inspect the result before closing
when delivery matters. Close returns no status and ignores flush
failure. For input, unread data is discarded.

Bugs

Cleanup assumes the configured pipe array and port are usable.
Partially initialized streams can violate that assumption.

psdCopyStr()

Synopsis

STRPTR psdCopyStr(
         CONST_STRPTR name );

Function

Allocate a copy of a NUL-terminated string in Poseidon memory.

Inputs

name - Valid NUL-terminated string; must not be NULL.

Result

Newly allocated copy or NULL if allocation fails. Release the
returned string with psdFreeVec().

Notes

The function allocates strlen(name) plus one byte through
psdAllocVec() and copies the string with strcpy(). It does not
validate the source pointer or bound its length.

psdCopyStrFmtA()

Synopsis

STRPTR psdCopyStrFmtA(
   CONST_STRPTR fmtstr, RAWARG fmtdata)

Function

Allocate a string formatted with Exec RawDoFmt().

Inputs

fmtstr - Non-NULL RawDoFmt format string.
fmtdata - Argument stream in the format required by RawDoFmt(),
    matching fmtstr. Referenced strings must remain valid and unchanged
    throughout both formatting passes.

Result

A NUL-terminated allocated string, or NULL on allocation failure.
Release the result with psdFreeVec().

Notes

Formats once to count output characters and again to fill the buffer.
The format and argument data are borrowed and are not retained.
RawDoFmt conventions apply, including argument widths and string
representations; this is not a printf argument list.

The character count, terminator and allocator overhead must fit in
ULONG. Count overflow and NULL input pointers are not checked.

psdDebugSemaphores()

Synopsis

VOID psdDebugSemaphores(
   )

Function

Log the registered Poseidon semaphore owners, readers and waiters.

Result

None. Output is added to the Poseidon message log.

Notes

Reports the calling task, then each registered semaphore's name,
exclusive and shared counts, owner, waiting tasks and shared-lock counts.
It does not acquire, release or repair the reported locks.

Messages use informational severity and are suppressed when information
logging is disabled. Allocation failure can omit individual messages;
there is no complete-output indication. Only registered Poseidon locks
are visited, not arbitrary Exec semaphores.

Use from task context. Traversal uses Forbid()/Permit(), while logging
can allocate memory and perform other system calls. The output is a
diagnostic view, not a guaranteed atomic snapshot or a deadlock verdict.

psdDelayMS()

Synopsis

void psdDelayMS(
         ULONG milli );

Function

Perform a synchronous delay through Poseidon's timer device.

Inputs

milli - Requested delay in milliseconds.

Notes

The function initializes a private message port using the current
task's SIGB_SINGLE signal, copies the library's timer request,
sets its time to milli * 1000 microseconds and calls DoIO().
It does not expose a timer error or signal-interruption result.

Bugs

The multiplication by 1000 has no explicit overflow check.
The requested duration is not normalized into seconds here.

psdDoHubMethodA()

Synopsis

IPTR psdDoHubMethodA(
   APTR pd, ULONG methodid, IPTR *methoddata)

Function

Dispatch a method to the class bound to a device's parent hub.

Inputs

pd - Device used to select the parent hub class, or NULL. Keep the
    device, parent hub and class binding alive until return.
methodid - Method identifier understood by that class.
methoddata - Array of IPTR arguments in the layout required by the
    method. Keep the array and referenced objects valid until return
    and for any longer lifetime required by that method.

Result

The method result, subject to the return-width defect below. Returns
zero without dispatch if pd is NULL, has no parent hub, or the parent
has no device binding or class binding. Zero is also a possible method
result and does not distinguish these cases.

Notes

The argument array is passed unchanged. This function does not insert
the parent hub binding or validate the method identifier, argument count,
argument pointers or target port. The routing device and the objects in
the argument array have distinct roles.

For UCM_HubPowerCyclePort and UCM_HubDisablePort, the supplied hub.class
expects { hub device, one-based port number }. For UCM_HubClassScan it
expects { hub binding }; for UCM_HubClaimAppBinding,
{ hub binding, tag list }; for UCM_HubReleaseIfBinding,
{ hub binding, interface }; and for UCM_HubReleaseDevBinding,
UCM_HubSuspendDevice and UCM_HubResumeDevice, { hub binding, device }.

Takes no device or base lock. The caller must coordinate topology and
binding changes. The class method may block. For the supplied hub.class,
claim, release, suspend and resume requests can wait for its task to
reply. Power-cycle, disable-port and class-scan methods schedule work;
their return does not establish completion of that work.

Prefer the dedicated binding and power-state APIs when they provide the
requested operation; they perform additional bookkeeping and callbacks.

Bugs

The public result type is IPTR, but this implementation returns LONG.
On targets with pointers wider than 32 bits, pointer-valued and other
wide results cannot be relied on. In particular, do not obtain an
application-binding handle through this dispatcher on such targets;
use psdClaimAppBindingA(). The source also uses APTR for methoddata;
the public array layout remains IPTR elements.

psdDoPipe()

Synopsis

LONG psdDoPipe(
         struct PsdPipe * pp,
         APTR data,
         ULONG len );

Function

Submit a pipe transfer and wait for its completion.

Inputs

pp   - Allocated pipe that is not already pending.
data - Transfer buffer, or NULL for a control request without data.
len  - Number of bytes to transfer.

Result

IO error code returned by psdWaitPipe() after the transfer, or
UHIOERR_TIMEOUT if the device is disconnected. Zero indicates
successful completion.

Notes

For a connected device, the function requests resume if suspended,
sets the data pointer, transfer length and stream ID, and sets the
control-request wLength when using endpoint zero. It queues the
pipe to the hardware task, updates the device busy count and last
activity, then waits for a reply. A disconnected device instead
delays for 50 ms, clears the actual length and returns a timeout.
The call may block while the transfer is pending.

psdEnumerateDevice()

Synopsis

struct PsdDevice * psdEnumerateDevice(
         struct PsdPipe * pp );

Function

Assign and query USB device state through an enumeration pipe.

Inputs

pp - Valid default-control pipe for a device being enumerated.

Result

Device associated with the pipe, or NULL on an earlier enumeration
failure. A non-NULL result does not guarantee that configuration
descriptors were read successfully or that a configuration was set.

Notes

The procedure acquires the device write lock, performs USB
requests to determine speed, address, descriptors and available
configurations, and updates the device's parsed state. It saves
the pipe flags and NAK timeout and restores them on completion.
On the address-assigned failure path, it clears the temporary
address and connected flags before returning NULL. Failure to
parse configurations is logged but returns the device pointer.
The call may block on USB transfers and does not establish a
class binding.

psdEnumerateHardware()

Synopsis

struct PsdDevice * psdEnumerateHardware(
         struct PsdHardware * phw );

Function

Enumerate the root USB device or root hubs of a registered
controller.

Inputs

phw - Initialized controller handle returned by psdAddHardware().

Result

Root device established by the enumeration procedure, or NULL if
no root device can be configured.

Notes

Uses a temporary message port and control pipe to reset and probe
the controller's root topology. The implementation includes
separate USB 2 and SuperSpeed root-hub handling where supported.
Unusable probe resources are released along failure paths. The
caller can run psdClassScan() after root enumeration to establish
suitable class bindings.

psdFindCfgForm()

Synopsis

struct PsdIFFContext * psdFindCfgForm(
         struct PsdIFFContext * pic,
         ULONG formid );

Function

Find the first child IFF FORM of a given identifier.

Inputs

pic    - Parent context, or NULL for the configuration root.
formid - Identifier of the required child form.

Result

Matching internal IFF context, or NULL if none exists.

Notes

The search is restricted to immediate child forms. The function
takes and releases the shared configuration lock internally, but
the returned context is not copied and may become stale after a
concurrent modification. Use psdNextCfgForm() for further matches.

psdFindDescriptorA()

Synopsis

APTR psdFindDescriptorA(
   APTR pd, APTR pdd, struct TagItem *taglist)

Function

Find the next stored descriptor matching all supplied filters.

Inputs

pd - Valid device handle.
pdd - NULL to start; otherwise a previous descriptor from this device.
    Searching resumes after it.
taglist - Filter list, or NULL for default configuration filtering.

Tags

DDA_Config - Configuration handle to match. NULL accepts every
    configuration. If omitted, matches the current configuration.
DDA_Interface, DDA_Endpoint - Exact association-pointer matches.
    NULL matches an unassociated descriptor, not every association.
DDA_DescriptorType, DDA_CS_SubType, DDA_DescriptorLength - Exact
    matches against stored descriptor attributes.

Result

A borrowed descriptor handle, or NULL if no further match is found.

Notes

Searches the device's stored descriptor list without issuing USB
requests. Unknown tags are ignored. With no current configuration,
the default matches descriptors whose configuration pointer is NULL.

No lock is taken. Keep the device, cursor and returned objects alive
and exclude concurrent list changes. Do not free the result. The tag
list is not retained.

Bugs

DDA_Device, DDA_Name and DDA_DescriptorData are declared but
not interpreted as search filters. A NULL device and a
foreign continuation descriptor are not validated.

psdFindDeviceA()

Synopsis

struct PsdDevice * psdFindDeviceA(
         struct PsdDevice * pd,
         struct TagItem * tags );

struct PsdDevice * psdFindDevice(
         struct PsdDevice * pd,
         TAG tag, ... );

Function

Find the next device satisfying all supplied search attributes.

Inputs

pd   - Previous device, or NULL to begin at the first device.
tags - Matching criteria expressed as DA_* search tags.

Result

First subsequent matching device, or NULL at the end of traversal.

Notes

Traverses the same controller/device lists as psdGetNextDevice().
Only search tags handled by this implementation constrain a match;
unrecognized tags are ignored. The function takes no base lock; callers requiring a stable result
must hold psdLockReadPBase() during traversal.

psdFindEndpointA()

Synopsis

APTR psdFindEndpointA(
   APTR pif, APTR pep, struct TagItem *taglist)

Function

Find the next endpoint matching all supplied filters.

Inputs

pif - Valid interface handle.
pep - NULL to start at the first endpoint; otherwise a previous result
    belonging to pif. Searching resumes after that endpoint.
taglist - Filter list, or NULL for no filters.

Tags

EA_IsIn - Nonzero for IN, zero for OUT.
EA_EndpointNum, EA_TransferType, EA_MaxPktSize, EA_Interval,
EA_MaxBurst, EA_CompAttributes, EA_BytesPerInterval - Exact matches
    against the corresponding stored endpoint attributes.

Result

A borrowed endpoint handle, or NULL if no further endpoint matches.

Notes

Searches only this interface's endpoint list. Does not allocate an
endpoint, issue USB requests or retain the tag list. Unknown tags are
ignored. No lock is taken: keep the interface, cursor and returned
object alive and exclude concurrent list changes while traversing.
Do not free the result.

Bugs

EA_Interface, EA_SyncType, EA_UsageType and EA_MaxStreams are
declared but are not supported as search filters. A NULL
interface and an unrelated continuation cursor are unchecked.

psdFindInterfaceA()

Synopsis

APTR psdFindInterfaceA(
   APTR pd, APTR pif, struct TagItem *taglist)

Function

Find the next interface matching all supplied filters.

Inputs

pd - Valid device handle. A fresh search uses its current configuration.
pif - NULL to start; otherwise a previous result for this device.
taglist - Filter list, or NULL for no filters.

Tags

IFA_InterfaceNum, IFA_NumEndpoints, IFA_Class, IFA_SubClass,
IFA_Protocol - Exact matches against stored attributes.
IFA_AlternateNum - Enables alternate-interface searching. Values
    through 255 also select that alternate number; larger values
    accept any alternate number.
IFA_Binding - Exact binding-pointer match, including NULL.
IFA_InterfaceName, IFA_IDString - Case-sensitive string matches.
    Supply valid strings; the corresponding stored string must exist.

Result

A borrowed interface handle, or NULL if no further match is found
or a fresh search has no current configuration.

Notes

Without IFA_AlternateNum, fresh searches visit main interfaces only.
With it, each main interface is followed by its alternates. Resuming
from an alternate also enables alternate traversal. Unknown tags are
ignored. This call does not select an alternate or issue USB requests.

No lock is taken. Keep device, configuration, cursor and results alive
and exclude concurrent topology changes while traversing. The result
is owned by Poseidon; do not free it. Tag data is not retained.

Bugs

Resuming after the last alternate can return NULL before visiting
later main interfaces. Name filters pass stored pointers to strcmp()
without checking for NULL. Other declared interface filters,
including IFA_Config and IFA_BindingClass, are not handled.

psdFreeDevice()

Synopsis

void psdFreeDevice(
         struct PsdDevice * pd );

Function

Remove a device from active enumeration and begin its teardown.

Inputs

pd - Valid device to retire; NULL is not accepted.

Notes

Moves the device to its controller's dead-device list, notifies
registered real-time isochronous release hooks, and releases
device and interface bindings under the device lock. The internal
release routine may defer final reclamation while pipe references
remain. Callers must not use the device as an active device after
this call.

psdFreePipe()

Synopsis

void psdFreePipe(
         struct PsdPipe * pp );

Function

Release a pipe and its associated device reference.

Inputs

pp - Pipe returned by psdAllocPipe(); NULL has no effect.

Notes

When the pipe message is still pending, this function requests an
abort and waits for the reply before freeing the pipe. It then
tears down the endpoint hardware state, decrements the device use
count and frees the pipe. If this was the last reference to a device
marked for deferred expunge, the device is also released.

The pipe becomes invalid on return. Waiting for a pending transfer
may block; the function returns no abort or completion status.

psdFreeRTIsoHandler()

Synopsis

VOID psdFreeRTIsoHandler(
   APTR prt)

Function

Remove a real-time isochronous handler and free its library storage.

Inputs

prt - Live handler returned by psdAllocRTIsoHandlerA(), or NULL.

Notes

NULL is ignored. Call in task context. Stop a running handler first
and serialize this call with all operations using it. Removes the
handler from the device list, asks the controller to remove it, then
frees its pipe and storage. The handle is invalid after return.

Does not stop an active handler, call the release hook or
balance a successful start itself.
This call has no library-level timeout.

Bugs

The controller removal result is ignored. Storage is freed even if
removal fails, so return does not independently prove that callbacks
or controller references have been quiesced.

psdFreeVec()

Synopsis

void psdFreeVec(
         APTR pmem );

Function

Release a block allocated by psdAllocVec().

Inputs

pmem - Block returned by psdAllocVec(), or NULL for no action.

Notes

The allocator header immediately before the block supplies the
original pooled allocation pointer and the requested byte count.
The function decreases the library's allocated-byte counter and
frees the original pool block using its original total allocation
size, including alignment storage and optional MEMDEBUG space.
The pointer becomes invalid on return; non-Poseidon pointers are
not accepted.

See also

psdAllocVec()


psdGetAttrsA()

Synopsis

LONG psdGetAttrsA(
         ULONG type,
         APTR psdstruct,
         struct TagItem * tags );

LONG psdGetAttrs(
         ULONG type,
         APTR psdstruct,
         TAG tag, ... );

Function

Read supported attributes from a Poseidon object or stack state.

Inputs

type      - PGA_* object category selecting the attribute table.
psdstruct - Object of the selected category; PGA_STACK uses the
            library's own base state.
tags      - Tag list identifying attributes and writable result
            addresses; result addresses must be valid.

Result

Number of recognized attributes read, or -1 when the category
has no pack table.

Notes

Explicit attributes are handled by the selected category's
special cases; remaining attributes are read with
UnpackStructureTags(). Returned pointers refer to live Poseidon
structures and must not be freed or retained beyond their valid
lifetime. See libraries/poseidon.h for supported tag identifiers.

psdGetCfgChunk()

Synopsis

APTR psdGetCfgChunk(
         struct PsdIFFContext * pic,
         ULONG chnkid );

Function

Copy a serialized IFF chunk out of a configuration context.

Inputs

pic    - Context, or NULL for the configuration root.
chnkid - Identifier of the requested chunk.

Result

Allocated copy of the full chunk including its IFF header, or
NULL if the chunk is absent or allocation fails. Free with
psdFreeVec().

Notes

Searches under the shared configuration lock and copies the
stored chunk into independent memory. Root-context lookup may
refresh stored global configuration chunks before reading, so
this operation is not strictly read-only. The IFF size field
describes payload size; the copy also includes the eight-byte
chunk header.

psdGetClsCfg()

Synopsis

struct PsdIFFContext * psdGetClsCfg(
         STRPTR owner );

Function

Find the stored configuration context for a class owner.

Inputs

owner - Valid class or owner identifier string.

Result

Internal CLASSDATA context for the matching owner, or NULL if
none is present.

Notes

The returned pointer refers to live configuration storage, not
a serialized IFF buffer. It is not caller-owned and should not
outlive changes that remove or replace its containing form.

psdGetForcedBinding()

Synopsis

STRPTR psdGetForcedBinding(
   STRPTR devid, STRPTR ifid)

Function

Look up the configured forced class binding for a device or interface.

Inputs

devid - Non-NULL, NUL-terminated device ID string.
ifid - NUL-terminated interface ID string, or NULL for a device binding.
    Both strings must remain valid until return.

Result

A borrowed pointer to the stored class name, or NULL if no matching
binding is found. Do not modify or free the returned string.

Notes

May wait for the configuration read lock. Searches only the first
matching device form. An interface lookup does not fall back to the
device binding. The result describes configuration, not a live binding
or proof that the named class is available.

The read lock is released before return. Configuration replacement,
removal, or buffer reallocation can invalidate the pointer. Exclude
concurrent configuration mutation for the lookup and the entire use
of the result; copy it while that exclusion remains in effect if a
longer-lived value is required.

psdGetNextDevice()

Synopsis

struct PsdDevice * psdGetNextDevice(
         struct PsdDevice * pd );

Function

Return the next device in Poseidon's controller/device lists.

Inputs

pd - Previous device, or NULL to start with the first controller.

Result

Next device pointer, or NULL when no further device is found.

Notes

The function first examines the next node in the current
controller's device list. When that list is exhausted, it visits
subsequent controllers. With NULL input, it starts at the first
controller. It takes no lock; callers must keep the relevant
lists stable for the traversal and must not retain a returned
pointer beyond the device's valid lifetime.

psdGetPipeActual()

Synopsis

ULONG psdGetPipeActual(
         struct PsdPipe * pp );

Function

Read the actual byte count recorded for a pipe transfer.

Inputs

pp - Valid Poseidon pipe; NULL is not accepted.

Result

Value of the pipe request's iouh_Actual field.

Notes

The function does not wait for completion or validate the pipe
state. Read the count after handling the transfer completion.

psdGetPipeError()

Synopsis

LONG psdGetPipeError(
         struct PsdPipe * pp );

Function

Read the IO error recorded for a pipe transfer.

Inputs

pp - Valid Poseidon pipe; NULL is not accepted.

Result

The pipe request's io_Error value, cast to LONG. Zero indicates
no recorded error.

Notes

The function does not wait for completion or validate the pipe
state. Read the error after handling an asynchronous completion.

psdGetStreamError()

Synopsis

LONG psdGetStreamError(
   APTR pps)

Function

Return a stream's stored error value.

Inputs

pps - Live stream, or NULL.

Result

The stored error value, or -1 for NULL. Zero means no error is stored;
it does not prove transfer completion or successful delivery.

Notes

Does not wait, collect pipe replies, clear the error or acquire the
stream semaphore. Read, write and flush reset the value on entry and
then record selected errors. Query immediately after the operation
under the caller's serialization policy; another operation or an
explicit PSA_Error update can replace it.

psdGetStringChunk()

Synopsis

STRPTR psdGetStringChunk(
   APTR pic, ULONG chunkid)

Function

Copy the first matching configuration chunk into a string buffer.

Inputs

pic - Valid, non-NULL form handle.
chunkid - Numeric chunk identifier in host byte order.

Result

An allocated copy of the chunk payload, followed by a zero byte.
Returns NULL if the chunk is absent or allocation fails. Release the
result with psdFreeVec(). An empty stored string returns a non-NULL
empty string when allocation succeeds.

Notes

Copies the declared payload length, including any embedded NULs.
The extra zero byte comes from the cleared allocation. The result
remains valid after the form changes or is removed.

Uses the configuration read lock and may wait; call in task context.
Coordinate form lifetime separately. The form must contain structurally
valid chunks; this operation does not validate imported IFF data.

psdGetStringDescriptor()

Synopsis

STRPTR psdGetStringDescriptor(
         struct PsdPipe * pp,
         UWORD idx );

Function

Read a USB string descriptor and convert it to a C string.

Inputs

pp  - Valid device control pipe.
idx - USB string-descriptor index to request.

Result

Newly allocated NUL-terminated string, or NULL when a required
descriptor request or allocation fails. Release it with
psdFreeVec() unless ownership has been transferred explicitly.

Notes

The first request for a device also attempts to discover language
identifiers and select a language. Subsequent control transfers
fetch the descriptor data. The implementation converts characters
from the device's UTF-16 string representation to its supported
narrow-string form, substituting '?' for code points outside
the byte range or below U+0020. It does not preserve arbitrary
Unicode input.

Bugs

When fetching the language-ID array, the second transfer starts
two bytes after the beginning of an allocation sized to the
descriptor length. A full-length reply can overwrite two bytes
beyond that allocation. The string-descriptor transfer also
uses the size advertised by the device without bounding the
destination against the remaining bytes in its local buffer.
Both transfers can overrun their destination allocations.

psdGetUsbDevCfg()

Synopsis

struct PsdIFFContext * psdGetUsbDevCfg(
         STRPTR owner,
         STRPTR devid,
         STRPTR ifid );

Function

Find stored class configuration for a device or interface.

Inputs

owner - Class or owner identifier.
devid - Required USB device identification string.
ifid  - Optional interface identification string; NULL selects
        device-level configuration.

Result

Internal class-data IFF context, or NULL if no matching entry
exists.

Notes

Searches the device, optional interface and owner configuration
forms under the shared configuration lock. The returned pointer
refers to mutable internal storage rather than a copied IFF buffer.
Call psdWriteCfg() to obtain an independently allocated snapshot.

psdHubClaimAppBindingA()

Synopsis

APTR psdHubClaimAppBindingA(
   struct TagItem *taglist)

Function

Install an application binding on an unbound device.

Inputs

taglist - TagItem list describing the application binding.

Tags

ABA_Device - Required valid device handle.
ABA_ReleaseHook - Required hook, retained until release. It is called
    with the binding handle as the object and ABA_UserData as the message.
ABA_UserData - Value passed to the release hook; defaults to zero.
    Keep any referenced data alive until the hook has returned.
ABA_Task - Task pointer stored in the binding; defaults to NULL.
    This function does not substitute the current task.
ABA_ForceRelease - Stored flag; does not force release in this function.

Result

An installed binding handle, or NULL if allocation fails, a required
attribute is missing, or any device or interface binding already exists.
Do not free the handle with psdFreeVec().

Notes

This is the hub-side operation. Applications should normally use
psdClaimAppBindingA(), which dispatches to the hub owner, handles forced
release, records the calling task and sends the binding-added event.

The caller must serialize access to the device and its configurations;
this function takes no device lock. Tag values are copied, but referenced
objects are retained rather than copied. Keep the device, hook and any
supplied task pointer valid for the binding lifetime. The tag list itself
is not retained.

Release through the owning binding path. On release, the hook must
finish using the binding before returning; Poseidon then frees it.
This function neither emits a binding-added event nor assigns a task
name to the binding.

psdHubClassScan()

Synopsis

VOID psdHubClassScan(
   APTR pd)

Function

Try to bind installed USB classes to a device and request a hub scan.

Inputs

pd - Valid, non-NULL device with a stable configuration and interface
    tree. Keep it alive until return.

Result

None. Allocation, configuration and binding failures are not aggregated.

Notes

Runs in the owning hub context. Ordinary clients should normally use
psdClassScan() to initiate scanning through the stack.

Creates a message port and control pipe, takes the base read lock and
the device write lock, and may perform USB control transfers and invoke
class methods while those locks are held. There is no whole-scan timeout.
Allocation failure for the message port or control pipe prevents
new binding attempts.

An existing device binding or the device's no-class-binding setting
skips new binding attempts. Otherwise a forced device class is tried
first when no interface binding exists. A configured forced name
suppresses ordinary fallback even when that class is absent or refuses.

Without that forced-device path, tries unbound interfaces across eligible
configurations and alternate settings. Existing interface bindings
restrict configuration selection. Forced interface names restrict class
selection; otherwise classes are tried in list order. If no interface
binds, attempts a device-level binding.

Successful bindings update class use counts and send EHMB_ADDBINDING.
Configuration and alternate-setting selection can change even when no
class binds. Do not retain assumptions about current interface ordering
across this call.

Finally, if a device class binding exists, invokes UCM_HubClassScan on
it, including when new binding attempts were skipped. The supplied
hub.class schedules its downstream scan; this call does not wait for
that downstream scan to finish.

Bugs

A NULL device handle is not validated before dereference.
Class callbacks run under stack and device locks and can deadlock if
they wait for another task requiring those locks. Forced class names
are borrowed from configuration storage; concurrent configuration
replacement can invalidate them. Coordinate configuration mutation
with scanning. Failed attempts do not restore the original configuration
or guarantee that all temporary alternate selections were undone.

psdHubReleaseDevBinding()

Synopsis

VOID psdHubReleaseDevBinding(
   APTR pd)

Function

Remove a device-level binding and invoke its release callback.

Inputs

pd - Device handle, or NULL to do nothing. Keep a non-NULL device
    alive until return.

Result

None. Callback results are ignored.

Notes

This is the hub-side operation; ordinary clients should use
psdReleaseDevBinding() or psdReleaseAppBinding(). Waits for the device
write lock and keeps it held while invoking the release callback.
Coordinate device lifetime and avoid callback dependencies on another
task that needs this lock.

Clears the device binding pointer before the callback. For an application
binding, calls its release hook with the binding as the object and its
user data as the message, then clears the application-binding flag,
frees the binding and sends EHMB_REMBINDING. The hook must not free the
binding or retain it after returning.

For a class binding, clears the class pointer, calls
UCM_ReleaseDeviceBinding, decrements the class use count and sends
EHMB_REMBINDING. If no class pointer is present, only the device binding
pointer is cleared. Interface bindings are not released here.

Release callbacks must complete before return. Do not install a new
binding from the callback while this release is still cleaning up.

psdHubReleaseIfBinding()

Synopsis

VOID psdHubReleaseIfBinding(
   APTR pif)

Function

Remove an interface binding and invoke its class release method.

Inputs

pif - Interface handle, or NULL to do nothing. Keep a non-NULL
    interface, its configuration and its device alive until return.

Result

None. The class method result is ignored.

Notes

This is the hub-side operation; ordinary clients should use
psdReleaseIfBinding(). Waits for the device write lock and holds it
through the class callback. Avoid callback dependencies on another
task that needs this lock.

If a binding exists, clears the interface binding pointer. If its class
is present, also clears the class pointer, calls
UCM_ReleaseInterfaceBinding and decrements the class use count.
Sends EHMB_REMBINDING for the device whenever a binding was removed,
including when no class pointer was present.

Does nothing if the interface has no binding. Other interface bindings
and the device-level binding are left intact. Stop using the released
binding; the class owns its cleanup. This function does not free the
interface or its configuration.

psdLoadCfgFromDisk()

Synopsis

BOOL psdLoadCfgFromDisk(
   STRPTR filename)

Function

Read a Poseidon preferences file and apply its configuration to the
running stack.

Inputs

filename - NUL-terminated DOS path, valid until return. NULL tries
    ENV:Sys/poseidon.prefs first, then ENVARC:Sys/poseidon.prefs if
    the first attempt returns FALSE.

Result

TRUE after the header and declared payload have been read and
configuration application has been attempted. FALSE if DOS cannot be
opened, the file cannot be opened, the header is rejected, allocation
fails, or the requested bytes cannot be read.

Notes

This call performs synchronous file I/O and may add or remove hardware,
load or unload classes, and change device bindings through psdParseCfg().
Call from a context that permits DOS I/O and blocking stack operations.
The filename is not retained. A reported success updates the saved
configuration hash.

Bugs

Only load trusted, structurally valid Poseidon IFF configuration files.
The declared FORM length is used without complete bounds or overflow
validation. Malformed lengths can cause invalid memory accesses.

The result of psdReadCfg() is ignored. TRUE does not establish that the
configuration was imported completely or that all devices and classes
were configured. Import failure can leave a partially replaced tree;
there is no rollback. A TRUE result also prevents default-path fallback.

psdLockReadDevice()

Synopsis

void psdLockReadDevice(
         struct PsdDevice * pd );

Function

Acquire the shared lock for a Poseidon device.

Inputs

pd - Valid device whose lock is to be acquired; not NULL.

Notes

Calls pLockSemShared() on the device's lock. The acquisition may
block, and each acquisition must be balanced with
psdUnlockDevice(). The caller must preserve lock ordering when
also accessing the global Poseidon base state.

psdLockReadPBase()

Synopsis

void psdLockReadPBase();

Function

Acquire a shared lock on the Poseidon base state.

Notes

The lock protects access to mutable global Poseidon structures,
including the hardware, device and class lists. It is acquired
through pLockSemShared() and must be released with
psdUnlockPBase(). The call may block while an exclusive owner
prevents shared access.

psdLockWriteDevice()

Synopsis

void psdLockWriteDevice(
         struct PsdDevice * pd );

Function

Acquire the exclusive lock for a Poseidon device.

Inputs

pd - Valid device whose lock is to be acquired; not NULL.

Notes

Calls pLockSemExcl() on the device's lock. The acquisition may
block, and each acquisition must be balanced with
psdUnlockDevice().

psdLockWritePBase()

Synopsis

void psdLockWritePBase();

Function

Acquire an exclusive lock on the Poseidon base state.

Notes

The function delegates to pLockSemExcl(). It may block until
conflicting owners release the lock. The caller must balance the
acquisition with psdUnlockPBase() and avoid lock-order inversions
when also locking a device or other Poseidon state.

psdMatchStringChunk()

Synopsis

BOOL psdMatchStringChunk(
   APTR pic, ULONG chunkid, CONST_STRPTR contents)

Function

Compare a string with the first matching configuration chunk.

Inputs

pic - Valid, non-NULL form handle.
chunkid - Numeric chunk identifier in host byte order.
contents - Non-NULL, NUL-terminated string to compare.

Result

TRUE for a byte-for-byte, case-sensitive match; FALSE if the chunk
is absent or differs. Comparison stops at its first NUL or declared
length, and the supplied string must end at that point.

Notes

Uses the configuration read lock and may wait; call in task context.
Retains neither the string nor a chunk pointer. Coordinate form
lifetime separately. This is not validation of serialized IFF data;
the form must already contain structurally valid chunks.

psdNextCfgForm()

Synopsis

struct PsdIFFContext * psdNextCfgForm(
         struct PsdIFFContext * pic );

Function

Find the next sibling IFF FORM with the same identifier.

Inputs

pic - Existing IFF context, typically returned by
      psdFindCfgForm(); NULL returns NULL.

Result

Next matching sibling context, or NULL if no further match exists.

Notes

The current form ID is reused for the search. The returned
context points into mutable configuration state and is not
independently reference-counted by this function.

psdNumToStr()

Synopsis

STRPTR psdNumToStr(
         UWORD type,
         LONG idx,
         STRPTR defstr );

Function

Look up a human-readable name for a USB value or enumeration.

Inputs

type   - NTS_* lookup category, such as NTS_IOERR or NTS_LANGID.
idx    - Numeric value within the selected category.
defstr - Fallback string returned when no name is available.

Result

Pointer to a static lookup string or the supplied fallback.
The returned pointer is not a new Poseidon allocation.

Notes

The supported categories and mappings are implemented in the
library's lookup tables and switch statement. Callers must not
free a returned table string.

psdOpenStreamA()

Synopsis

APTR psdOpenStreamA(
   APTR pep, struct TagItem *taglist)

Function

Create a buffered pipe stream for an endpoint.

Inputs

pep - Live endpoint with a nonzero maximum packet size.
taglist - PSA_* settings, or NULL for defaults.

Tags

PSA_MessagePort - Dedicated reply port, owned by the caller. If NULL
    or omitted, a port is created for the calling task. The task doing
    blocking stream I/O must receive its signals.
PSA_NumPipes - Pipe count; default 4, minimum 1. USB3 stream-ID
    availability may further limit the count.
PSA_BufferSize - Per-pipe buffer size; minimum one maximum packet.
    Default: 32 packets for IN, 4 for OUT. Allocation products and
    overhead must fit in ULONG; overflow is not checked.
PSA_BufferedRead, PSA_ReadAhead, PSA_AllowRuntPackets - Enabled by
    default for IN. Plain reads do not support read-ahead or terminators.
PSA_BufferedWrite - Retain incomplete output in the stream; default off.
PSA_NoZeroPktTerm - Suppress the automatic zero-length terminator;
    enabled by default for OUT.
PSA_ShortPktTerm - End a buffered read after a non-packet-aligned
    received length. A zero-length packet does not meet this test.
PSA_NakTimeout, PSA_NakTimeoutTime - Enable per-pipe NAK timeout and
    set its duration in milliseconds. Duration defaults to 5000; the
    enable flag defaults off. This is not a whole-operation deadline.
PSA_TermArray - Retained table of eight sorted termination bytes, or
    NULL. Repeating the last value pads a shorter set. The terminator
    is included in the transfer count. See psdStreamWrite() limitations.
PSA_DoNotWait - Return from buffered reads without waiting for more
    data. Does not prevent semaphore waits or hardware submission.
PSA_AbortSigMask - Signals that interrupt supported stream waits.
    Observed abort signals are reasserted for the calling task.
PSA_AsyncIO - Leave disabled: read and write have no async transfer path.
PSA_Error - Initial stored error value; normally leave at zero.
PSA_BytesPending, PSA_ActivePipe - Read-only query attributes.

Result

A stream handle, or NULL for a NULL endpoint or a detected allocation
failure. Close a successfully created stream with psdCloseStream().

Notes

Call in task context. The endpoint determines direction; no endpoint
transfer-type check is made here. Port and terminator-table pointers
are retained; tag-list storage is not. Keep retained objects valid
until close. Do not share the reply port with unrelated traffic.

Stream operations use an access semaphore, but the caller must still
coordinate port signal ownership, configuration changes and lifetime.
Do not change message ports or buffer settings during active I/O.

Bugs

psdSetAttrsA() return status is ignored during setup.
Individual pipe-allocation failures do not make opening fail. A
non-NULL stream can contain missing pipes. Failure cleanup can itself
enter flush with incomplete arrays or a missing port. Non-NULL is
therefore not proof that every resource was initialized successfully.

psdParseCfg()

Synopsis

VOID psdParseCfg(
   )

Function

Apply the in-memory stack configuration to hardware and USB classes,
then scan devices for class bindings.

Result

None. Failures are not returned to the caller.

Notes

May block while opening classes, adding or enumerating hardware,
removing resources, or scanning bindings. Coordinate the call with
other configuration changes and stack lifecycle operations.

If no stack configuration form exists, hardware and class reconciliation
is skipped. If the form has no hardware entries, existing hardware is
preserved. Otherwise hardware absent from the enabled entries is
removed. Classes absent from the configured list are removed, except
resident classes whose use count is nonzero.

Missing classes are opened. Missing enabled hardware is added and
enumerated; hardware whose initial enumeration fails is removed again.
These operations can invalidate existing device and binding handles.

After reconciliation, marks the configuration as read, updates the saved
configuration hash, and calls psdClassScan(). When called by a task
rather than a process, a configured boot delay may wait for hubs and
mass-storage bindings. This call does not save a preferences file.

Bugs

Application is not transactional. Individual add and remove failures
have no aggregate result, and completed changes are not rolled back.
Class opening occurs while the configuration read lock is held; a class
that waits for another task to modify configuration can deadlock.

psdPipeSetup()

Synopsis

void psdPipeSetup(
         struct PsdPipe * pp,
         UWORD rt,
         UWORD rq,
         UWORD val,
         UWORD idx );

Function

Set the USB setup request fields on a control pipe.

Inputs

pp  - Valid control pipe to configure.
rt  - bmRequestType field.
rq  - bRequest field.
val - Host-order wValue field.
idx - Host-order wIndex field.

Notes

The request fields are written into the pipe's setup data. The
two 16-bit values are converted to USB little-endian representation
with AROS_WORD2LE(). For a control transfer, psdDoPipe() or
psdSendPipe() fills wLength from the requested data length.
This function does not submit a transfer or validate the request.

psdReadCfg()

Synopsis

BOOL psdReadCfg(
         struct PsdIFFContext * pic,
         APTR formdata );

Function

Replace a Poseidon configuration context with a serialized IFF
FORM of the same type.

Inputs

pic      - Target IFF context, or NULL for the configuration root.
formdata - Valid serialized IFF FORM buffer with matching form ID.

Result

TRUE when the form data was accepted, otherwise FALSE.

Notes

Takes the configuration write lock, validates the FORM header and
form identifier, and rebuilds the context contents. The serialized
input is not a PsdIFFContext pointer. No rollback guarantee is
established for a failure after partial context modification.

psdReleaseAppBinding()

Synopsis

void psdReleaseAppBinding(
         struct PsdAppBinding * pab );

Function

Request release of an application-owned device binding.

Inputs

pab - Binding returned by psdClaimAppBindingA(), or NULL.

Notes

For a root hub the implementation invokes the local hub release
path. For downstream devices it delegates to the parent hub class
through UCM_HubReleaseDevBinding when that hub is bound. The
binding release path invokes its registered release hook. No
completion or error result is returned.

psdReleaseDevBinding()

Synopsis

VOID psdReleaseDevBinding(
   APTR pd)

Function

Request release of the current device-level class or application binding.

Inputs

pd - Valid, non-NULL device handle. Keep the device alive until return.

Result

None. Dispatch and release failures are not reported.

Notes

Does nothing if the device has no device-level binding. Interface
bindings are not released by this call.

For a root device, calls psdHubReleaseDevBinding() directly. For a
child device, dispatches UCM_HubReleaseDevBinding through its parent
hub class. The supplied hub.class waits for the hub task to finish;
callbacks and that wait may block without a timeout.

The release path can invoke an application release hook or a class
release method. Stop using the binding before requesting release.
Coordinate device lifetime and competing binding operations with the
owner of the device.

Bugs

If the parent hub has no device binding or class binding, the request
is silently skipped. Returning does not by itself prove release.

psdReleaseIfBinding()

Synopsis

VOID psdReleaseIfBinding(
   APTR pif)

Function

Request release of an interface class binding.

Inputs

pif - Valid, non-NULL interface handle whose configuration and device
    remain alive until return.

Result

None. Dispatch and release failures are not reported.

Notes

Does nothing unless both an interface binding and its class are present.
Other interface bindings and the device-level binding are left intact.

For a root device, calls psdHubReleaseIfBinding() directly. Otherwise
dispatches UCM_HubReleaseIfBinding through the parent hub class. The
supplied hub.class waits for the hub task to finish; the class release
callback and that wait may block without a timeout.

Stop using the binding before requesting release. Coordinate interface
and device lifetime and competing binding operations with their owner.

Bugs

If the parent hub has no device binding or class binding, the request
is silently skipped. Returning does not by itself prove release.

psdRemCfgChunk()

Synopsis

BOOL psdRemCfgChunk(
         struct PsdIFFContext * pic,
         ULONG chnkid );

Function

Remove a chunk by identifier, or clear a form's entire contents.

Inputs

pic    - Context to modify, or NULL for the configuration root.
chnkid - Chunk identifier; zero clears the context's entries.

Result

TRUE when an entry was removed or a context was cleared,
otherwise FALSE.

Notes

The exclusive configuration lock protects modification. Clearing
with identifier zero retains the selected context object while
releasing its subordinate forms and chunks.

psdRemCfgForm()

Synopsis

void psdRemCfgForm(
         struct PsdIFFContext * pic );

Function

Remove a configuration FORM and all its nested data.

Inputs

pic - Context to remove, or NULL to select the configuration root.

Notes

Takes the exclusive configuration lock and recursively frees the
selected form. Sets the configuration-check flag after removal.
References to the removed context and its descendants become
invalid. The function returns no status.

psdRemClass()

Synopsis

void psdRemClass(
         struct PsdUsbClass * puc );

Function

Unregister and close a previously installed USB class.

Inputs

puc - Valid class record returned by psdAddClass().

Notes

Removes the class from the global list and tries to release
outstanding device and interface bindings before closing the
class library and freeing the class record. If the class use
count remains nonzero, the release loop retries without a sleep
and may run indefinitely. It sends EHMB_REMCLASS without a
completion status.
The record is invalid after successful teardown.

Bugs

EHMB_REMCLASS is queued after the class record is freed. The
event pointer cannot safely be dereferenced by receivers.

psdRemErrorMsg()

Synopsis

void psdRemErrorMsg(
         struct PsdErrorMsg * pem );

Function

Remove a Poseidon error-log entry and release its storage.

Inputs

pem - Valid error-message record currently linked in the list.

Notes

Unlinks the record under Forbid()/Permit(), frees its origin and
text, and releases the record. An EHMB_REMERRORMSG event is emitted.
The pointer is invalid after this call, and no status is returned.

Bugs

EHMB_REMERRORMSG is emitted after freeing pem; consumers must
not dereference the event pointer.

psdRemEventHandler()

Synopsis

VOID psdRemEventHandler(
   APTR peh)

Function

Remove an event registration and reply to queued port messages.

Inputs

peh - Live registration returned by psdAddEventHandler(), or NULL.

Notes

NULL is ignored. Call in task context. Removes the registration
under the event semaphore, drains its port with GetMsg()/ReplyMsg(),
and frees the registration. No later send can select that registration.
The port itself is not deleted.

Coordinate with the receiving task before removal. Messages already
taken by the consumer are not drained; the consumer must still reply
to each exactly once. Do not reuse the registration handle.

Bugs

Drains every message on the port without checking its origin. Use a
dedicated port, not a port shared with another registration or protocol.

psdRemHardware()

Synopsis

void psdRemHardware(
         struct PsdHardware * phw );

Function

Shut down a registered USB controller and release its stack state.

Inputs

phw - Valid controller returned by psdAddHardware().

Notes

Releases bindings and retires attached devices, then waits for
the controller task to exit. Pending pipe references delay device
teardown, but repeated unsuccessful waits can cause the code to
clear the device use count and continue. The internal device
cleanup releases owned state without freeing the device record.
Controller metadata is freed before EHMB_REMHARDWARE is sent.
No completion status is returned.

Bugs

EHMB_REMDEVICE can carry a retired device whose owned state has
already been released. EHMB_REMHARDWARE carries the pointer to
a freed controller. Event recipients must not dereference either
pointer after the associated teardown.

psdResumeBindings()

Synopsis

BOOL psdResumeBindings(
   APTR pd)

Function

Ask existing class bindings to resume and rescan after a failed callback.

Inputs

pd - Device with a valid current configuration, or NULL. Keep the
    device, configuration and bindings alive throughout the call.

Result

Always TRUE, including for NULL and when a class resume method fails.
The result does not certify that all bindings resumed.

Notes

Requires serialized access to the device and its bindings; this function
takes no device lock. Class callbacks, releases and rescanning can block.
It neither resumes the hub port nor changes the suspended flag.

Sends UCM_AttemptResumeDevice to a device class binding. Application
bindings are left alone. A failed class callback requests release of
that binding and schedules a stack-wide psdClassScan(). The same
handling is applied to the first bound interface in the current
configuration. A rescan can create new bindings; it does not guarantee
replacement of each released binding.

Bugs

Interface traversal stops at the first binding, even if its class
pointer is absent. Later bound interfaces are not resumed. Failures
are not returned and release completion is not checked. A non-NULL
device without a current configuration can cause a NULL dereference.

psdResumeDevice()

Synopsis

BOOL psdResumeDevice(
   APTR pd)

Function

Request port resume through the parent hub, then resume class bindings.

Inputs

pd - Device handle, or NULL. A suspended device must have a valid
    current configuration. Keep the device and parent hub alive until
    return; serialize competing state changes.

Result

TRUE if the device is already marked active, or if the hub resume
method succeeds. FALSE for NULL, an unsupported root-hub resume, a
missing parent binding or class, or a failed hub resume method.
TRUE does not certify successful resumption of all class bindings.

Notes

May block on the device write lock, a hub-task reply, USB control I/O,
class callbacks and rescanning. There is no whole-operation timeout.

Dispatches UCM_HubResumeDevice while holding the device write lock.
The supplied hub.class clears PORT_SUSPEND; after a successful transfer
it clears the suspended flag, sends EHMB_DEVRESUMED and waits 30 ms.
After the hub method returns successfully, this function releases the
lock and calls psdResumeBindings(). The resumed event therefore does
not establish that binding callbacks have finished.

An already-active device returns immediately without resuming bindings.
An active root hub also returns TRUE; resuming a suspended root hub is
unsupported.

Bugs

The binding phase has no usable failure result and only processes the
first bound interface. State checks, hub resume and binding callbacks
are not one atomic transition.

psdSafeRawDoFmtA()

Synopsis

void psdSafeRawDoFmtA(
         STRPTR buf,
         ULONG len,
         CONST_STRPTR fmtstr,
         RAWARG fmtdata );

void psdSafeRawDoFmt(
         STRPTR buf,
         ULONG len,
         CONST_STRPTR fmtstr,
         ... );

Function

Write formatted text into a caller-provided bounded buffer.

Inputs

buf     - Writable output buffer when len is nonzero.
len     - Buffer capacity in bytes, including the terminating NUL.
fmtstr  - Valid RawDoFmt() format string.
fmtdata - Matching RawDoFmt() argument stream.

Notes

Writes at most len bytes through a bounded RawDoFmt() callback,
then sets buf[len - 1] to NUL. With len zero, does nothing.
The callback does not report truncation; callers must not infer
that the complete formatted result was written.

psdSaveCfgToDisk()

Synopsis

BOOL psdSaveCfgToDisk(
   STRPTR filename, BOOL mode)

Function

Write the current configuration to a Poseidon preferences file.

Inputs

filename - NUL-terminated DOS path, valid until return. NULL writes
    both ENVARC:Sys/poseidon.prefs and ENV:Sys/poseidon.prefs, in
    that order. Both writes are attempted.
mode - Ignored by this implementation. Pass FALSE.

Result

TRUE if serialization and opening the destination succeeded. FALSE
if DOS cannot be opened, serialization fails, or opening fails. With
filename NULL, TRUE requires both default-path calls to return TRUE.

Notes

Performs synchronous DOS I/O while holding the configuration read lock.
Opening an existing destination truncates it. There is no temporary-file
replacement or rollback. The filename is not retained. A reported
success updates the saved configuration hash.

Bugs

Write() and Close() results are ignored. TRUE does not establish that
the file was written completely or closed successfully. A failed write
can leave a truncated file and still mark the configuration as saved.
The two default destinations are not updated atomically.

psdSendEvent()

Synopsis

VOID psdSendEvent(
   ULONG ehmt, APTR param1, APTR param2)

Function

Queue a notification for each registration selecting an event.

Inputs

ehmt - EHMB_* event number, not an EHMF_* mask. Use a defined event
    from <libraries/poseidon.h>; the shift count is not validated.
param1, param2 - Event-specific values copied into each notification.
    Pointed-to objects are neither copied nor retained.

Notes

Call in task context; allocation and the event semaphore may wait.
The call queues messages and returns without waiting for recipients.
Each recipient must ReplyMsg() its notification. Replied messages are
reclaimed by Poseidon during subsequent event garbage collection.

Keep event payload lifetime independent of message delivery. An object
address may identify a change without remaining safe to dereference.

Bugs

Allocation failure drops the notification for that recipient without
a return status. Delivery is neither all-or-nothing nor guaranteed.

psdSendPipe()

Synopsis

void psdSendPipe(
         struct PsdPipe * pp,
         APTR data,
         ULONG len );

Function

Submit a pipe transfer without waiting for completion.

Inputs

pp   - Allocated pipe that is not already pending.
data - Transfer buffer, or NULL for a control request without data.
len  - Number of bytes to transfer.

Notes

On a connected device, this function requests resume if needed,
prepares the IO request and queues the pipe to the hardware task.
For a disconnected device, it delays for 50 ms, records
UHIOERR_TIMEOUT and replies to the pipe message without queuing
the hardware transfer. Both paths increment the device busy count.

The buffer and pipe must remain valid and unchanged until their
completion message has been received and handled. The function
does not return a completion status.

psdSetAltInterface()

Synopsis

BOOL psdSetAltInterface(
         struct PsdPipe * pp,
         struct PsdInterface * pif );

Function

Select an alternate setting of a configured USB interface.

Inputs

pp  - Control pipe for the containing device, or NULL to
      select the alternate setting only in Poseidon's local state.
pif - Valid interface or alternate interface to activate.

Result

TRUE when the requested setting is already active or the selected
path succeeds; otherwise FALSE. With pp set to NULL, TRUE does
not confirm any USB transfer or device-side selection.

Notes

Locates the main interface and alternate setting and takes the
device write lock. A non-NULL pp sends SET_INTERFACE followed by
GET_INTERFACE confirmation; with NULL pp the code skips both
requests and rearranges the local interface lists. The list
linkage changes only on the accepted path. USB errors are
reported through Poseidon's log.

psdSetAttrsA()

Synopsis

LONG psdSetAttrsA(
         ULONG type,
         APTR psdstruct,
         struct TagItem * tags );

LONG psdSetAttrs(
         ULONG type,
         APTR psdstruct,
         TAG tag, ... );

Function

Change writable attributes of a Poseidon object.

Inputs

type      - PGA_* object category selecting the attribute table.
psdstruct - Object to update; required when the category uses
            object-specific state.
tags      - Attribute/value tag list for the selected category.

Result

The generic path returns the number of attributes processed by
PackStructureTags(), or -1 if no pack table is available.
PGA_ENDPOINT and PGA_PIPESTREAM return their own processed-tag
counts. The generic result does not include every attribute
handled explicitly.

Notes

Certain device and global configuration tags also update stored
configuration records or schedule a power recalculation. Changing
an attribute is not equivalent to sending a USB control request
unless the corresponding code path explicitly does so.
A nonnegative tag count does not guarantee successful resource
changes: PIPESTREAM reallocation failures are not reflected in
the returned count. Callers must respect object lifetimes and
the lock requirements of data shared with other tasks.

psdSetClsCfg()

Synopsis

BOOL psdSetClsCfg(
         STRPTR owner,
         APTR form );

Function

Store or clear class-specific configuration under an owner name.

Inputs

owner - Valid class or owner identifier string.
form  - Serialized IFFFORM_CLASSDATA, or NULL to clear its contents.

Result

TRUE on successful creation or update, otherwise FALSE.

Notes

Finds the matching class configuration by its owner chunk, or
creates one if none exists. The function updates configuration
change bookkeeping after its write-lock-protected operation.
A NULL form creates or preserves an empty CLASSDATA context rather
than removing the owning class entry itself. If replacement of
an existing CLASSDATA form fails, the routine also attempts the
new-entry path. A failed update may therefore leave an additional
class configuration entry rather than retaining a unique key.

psdSetDeviceConfig()

Synopsis

BOOL psdSetDeviceConfig(
         struct PsdPipe * pp,
         UWORD cfgnum );

Function

Select a USB device configuration through its control pipe.

Inputs

pp     - Valid default-control pipe for the device.
cfgnum - Configuration value to request.

Result

TRUE if SET_CONFIGURATION completed without an I/O error;
otherwise FALSE.

Notes

Records the new configuration number only after a successful
SET_CONFIGURATION transfer. Regardless of transfer success, it
resolves the active configuration pointer from the previously
stored number. If a matching configuration exists, it may query
device status or request remote wakeup. Failure of these later
requests does not change the original transfer result; the
active configuration pointer may remain NULL.

psdSetForcedBinding()

Synopsis

BOOL psdSetForcedBinding(
   STRPTR owner, STRPTR devid, STRPTR ifid)

Function

Store or remove the preferred USB class for a device or interface in
the in-memory configuration.

Inputs

owner - NUL-terminated class name to store. NULL or an empty string
    removes the forced binding.
devid - Non-NULL, NUL-terminated device ID string.
ifid - NUL-terminated interface ID string, or NULL for a device binding.
    Strings must remain valid until return; stored values are copied.

Result

TRUE if the binding was stored, or if removal was requested, including
when no matching binding existed. FALSE if storing could not complete.
Failure can leave configuration changes in place.

Notes

May wait for the configuration write lock. Searches the first matching
device form. Interface removal affects all matching interface forms
within that device; device removal leaves interface bindings intact.

Does not load the named class, verify that it accepts the target, or
release and rebind an existing device. Changes remain in memory until
saved. A changed configuration hash triggers a configuration-change
event; storing a name does not establish a live binding.

Bugs

Updates are not transactional. Allocation failure can remove a previous
value or leave incomplete or duplicate configuration forms. FALSE does
not guarantee that the previous binding remains available.

psdSetUsbDevCfg()

Synopsis

BOOL psdSetUsbDevCfg(
         STRPTR owner,
         STRPTR devid,
         STRPTR ifid,
         APTR form );

Function

Save device- or interface-specific class configuration.

Inputs

owner - Class or owner identifier.
devid - Required USB device identification string.
ifid  - Optional interface identification string; NULL selects
        device-level configuration.
form  - Serialized class-data IFF FORM, or NULL to clear data.

Result

TRUE when the matching configuration was created or updated,
otherwise FALSE.

Notes

Locates or creates the device configuration and optional interface
subform, then associates the owner with its class-data context.
Updates take the configuration write lock. The identifiers are
used as configuration keys; this call does not modify a live USB
device or immediately rebind its interfaces. If updating an
existing class-data form fails, the routine falls back to
creating a new device configuration entry. Duplicate keys and
partially created forms are possible on failure paths.

psdSpawnSubTask()

Synopsis

struct Task * psdSpawnSubTask(
         STRPTR name,
         APTR initpc,
         APTR userdata );

Function

Start a Poseidon worker as a process when DOS is available, or
as an Exec task during early startup.

Inputs

name     - Non-NULL task or process name.
initpc   - Non-NULL entry point for the worker.
userdata - Pointer stored as task user data.

Result

New task pointer, or NULL if argument validation, allocation or
task/process creation fails.

Notes

The DOS path uses CreateNewProcTags() with the configured worker
priority and stack size. The early-boot path allocates an Exec
task, stack and copied name through an attached memory list and
starts it with AddTask(). The returned worker has its own lifetime;
this function does not wait for worker initialization or exit.

psdStartRTIso()

Synopsis

LONG psdStartRTIso(
   APTR prt)

Function

Ask the controller to start a registered real-time ISO handler.

Inputs

prt - Live, stopped handler returned by psdAllocRTIsoHandlerA().

Result

Zero on controller-command success; otherwise the controller I/O
error. NULL returns UHIOERR_BADPARAMS. Success is not a completed
transfer or a guarantee of error-free future frames.

Notes

Call in task context. Serializes neither concurrent lifecycle calls
nor attribute changes; the caller must do so. If the device is
suspended, attempts to resume it before issuing the start command.
Data hooks can run during controller setup. There is no library-level
timeout or rollback guarantee for a failed start.

Each successful start increments the device busy count. Pair it with
one successful psdStopRTIso() before freeing the handler.

Bugs

No running-state guard prevents repeated starts. The device-resume
result is ignored; the returned status belongs to the start command.

psdStopRTIso()

Synopsis

LONG psdStopRTIso(
   APTR prt)

Function

Ask the controller to stop a running real-time ISO handler.

Inputs

prt - Live handler with one unmatched successful psdStartRTIso().

Result

Zero on controller-command success; otherwise the controller I/O
error. NULL returns UHIOERR_BADPARAMS. On failure, do not assume that
the controller has stopped accessing callback state or buffers.

Notes

Call in task context and serialize lifecycle operations. On success,
decrements the device busy count. The registered handler remains
allocated and may be started again. There is no library-level timeout;
callback and buffer quiescence depend on the controller implementation.

Bugs

No running-state guard prevents unmatched or repeated stops. Each
successful command decrements the busy count, even without a matching
successful start.

psdStreamFlush()

Synopsis

LONG psdStreamFlush(
   APTR pps)

Function

Discard pending input or submit buffered output.

Inputs

pps - Live stream.

Result

TRUE after input cleanup or successful output processing; FALSE if
output has no free pipe or its transfer fails. NULL returns -1, which
is nonzero: do not treat every nonzero result as success.

Notes

Call in task context with exclusive lifetime ownership. Takes the
access semaphore and resets the stored error. For IN, aborts and waits
for all pipes, recycles ready replies and discards unread data and
read offsets. Does not clear the read-ahead option.

For OUT, synchronously sends pending bytes using a free pipe. Empty
output succeeds only if a free pipe is present. Does not implement
PSA_DoNotWait or a stream-level abort wait; there is no whole-call
timeout. Query psdGetStreamError() immediately after the operation.

Bugs

Output pending bytes are cleared even when transfer fails, so an
unsent suffix is lost from the stream. Input abort/wait errors are
ignored. FALSE caused by no free output pipe leaves the error zero.
Flush assumes initialized pipe-array and port storage.

psdStreamRead()

Synopsis

LONG psdStreamRead(
   APTR pps, APTR buffer, LONG length)

Function

Read bytes from an IN stream.

Inputs

pps - Live IN stream.
buffer - Writable storage for length bytes. Must remain valid during
    the call and while any in-place read still references it.
length - Nonnegative byte capacity. The legacy -1 mode selects all
    currently buffered bytes without a capacity check; avoid it.
    Other negative values are invalid and are not rejected safely.

Result

Bytes delivered, possibly zero or fewer than requested. Returns -1
for NULL, wrong direction, missing pipe array or detected queue
inconsistency. Zero is not an end-of-file indication. Inspect
psdGetStreamError() even after a nonnegative or partial result.

Notes

Call from the task receiving the stream port signals. Resets the
stored error and holds the access semaphore. Buffered reads consume
ready packets, optionally stop at an included terminator or a short
packet, and may submit read-ahead requests. Zero length can still
collect completions or queue read-ahead; it is not necessarily a no-op.

PSA_DoNotWait applies only to buffered reads. The plain path uses
synchronous pipe I/O and ignores the stream abort mask. A buffered
NAK timeout with received bytes is treated as successful data. Other
observed errors stop that read and disable read-ahead.

An abort signal is reasserted but does not itself set the stream error.
There is no whole-call timeout.

Bugs

The implementation does not validate a non-NULL data buffer.
A buffered read can submit directly into the caller buffer. Early
return on abort or PSA_DoNotWait does not cancel and join that request.
Keep the buffer valid until outstanding reads have been stopped and
waited for, for example through a valid stream's flush or close.
PSA_AsyncIO skips transfer processing and returns zero after validation.
Queue-consistency failures can return -1 with a zero stored error.

psdStreamWrite()

Synopsis

LONG psdStreamWrite(
   APTR pps, APTR buffer, LONG length)

Function

Write bytes to an OUT stream or accept them into its buffer.

Inputs

pps - Live OUT stream.
buffer - Readable storage for length bytes, valid until return.
length - Nonnegative byte count, or -1 for a NUL-terminated string
    whose length fits in LONG. String mode does not send the NUL.
    Other negative values are invalid and are not checked safely.

Result

Bytes accepted, including bytes retained for a later flush when
buffering is enabled. This is not necessarily a transmitted-byte count.
Returns -1 for NULL, wrong direction or missing pipe array. Inspect
psdGetStreamError() even after a positive result; failures can follow
partial device writes. Retrying the entire payload can duplicate data.

Notes

Call from the task receiving the stream port signals. Resets the
stored error and holds the access semaphore. Direct transfers are
waited for before return; buffered tails are copied into stream storage.
An observed abort signal is reasserted, and the active request is
aborted and waited for before returning. There is no whole-call timeout.

A terminator table limits the accepted prefix through its first matched
byte. PSA_DoNotWait does not make writes nonblocking. Use flush to
submit remaining buffered output and inspect that result before close.

Bugs

The implementation does not validate a non-NULL data buffer.
The terminator scan can read table element 8 after checking element 7,
outside the eight-byte table, and its duplicate-value test differs from
the read path. Leave PSA_TermArray NULL for output until corrected.
PSA_AsyncIO skips transfer processing and returns zero after validation.
Buffered error recovery trusts the controller's actual byte count.

psdSuspendBindings()

Synopsis

BOOL psdSuspendBindings(
   APTR pd)

Function

Prepare the device binding and current interface bindings for suspension.

Inputs

pd - Device with a valid current configuration, or NULL. Keep the
    device, configuration and bindings alive throughout the call.

Result

TRUE if traversal finishes without a binding refusing suspension.
FALSE for NULL or a rejected suspension request. TRUE does not mean
that the hub port has been suspended.

Notes

Call in a context that serializes device and binding changes; this
function takes no device lock. Class methods and binding release can
block. psdSuspendDevice() performs this preparation under a device
write lock before asking the hub to suspend the port.

Classes advertising UCCA_SupportsSuspend receive
UCM_AttemptSuspendDevice. A refusal stops traversal. Classes without
that capability are accepted if the device has no active I/O.

When GCA_ForceSuspend is enabled and the current configuration advertises
remote wakeup, application bindings and busy bindings of classes without
suspend support are released. Otherwise an application binding or a busy,
unsupported class causes failure. A suspend-capable class may still veto
suspension when force mode is enabled.

Visits the device binding and every interface in the current
configuration. Released binding handles become invalid. This function
does not change the port state or the device's suspended flag.

Bugs

Failure does not undo earlier class suspension or binding releases.
Release requests have no status, so TRUE cannot establish that forced
release completed. A non-NULL device without a current configuration
is invalid and can cause a NULL dereference.

psdSuspendDevice()

Synopsis

BOOL psdSuspendDevice(
   APTR pd)

Function

Prepare a device for suspension and request suspension of its hub port.

Inputs

pd - Valid, non-NULL device with a current configuration. Keep it and
    its parent hub alive until return; serialize competing state changes.

Result

TRUE if the device is already marked suspended, or if binding
preparation and the dispatched hub method report success. FALSE if
preparation or the hub method fails, or a root hub needs suspension.
See BUGS for the missing-parent-binding case.

Notes

May block on device locks, class callbacks, hub-task replies and USB
control transfers. There is no whole-operation timeout.

Runs psdSuspendBindings() under the device write lock, then dispatches
UCM_HubSuspendDevice under a device read lock. Preparation may release
bindings. The supplied hub.class sets PORT_SUSPEND; on successful control
transfer it marks the device suspended and sends EHMB_DEVSUSPENDED.
This reports command completion, not an independent measurement of
power consumption.

Root-hub suspension is unsupported unless the suspended flag was already
set, in which case the initial state check returns TRUE.

Bugs

If preparation succeeds but the parent has no device binding or class
binding, no hub request is sent and TRUE is still returned. Preparation
is not rolled back after a failed port-suspend request.

NULL is unsafe: the failure diagnostic dereferences pd. State checks and
preparation are not one atomic transition with the subsequent hub call.

psdUnbindAll()

Synopsis

VOID psdUnbindAll(
   )

Function

Release device and interface bindings throughout the stack.

Result

None.

Notes

Visits hardware, devices, configurations and interfaces. Requests one
release, then restarts traversal from the beginning. Returns after a
complete traversal finds no binding. This is not an atomic snapshot
or a guarantee that later scans cannot create new bindings.

Can invoke class release methods and application release hooks, and
can wait for hub tasks. Coordinate stack teardown and exclude concurrent
device removal or rebinding before calling. Devices and hardware are
not explicitly freed by this function, but release callbacks can have
additional effects.

Bugs

There is no timeout or progress check. If a release leaves its binding
in place, the traversal can retry indefinitely. The base read lock is
released before each release request; the selected object is not pinned
across that interval, so concurrent removal can invalidate it.

psdUnlockDevice()

Synopsis

void psdUnlockDevice(
         struct PsdDevice * pd );

Function

Release the current task's lock on a Poseidon device.

Inputs

pd - Valid device whose lock is held; not NULL.

Notes

Calls pUnlockSem() on the device's lock. The function does not
report a completion result. Balance each shared or exclusive
device-lock acquisition with its corresponding release.

psdUnlockPBase()

Synopsis

void psdUnlockPBase();

Function

Release the current task's Poseidon base lock.

Notes

Delegates to pUnlockSem() for the shared/exclusive lock state
held by the calling task. Each acquisition must be balanced with
a corresponding release; this function does not report success
or verify a higher-level lock-order contract.

psdWaitPipe()

Synopsis

LONG psdWaitPipe(
         struct PsdPipe * pp );

Function

Wait for a pending pipe message and return the recorded IO error.

Inputs

pp - Valid pipe with a message port used for its submission.

Result

IO error stored in the pipe request; zero indicates success.

Notes

The function waits on the pipe's message-port signal while the
pipe message remains pending. For a replied message, it removes
the message from the reply queue and marks it free. Signals seen
while waiting are restored for other messages on the port.

The device busy count is decremented and last activity updated.
Transfer errors contribute to a device dead-count heuristic that
can emit EHMB_DEVICEDEAD; improving results can clear the dead flag.
Calling this function without a matching submitted transfer is
not supported by the bookkeeping in this implementation.

psdWriteCfg()

Synopsis

APTR psdWriteCfg(
         struct PsdIFFContext * pic );

Function

Serialize a Poseidon IFF configuration context into an allocated
FORM buffer.

Inputs

pic - Context to serialize, or NULL for the configuration root.

Result

Newly allocated serialized FORM buffer, or NULL when no suitable
root context exists or allocation fails. Free with psdFreeVec().

Notes

The function updates the global configuration fields, marks a
configuration check as needed, measures the serialized form and
writes it to a new buffer while holding the configuration lock.
The serialized FORM contains its IFF size in the header.