www.pudn.com > vxworks_usb.rar > usbLib.c
/* usbLib.c - USB utility functions */
/* Copyright 2000-2002 Wind River Systems, Inc. */
/*
Modification history
--------------------
01l,09nov01,wef Test for NULL on OSS_xALLOC calls, change sizeof () to
structure size macros
01k,25oct01,wef repalce automatic buffer creations with calls to OSS_MALLOC
in places where the buffer is passed to the hardware (related
to SPR 70492).
01j,18sep01,wef merge from wrs.tor2_0.usb1_1-f for veloce
01e,25jul01,jgn fixed spr 69287
01d,26jan00,rcb Modify usbRecurringTime() to accept instead
of .
Add usbDescrCopy32() and usbDescrStrCopy32().
01c,17jan00,rcb Add usbConfigDescrGet() function.
01b,23nov99,rcb Add usbRecurringTime() function.
01a,16jul99,rcb First.
*/
/*
DESCRIPTION
This modules contains miscellaneous functions which may be used by the
USB driver (USBD), USB HCD (USB Host Controller Driver), or by USBD clients.
*/
/* includes */
#include "usb/usbPlatform.h"
#include "string.h"
#include "usb/usbdLib.h"
#include "usb/usbLib.h"
/* defines */
/* USB time constants.
*
* NOTE: The following constants use units of picoseconds for improved
* calculation resolution. The calcTdTime() function - below - rounds
* the final calculated to the next higher nanosecond, and returns the
* calculated value in terms of nanoseconds.
*/
#define TIME_OVRHD_INPUT_NON_ISOCH ((UINT32) 9107000L)
#define TIME_OVRHD_INPUT_ISOCH ((UINT32) 7268000L)
#define TIME_OVRHD_OUTPUT_NON_ISOCH ((UINT32) 9107000L)
#define TIME_OVRHD_OUTPUT_ISOCH ((UINT32) 6265000L)
#define TIME_OVRHD_INPUT_LS ((UINT32) 64060000L)
#define TIME_OVRHD_OUTPUT_LS ((UINT32) 64107000L)
#define TIME_BIT ((UINT32) 83540L)
#define TIME_BIT_LS_INPUT ((UINT32) 676670L)
#define TIME_BIT_LS_OUTPUT ((UINT32) 667000L)
/* BIT_STUFF calculates the worst case number of bits for the indicated
* number of bytes. (The "19" in the following equation is equal to
* 3.167*6. Since 19 is added to the bit total which is then divided by
* 6, this has the effect of ading 3.167 bit times to the total.
*/
#define BIT_STUFF(bytes) ((UINT32) ((((UINT32) bytes) * 8 * 7 + 19) / 6))
/* functions */
/***************************************************************************
*
* usbTransferTime - Calculates bus time required for a USB transfer
*
* This function calculates the amount of time a transfer of a given number
* of bytes will require on the bus - measured in nanoseconds (10E-9 seconds).
* The formulas used here are taken from Section 5.9.3 of Revision 1.1 of the
* USB spec.
*
* , , and should describe the characteristics
* of the pipe/transfer as USB_XFRTYPE_xxxx, USB_DIR_xxxx, and USB_SPEED_xxxx,
* repsectively. is the size of the packet for which the transfer time
* should be calculated. and are the host delay and
* low-speed hub setup times in nanoseconds, respectively, and are host-controller
* specific.
*
* RETURNS: Worst case number of nanoseconds required for transfer
*/
UINT32 usbTransferTime (UINT16 transferType, /* transfer type */
UINT16 direction, /* transfer direction */
UINT16 speed, /* speed of pipe */
UINT32 bytes, /* number of bytes for packet to be calc'd */
UINT32 hostDelay, /* host controller delay per packet */
UINT32 hostHubLsSetup /* host controller time for low-speed setup */
)
{
UINT32 bits = BIT_STUFF (bytes);
UINT32 ps;
if (speed == USB_SPEED_FULL) {
if (direction == USB_DIR_IN) {
if (transferType == USB_XFRTYPE_ISOCH) {
ps = TIME_OVRHD_INPUT_ISOCH + TIME_BIT * bits;
} else {
ps = TIME_OVRHD_INPUT_NON_ISOCH + TIME_BIT * bits;
}
} else {
if (transferType == USB_XFRTYPE_ISOCH) {
ps = TIME_OVRHD_OUTPUT_ISOCH + TIME_BIT * bits;
} else {
ps = TIME_OVRHD_OUTPUT_NON_ISOCH + TIME_BIT * bits;
}
}
} else {
if (direction == USB_DIR_IN) {
ps = TIME_OVRHD_INPUT_LS + 2 * hostHubLsSetup * 1000L + TIME_BIT_LS_INPUT * bits;
} else {
ps = TIME_OVRHD_OUTPUT_LS + 2 * hostHubLsSetup * 1000L + TIME_BIT_LS_OUTPUT * bits;
}
}
ps += hostDelay * 1000L;
return (ps + 999L) / 1000L; /* returns value in nanoseconds */
}
/***************************************************************************
*
* usbRecurringTime - calculates recurring time for interrupt/isoch transfers
*
* For recurring transfers (e.g., interrupt or isochronous transfers) an HCD
* needs to be able to calculate the amount of bus time - measured in
* nanoseconds - which will be used by the transfer.
*
* specifies the type of transfer. For USB_XFRTYPE_CONTROL and
* USB_XFRTYPE_BULK, the calculated time is always 0...these are not recurring
* transfers. For USB_XFRTYPE_INTERRUPT, must express the number
* of bytes to be transferred in each frame. For USB_XFRTYPE_ISOCH,
* must express the number of bytes to be transferred in each second. The
* parameter is treated differently to allow greater flexibility in determining
* the true bandwidth requirements for each type of pipe.
*
* RETURNS: worst case number of nanoseconds required for transfer.
*/
UINT32 usbRecurringTime (UINT16 transferType, /* transfer type */
UINT16 direction, /* transfer direction */
UINT16 speed, /* speed of pipe */
UINT16 packetSize, /* max packet size for endpoint */
UINT32 bandwidth, /* bytes/frame or bytes/sec depending on pipe */
UINT32 hostDelay, /* host controller delay per packet */
UINT32 hostHubLsSetup /* host controller time for low-speed setup */
)
{
UINT16 packets;
UINT32 nanosecondsPerPacket;
UINT16 remainderBytes;
UINT32 remainderNanoseconds;
UINT32 bytesPerFrame;
/* Non-recurring transfers always return 0. */
if (transferType == USB_XFRTYPE_CONTROL || transferType == USB_XFRTYPE_BULK)
return 0;
/* Calculate time for recurring transfer */
if (transferType == USB_XFRTYPE_INTERRUPT)
bytesPerFrame = bandwidth;
else /* transferType == USB_XFRTYPE_ISOCH */
bytesPerFrame = (bandwidth + 999L) / 1000L;
packets = bytesPerFrame / packetSize;
remainderBytes = bytesPerFrame % packetSize;
nanosecondsPerPacket = usbTransferTime (transferType, direction,
speed, packetSize, hostDelay, hostHubLsSetup);
if (remainderBytes > 0)
remainderNanoseconds = usbTransferTime (transferType, direction,
speed, remainderBytes, hostDelay, hostHubLsSetup);
else
remainderNanoseconds = 0;
return packets * nanosecondsPerPacket + remainderNanoseconds;
}
/***************************************************************************
*
* usbDescrParseSkip - search for a descriptor and increment buffer
*
* Searches up to bytes for a descriptor of type matching
* . Returns a pointer to the descriptor if found.
* and are updated to reflect the next location in the buffer and
* the remaining size of the buffer, respectively.
*
* RETURNS: pointer to indicated descriptor, or NULL if descr not found.
*/
pVOID usbDescrParseSkip (pUINT8 * ppBfr, /* buffer to parse */
pUINT16 pBfrLen, /* length of buffer to parse */
UINT8 descriptorType /* type of descriptor being sought */
)
{
pUSB_DESCR_HDR pHdr;
/* The remaining buffer length must be at least two bytes to accommodate
* the descriptor length and descriptorType fields. If not, we're done.
*/
while (*pBfrLen >= sizeof (pHdr->length) + sizeof (pHdr->descriptorType)) {
pHdr = (pUSB_DESCR_HDR) * ppBfr;
if (pHdr->length == 0)
return NULL; /* must be invalid */
*ppBfr += min (pHdr->length, *pBfrLen);
*pBfrLen -= min (pHdr->length, *pBfrLen);
if (pHdr->descriptorType == descriptorType)
return (pVOID) pHdr;
}
return NULL;
}
/***************************************************************************
*
* usbDescrParse - search a buffer for the a particular USB descriptor
*
* Searches up to bytes for a descriptor of type matching
* . Returns a pointer to the descriptor if found.
*
* RETURNS: pointer to indicated descriptor, or NULL if descr not found
*/
pVOID usbDescrParse (pUINT8 pBfr, /* buffer to parse */
UINT16 bfrLen, /* length of buffer to parse */
UINT8 descriptorType /* type of descriptor being sought */
)
{
return usbDescrParseSkip (&pBfr, &bfrLen, descriptorType);
}
/***************************************************************************
*
* usbConfigCountGet - Retrieves number of device configurations
*
* Using the provided by the caller, this function
* reads the 's device descriptor and returns the number of
* configurations supported by the device in .
*
* RETURNS: OK, or ERROR if unable to read device descriptor
*/
STATUS usbConfigCountGet (USBD_CLIENT_HANDLE usbdClientHandle, /* caller's USBD client handle */
USBD_NODE_ID nodeId, /* device node ID */
pUINT16 pNumConfig /* bfr to receive nbr of config */
)
{
USB_DEVICE_DESCR *pDevDescr;
UINT16 actLen;
if ((pDevDescr = OSS_MALLOC (USB_DEVICE_DESCR_LEN)) == NULL)
return ERROR;
/* Read the device descriptor to determine the number of configurations. */
if (usbdDescriptorGet (usbdClientHandle,
nodeId,
USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_DEVICE,
0,
0,
USB_DEVICE_DESCR_LEN,
(UINT8 *) pDevDescr, &actLen) != OK || actLen < USB_DEVICE_DESCR_LEN) {
OSS_FREE (pDevDescr);
return ERROR;
}
if (pNumConfig)
*pNumConfig = pDevDescr->numConfigurations;
OSS_FREE (pDevDescr);
return OK;
}
/***************************************************************************
*
* usbConfigDescrGet - reads full configuration descriptor from device
*
* This function reads the configuration descriptor and all associated
* descriptors (interface, endpoint, etc.) for the device specified by
* . The total amount of data returned by a device is variable,
* so, this function pre-reads just the configuration descriptor and uses
* the "totalLength" field from that descriptor to determine the total
* length of the configuration descriptor and its associated descriptors.
*
* This function uses the macro OSS_MALLOC() to allocate a buffer for the
* complete descriptor. The size and location of the buffer are returned
* in . It is the caller's responsibility to free the
* buffer using the OSS_FREE() macro.
*
* RETURNS: OK, or ERROR if unable to read descriptor
*/
STATUS usbConfigDescrGet (USBD_CLIENT_HANDLE usbdClientHandle, /* caller's USBD client handle */
USBD_NODE_ID nodeId, /* device node ID */
UINT16 cfgNo, /* specifies configuration nbr */
pUINT16 pBfrLen, /* receives length of buffer */
pUINT8 * ppBfr /* receives pointer to buffer */
)
{
USB_CONFIG_DESCR *pCfgDescr;
UINT16 actLen;
UINT16 totalLength;
pUINT8 pBfr;
if ((pCfgDescr = OSS_MALLOC (USB_CONFIG_DESCR_LEN)) == NULL)
return ERROR;
/* Validate parameters. ppBfr must be non-NULL */
if (ppBfr == NULL)
return ERROR;
*ppBfr = NULL;
/* Read the configuration descriptor to determine the totalLengh of the
* configuration.
*/
if (usbdDescriptorGet (usbdClientHandle,
nodeId,
USB_RT_STANDARD | USB_RT_DEVICE,
USB_DESCR_CONFIGURATION,
cfgNo, 0, USB_CONFIG_DESCR_LEN, (UINT8 *) pCfgDescr, &actLen)
!= OK || actLen < USB_CONFIG_DESCR_LEN) {
OSS_FREE (pCfgDescr);
return ERROR;
}
totalLength = FROM_LITTLEW (pCfgDescr->totalLength);
OSS_FREE (pCfgDescr);
if (pBfrLen != NULL)
*pBfrLen = totalLength;
/* Allocate a buffer of totalLength bytes. */
if ((pBfr = OSS_MALLOC (totalLength)) == NULL)
return ERROR;
/* Read the full configuration descriptor. */
if (usbdDescriptorGet (usbdClientHandle, nodeId,
USB_RT_STANDARD | USB_RT_DEVICE, USB_DESCR_CONFIGURATION,
cfgNo, 0, totalLength, pBfr, NULL) != OK) {
OSS_FREE (pBfr);
return ERROR;
}
*ppBfr = pBfr;
return OK;
}
/***************************************************************************
*
* usbHidReportSet - Issues a SET_REPORT request to a USB HID
*
* Using the provided by the caller, this function
* issues a SET_REPORT request to the indicated . The caller
* must also specify the , , , ,
* and . Refer to Section 7.2.2 of the USB HID specification
* for further detail.
*
* RETURNS: OK, or ERROR if unable to issue SET_REPORT request.
*/
STATUS usbHidReportSet (USBD_CLIENT_HANDLE usbdClientHandle, /* caller's USBD client handle */
USBD_NODE_ID nodeId, /* desired node */
UINT16 interface, /* desired interface */
UINT16 reportType, /* report type */
UINT16 reportId, /* report Id */
pUINT8 reportBfr, /* report value */
UINT16 reportLen /* length of report */
)
{
UINT16 actLen;
if (usbdVendorSpecific (usbdClientHandle, nodeId,
USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
USB_REQ_HID_SET_REPORT, (reportType << 8) | reportId, interface,
reportLen, reportBfr, &actLen) != OK || actLen < reportLen)
return ERROR;
return OK;
}
/***************************************************************************
*
* usbHidIdleSet - Issues a SET_IDLE request to a USB HID
*
* Using the provided by the caller, this function
* issues a SET_IDLE request to the indicated . The caller must
* also specify the , , and . If the
* is zero, the idle period is infinite. If is
* non-zero, then it expresses time in 4msec units (e.g., a
* of 1 = 4msec, 2 = 8msec, and so forth). Refer to Section 7.2.4 of the
* USB HID specification for further details.
*
* RETURNS: OK, or ERROR if unable to issue SET_IDLE request.
*/
STATUS usbHidIdleSet (USBD_CLIENT_HANDLE usbdClientHandle, /* caller's USBD client handle */
USBD_NODE_ID nodeId, /* desired node */
UINT16 interface, /* desired interface */
UINT16 reportId, /* desired report */
UINT16 duration /* idle duration */
)
{
return usbdVendorSpecific (usbdClientHandle, nodeId,
USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
USB_REQ_HID_SET_IDLE, (duration << 8) | reportId, interface,
0, NULL, NULL);
}
/***************************************************************************
*
* usbHidProtocolSet - Issues a SET_PROTOCOL request to a USB HID
*
* Using the provided by the caller, this function
* issues a SET_PROTOCOL request to the indicated . The caller
* must specify the and the desired . The
* is expressed as USB_HID_PROTOCOL_xxxx. Refer to Section 7.2.6 of the
* USB HID specification for further details.
*
* RETURNS: OK, or ERROR if unable to issue SET_PROTOCOL request.
*/
STATUS usbHidProtocolSet (USBD_CLIENT_HANDLE usbdClientHandle, /* caller's USBD client handle */
USBD_NODE_ID nodeId, /* desired node */
UINT16 interface, /* desired interface */
UINT16 protocol /* USB_HID_PROTOCOL_xxxx */
)
{
return usbdVendorSpecific (usbdClientHandle, nodeId,
USB_RT_HOST_TO_DEV | USB_RT_CLASS | USB_RT_INTERFACE,
USB_REQ_HID_SET_PROTOCOL, protocol, interface, 0, NULL, NULL);
}
/* End of file. */