📄 c-hoststack.html
字号:
/* Client is registered...application code follows. */ ... ... /* Unregister the client. */ usbdClientUnregister (usbdClientHandle); </pre></font></dl></dl><dl class="margin"><dd><font face="Helvetica, sans-serif" size="-1" class="sans"><h5 class="HU"><i><a name="85584"></a>Client Callback Tasks</i></h5></font><dl class="margin"><dd><p class="Body"><a name="85585"></a>USB operations can be time-critical. For example, both USB interrupt and isochronous transfers depend on timely servicing in order to work correctly. In a host system in which several different USBD clients are present, the possibility always exists for one client to interfere with the timely execution of other clients needing to service time-sensitive USB traffic. The Wind River USBD introduces per-client callback tasks to manage this problem.</p><dd><p class="Body"><a name="85586"></a>Many USB events can result in callbacks to a USBD client. For example, whenever the USBD completes the execution of a USB IRP, the client's IRP callback routine is invoked. Similarly, whenever the USBD recognizes a dynamic attachment event, one or more client's dynamic attachment callback routines are invoked. Instead of invoking these callback routines immediately, the USBD schedules the callbacks to be performed by the callback task for the appropriate USBD client(s). Normally, the callback task for each client is "dormant" (in a blocked state). When the USBD schedules a callback for a specified client, the corresponding client callback task "wakes up" (unblocks) and performs the actual callback. This approach allows the USBD to process all outstanding USB events before the clients themselves obtain control of the CPU.</p><dd><p class="Body"><a name="85587"></a>The callback task for each client inherits the VxWorks task priority of the task that originally called <b class="routine">usbdClientRegister( )</b>. This ensures that callbacks are processed at the task priority level intended by each client and allows you to write clients to take advantage of task priorities as a means of ensuring proper scheduling of time-sensitive USB traffic.</p><dd><p class="Body"><a name="85588"></a>Because each client has its own callback task, clients have greater flexibility in the amount of work they can do during the callback. For example, during callback, it is acceptable for executing code to block without hurting the performance of the USBD or other USBD clients.</p><dd><p class="Body"><a name="85589"></a>Client callback tasks have the VxWorks task name <b class="symbol_lc">tUsbdCln</b>.</p></dl><dd><font face="Helvetica, sans-serif" size="-1" class="sans"><h5 class="HU"><i><a name="85590"></a>USBD Internal Client</i></h5></font><dl class="margin"><dd><p class="Body"><a name="85591"></a>When first initialized, the USBD registers an internal "client" that is used to track USB requests generated by the USBD itself. Only one such internal client is created, regardless of the number of calls to <b class="routine">usbdInitialize( )</b>.</p><dd><p class="Body"><a name="85592"></a>What types of USB requests can the USBD generate? All USBD communication with USB devices is made using the same calls available to USBD clients. For example, all control pipe requests to a device are made using a control pipe that the USBD creates automatically when a device is first attached to the system. Just as a USBD client would use <b class="routine">usbdPipeCreate( )</b> to create a pipe to talk to a USB device endpoint, the USBD itself creates a control pipe to talk to endpoint 0 (the default control endpoint) on each device. All internal USBD and external USBD client calls to routines like <b class="routine">usbdDescriptorGet( ) </b>or <b class="routine">usbdFeatureSet( )</b> are routed through this pipe.</p><dd><p class="Body"><a name="85593"></a>So, the USBD is actually using its own entry points recursively, and the internal client is the USBD's mechanism for tracking these requests.</p></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="85595"></a>Dynamic Attachment Registration</i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="85596"></a>A typical USBD client wants to be notified whenever a device of a particular type is attached to or removed from the system. By calling the <b class="routine">usbdDynamicAttachRegister( )</b> routine, a client can specify a callback routine to request such notification.</p><dd><p class="Body"><a name="85597"></a>USB device types are identified by a class, subclass, and protocol. Standard USB classes are defined in <b class="file">usb.h</b> as <b class="symbol_UC">USB_CLASS_</b><i class="textVariable">xxxx</i>. Subclass and protocol definitions depend on the class; therefore, these constants are generally defined in the header files associated with a specific class.</p><dd><p class="Body"><a name="85598"></a>Sometimes, a client is interested in a narrow range of devices. In this case, it specifies values for the class, subclass, and protocol when registering through <b class="routine">usbdDynamicAttachRegister( )</b>. For example, the USB keyboard class driver, <b class="library">usbKeyboardLib</b>, registers for a Human Interface Device (HID) class of <b class="symbol_UC">USB_CLASS_HID</b>, a subclass of <b class="symbol_UC">USB_SUBCLASS_HID_BOOT</b>, and a protocol of <b class="symbol_UC">USB_PROTOCOL_HID_BOOT_KEYBOARD</b> (both the subclass and protocol are defined in <b class="file">usbHid.h</b>). In response, by means of the callback mechanism, the USBD notifies the keyboard class driver whenever a device matching exactly these criteria is attached to or removed from the system. </p><dd><p class="Body"><a name="85599"></a>In other cases, a client's interest is broader. In this case, the constant <b class="symbol_UC">USBD_NOTIFY_ALL</b> (defined in <b class="file">usbdLib.h</b>) can be substituted for any or all of the class, subclass, and protocol match criteria. For example, the USB printer class driver, <b class="library">usbPrinterLib</b>, registers for a class of <b class="symbol_UC">USB_CLASS_PRINTER</b>, subclass of <b class="symbol_UC">USB_SUBCLASS_PRINTER</b> (defined in <b class="file">usbPrinter.h</b>), and a protocol of <b class="symbol_UC">USBD_NOTIFY_ALL</b>.</p><dd><p class="Body"><a name="85600"></a>While a typical client makes only a single call to <b class="routine">usbdDynamicAttachRegister( )</b>, there is no limit to the number of concurrent notification requests a client can have. A single client can register concurrently for attachment notification of as many device types as desired. </p><dd><p class="Body"><a name="85601"></a>The following code fragments demonstrate the correct use of the dynamic attachment registration functions:</p></dl><dl class="margin"><dd><font color="0000a0"><pre class="Code"><a name="85602"></a>/*************************************************************************** * * attachCallback - called by USBD when a device is attached/removed * * The USBD invokes this callback when a USB device is attached to or * removed from the system. <nodeId> is the USBD_NODE_ID of the node being * attached or removed. <attachAction> is USBD_DYNA_ATTACH or * USBD_DYNA_REMOVE. * * RETURNS: N/A */ LOCAL VOID attachCallback ( USBD_NODE_ID nodeId, UINT16 attachAction, UINT16 configuration, UINT16 interface, UINT16 deviceClass, UINT16 deviceSubClass, UINT16 deviceProtocol ) { /* Depending on the attachment code, add or remove a device. */ switch (attachAction) { case USBD_DYNA_ATTACH: /* A device is being attached. */ printf ("New device attached to system.\n"); break; case USBD_DYNA_REMOVE: /* A device is being detached. */ printf ("Device removed from system.\n"); break; } }</pre></font></dl><dl class="margin"><dd><p class="Body"><a name="85603"></a>Somewhere in the initialization of the application, the following code fragment should also appear:</p></dl><dl class="margin"><dd><font color="0000a0"><pre class="Code"><a name="85604"></a> /* Register for dynamic notification when a USB device is attached to or * removed from the system. For the sake of demonstration, we'll request * notification for USB printers, though this same code could be used for * any other type of device. * * usbdClientHandle is the USBD_CLIENT_HANDLE for the client. * USB_CLASS_PRINTER is defined in usb.h. USB_SUBCLASS_PRINTER is * defined in usbPrinter.h. USBD_NOTIFY_ALL is a wild-card that * matches anything. In this case we use it to match any USB programming * interface. */ if (usbdDynamicAttachRegister (usbdClientHandle, USB_CLASS_PRINTER, USB_SUBCLASS_PRINTER, USBD_NOTIFY_ALL, attachCallback) != OK) { /* Attempt to register for dynamic attachment notification failed. */ return ERROR; } /* attachCallback() - above - is now called whenever a USB keyboard * is attached or removed from the system. */ ... ... /* Cancel the dynamic attachment registration. Each parameter must match * exactly those found in an earlier call to usbdDynamicAttachRegister(). */ usbdDynamicAttachUnRegister (usbdClientHandle, USB_CLASS_PRINTER, USB_SUBCLASS_PRINTER, USBD_NOTIFY_ALL, attachCallback); </pre></font></dl></dl><dl class="margin"><dd><font face="Helvetica, sans-serif" size="-1" class="sans"><h5 class="HU"><i><a name="85605"></a>Node IDs</i></h5></font><dl class="margin"><dd><p class="Body"><a name="85606"></a>USB devices are always identified using a <b class="symbol_UC">USBD_NODE_ID</b>. The <b class="symbol_UC">USBD_NODE_ID</b> is, in effect, a handle created by the USBD to track a device; it has no relationship to the device's actual USB address. This reflects the fact that clients are usually not interested in knowing to which USB/host controller a device is physically attached. Because each device is referred to using the abstract concept of a node ID, the client can remain unconcerned with the details of physical device attachment and USB address assignment, and the USBD can manage these details internally.</p><dd><p class="Body"><a name="85607"></a>When a client is notified of the attachment or removal of a device, the USBD always identifies the device in question using the <b class="symbol_UC">USBD_NODE_ID</b>. Likewise, when the client wishes to communicate through the USBD with a particular device, it must pass the <b class="symbol_UC">USBD_NODE_ID</b> for that device to the USBD.</p></dl><dd><font face="Helvetica, sans-serif" size="-1" class="sans"><h5 class="HU"><i><a name="85608"></a>Bus Enumeration Routines</i></h5></font><dl class="margin"><dd><p class="Body"><a name="85609"></a>The <b class="library">usbdLib</b> module exports the routines <b class="routine">usbdBusCountGet( )</b>, <b class="routine">usbdRootNodeIdGet( )</b>, <b class="routine">usbdHubPortCountGet( )</b>, <b class="routine">usbdNodeIdGet( )</b>, and <b class="routine">usbdNodeInfoGet( )</b>. As a group, these are referred to as bus enumeration routines, and they allow USBD clients to enumerate the network of devices attached to each host controller.</p><dd><p class="Body"><a name="85610"></a>These routines are useful in the authoring of diagnostic tools and test programs such as <b class="command">usbTool</b>. However, when the caller uses these routines, it has no way of knowing if the USB topology changes after enumeration or even mid-enumeration. Therefore, authors of traditional clients, such as USB class drivers, are advised not to use these routines.</p></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="85611"></a>Device Configuration</i></h4></font><dl class="margin"><dl class="margin"><dd><p class="Body"><a name="85612"></a>The USB specification defines a set of standard requests, a subset of which must be supported by all USB devices. Typically, a client uses these functions to interrogate a device's "descriptors"--thus determining the device's capabilities--and to set a particular device configuration.</p><dd><p class="Body"><a name="85613"></a>The USBD itself takes care of certain USB configuration issues automatically. Most critically, the USBD internally implements the code necessary to manage USB hubs and to set device addresses when new devices are added to the USB topology. Clients must not attempt to manage these functions themselves, for doing so is likely to cause the USBD to malfunction.</p><dd><p class="Body"><a name="85614"></a>The USBD also monitors so-called <i class="term">configuration events</i>. When a USBD client invokes a USBD function that causes a configuration event, the USBD automatically resets the USB data toggles (<b class="symbol_UC">DATA0</b> and <b class="symbol_UC">DATA1</b>) associated with the device's pipes and endpoints. For example, a call to the USB command <b class="routine">usbdConfigurationSet( )</b> issues the set configuration command to the device, and in the process resets the data toggle to <b class="symbol_UC">DATA0</b>. Because the USBD handles USB data toggles automatically, you do not typically need to concern yourself with resetting data toggles. For an explanation of pipes and endpoints in the USB environment, see <a href="c-hostStack.html#85621"><i class="title">Data Flow</i></a>. For more information about USB data toggles, see the <i class="title">USB Specification</i>.</p><dd><p class="Body"><a name="85618"></a>Device configuration depends heavily on the type of device being configured. The following code fragment demonstrates how to read and parse a typical device descriptor:</p></dl><dl class="margin"><dd><font color="0000a0"><pre class="Code"><a name="85619"></a> UINT8 bfr [USB_MAX_DESCR_LEN]; /* USB_MAX_DESCR_LEN defined in usb.h */ UINT16 actLen; pUSB_CONFIG_DESCR pCfgDescr; /* USB_CONFIG_DESCR defined in usb.h */ pUSB_INTERFACE_DESCR pIfDescr; /* USB_INTERFACE_DESCR is also in usb.h */ /* Read the configuration descriptor. In the following fragment it is * assumed that nodeId was initialized, probably in response to an * earlier call to the client's dynamic attachment notification callback * (see above). */ if (usbdDescriptorGet (usbdClientHandle, nodeId, USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_CONFIGURATION, 0, 0, sizeof (bfr), bfr, &actLen) != OK) { /* We failed to read the device's configuration descriptor. */ return FALSE; } /* Use the function usbDescrParse() - exported by usbLib.h - to extract * the configuration descriptor and the first interface descriptor from * the buffer. */ if ((pCfgDescr = usbDescrParse (bfr, actLen, USB_DESCR_CONFIGURATION)) == NULL) { /* No configuration descriptor was found in the buffer. */ return FALSE; } if ((pIfDescr = usbDescrParse (bfr, actLen, USB_DESCR_INTERFACE)) == NULL) { /* No interface descriptor was found in the buffer. */ return FALSE; } </pre></font></dl></dl><font face="Helvetica, sans-serif" class="sans"><h4 class="H4"><i><a name="85621"></a>Data Flow</i></h4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -