?? usbdcorelib.c
字號:
/* usbdCoreLib.c - USBD core logic *//* Copyright 2000-2002 Wind River Systems, Inc. *//*Modification history--------------------01l,08nov01,wef USBD_NODE struture element changed from hubStatus to pHubStatus, reflect this change01k,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 veloce01i,08aug01,dat Removing warnings01h,12aug00,bri Modify interrogateDeviceClass() to 1. Allow multifunction devices that belong to same USB class but have interfaces belonging to different subclasses. 2. Store the configuration Value as mentioned in the configuration descriptor in the nodeClass. 3. Ensure nodeclasses are created for all devices.01g,20mar00,rcb Add USB_DEVICE_DESCR field to USBD_NODE.01f,17jan00,rcb Modify interrogateDeviceClass() to use usbConfigDescrGet()... ensures that all descriptors associated with a configuration descriptor will be read, even if the total length is very long.01e,20dec99,rcb Fix benign bug in fncConfigSet() regarding pRoot. Fix benign bug in HCD detach logic which detached the HCD before deleting all pipes.01d,23nov99,rcb Replace HCD bandwidth alloc/release with pipe create/destroy in order to generalize approach for OHCI HCD.01c,24sep99,rcb Change packet count calculation in transferIrpCallback() to handle case where a single 0-length packet is transferred.01b,07sep99,rcb Add support for management callbacks and set-bus-state API.01a,08jun99,rcb First.*//*DESCRIPTIONThis module contains the primary USBD entry point, usbdUrbExec() and theindividual USBD function execution routines. usbdUrbExec() is responsible for interpreting each URB's function code and then fanning-out to the individual function processor. IMPLEMENTATION NOTESWhen the USBD is first initialized it creates an internal "client" which is used by the USBD when performing control pipe transfers to each hub/device. This"client" remains active until the USBD is shut down.For each client registered with the USBD, including the internal client, the USBDallocates an individual task, and that task inherits the priority of the clienttask which invokes the usbdClientRegister() function. This task is normally inactive, and only wakes up when a client callback is to be executed. Therefore, each client's callbacks are invoked on a task which is unique to that client.Other USBD tasks (see below) are therefore shielded from the behavoir of anindividual client's callback routine.For each USB which is attached to the USBD through the usbdHcdAttach() function,the USBD also creates a unique "bus monitor" task. This task is responsiblefor configuring and monitoring each hub on a given USB. Whenever a hub or deviceis attached/removed from the USB, the bus monitor thread is responsible forupdating internal data structures, configuring/re-configuring hubs, and fortriggering "dynamic attach/removal" callbacks - which themselves are performed byeach individual client's callback task.All USBD internal data structures, e.g., client lists, HCD lists and releatednode structures, are protected by a single mutex, structMutex. All threads whichrely on the stability of internal data structures or which can modify internaldata structures take this mutex. usbdCoreEntry() is the single entry pointresponsible for taking this mutex when clients invoke the USBD. Each "busmonitor" thread also takes this mutex each time it may update bus structures. IRP callback, however, do not take the mutex. While certain IRP "userPtr" fieldsmay point to other USBD structures, the organization of the code guarantees thatIRPs will be completed or canceled prior to dismantling the USBD structures withwhich they are associated.*//* defines */#define USBD_VERSION 0x0001 /* USBD version in BCD */#define USBD_MFG "Wind River Systems, Inc." /* USBD Mfg */#define INTERNAL_CLIENT_NAME "usbd"/* includes */#include "usb/usbPlatform.h"#include "string.h"#include "usb/ossLib.h"#include "usb/usbQueueLib.h"#include "usb/usbLib.h" /* USB utility functions */#include "usb/usbdCoreLib.h" /* our API */#include "drv/usb/usbHcd.h" /* HCD interface */#include "usb/usbHcdLib.h" /* HCD function library */#include "usb/usbdStructures.h" /* usbdCoreLib data structures *//* defines */#define PENDING 1#define CALLBACK_Q_DEPTH 128 /* Needs to be fairly deep to handle */ /* a potentially large number of */ /* notification callbacks */#define BUS_Q_DEPTH 32 /* Outstanding bus service requests *//* clientThread request codes...stored in msg field of OSS_MESSAGE. */#define CALLBACK_FNC_TERMINATE 0 /* Terminate the callback thread */#define CALLBACK_FNC_IRP_COMPLETE 1 /* issue an IRP completion callback */#define CALLBACK_FNC_NOTIFY_ATTACH 2 /* issue an attach callback */#define CALLBACK_FNC_MNGMT_EVENT 3 /* management event callback */#define CALLBACK_TIMEOUT 5000 /* Wait 5 seconds for callback to */ /* exit in response to terminate fnc *//* busThread request codes...stored in msg field of OSS_MESSAGE. */#define BUS_FNC_TERMINATE 0 /* Terminate the bus monitor thread */#define BUS_FNC_UPDATE_HUB 1 /* update a hub */#define BUS_TIMEOUT 5000 /* Wait 5 seconds for bus monitor */ /* thread to terminate *//* general timeout */#define IO_TIMEOUT 5000 /* 5 seconds */#define EXCLUSION_TIMEOUT 10000 /* 10 seconds *//* HUB_STATUS_LEN() returns length of status structure for indicated hub node */#define HUB_STATUS_LEN(pNode) \ min ((pNode->numPorts + 1 + 7) / 8, (int) MAX_HUB_STATUS_LEN)/* Constants used by resetDataToggle(). */#define ANY_CONFIGURATION 0xffff#define ANY_INTERFACE 0xffff#define ANY_ENDPOINT 0xffff/* typedefs *//* NOTIFICATION * * Created by notifyIfMatch() and consumed by client's callback thread. */typedef struct notification { USBD_ATTACH_CALLBACK callback; /* client's callback routine */ USBD_NODE_ID nodeId; /* node being attached/removed */ UINT16 attachCode; /* attach code */ UINT16 configuration; /* config matching notify request */ UINT16 interface; /* interface matching notify request */ UINT16 deviceClass; /* device/interface class */ UINT16 deviceSubClass; /* device/interface sub class */ UINT16 deviceProtocol; /* device/interface protcol */ } NOTIFICATION, *pNOTIFICATION;/* locals */LOCAL int initCount = 0;LOCAL MUTEX_HANDLE structMutex = NULL; /* guards USBD structures */LOCAL LIST_HEAD hcdList = {0}; /* List of attached HCDs */LOCAL LIST_HEAD clientList = {0}; /* list of registered clients */LOCAL USBD_CLIENT_HANDLE internalClient = NULL; /* internal client *//* forward declarations */LOCAL BOOL initHubIrp ( pUSBD_NODE pNode );LOCAL pUSBD_NODE createNode ( pUSBD_BUS pBus, /* node's parent bus */ USBD_NODE_ID rootId, /* root id */ USBD_NODE_ID parentHubId, /* parent hub id */ UINT16 parentHubPort, /* parent hub port no */ UINT16 nodeSpeed, /* node speed */ UINT16 topologyDepth /* this node's depth in topology */ );/* functions *//***************************************************************************** validateClient - Determines if a client handle is valid** RETURNS: TRUE if client valid, else FALSE*/LOCAL BOOL validateClient ( USBD_CLIENT_HANDLE clientHandle, /* client to be validated */ pUSBD_CLIENT *ppClient /* ptr to USBD_CLIENT if valid */ ) { if (usbHandleValidate (clientHandle, USBD_CLIENT_SIG, (pVOID *) ppClient) != OK) return FALSE; return TRUE; }/***************************************************************************** validateNode - Determines if a node handle is valid** RETURNS: TRUE if node valid, else FALSE*/LOCAL BOOL validateNode ( USBD_NODE_ID nodeId, /* Node to be validated */ pUSBD_NODE *ppNode /* ptr to USBD_NODE if valid */ ) { if (usbHandleValidate (nodeId, USBD_NODE_SIG, (pVOID *) ppNode) != OK || (*ppNode)->nodeDeletePending) return FALSE; return TRUE; }/***************************************************************************** validatePipe - Determines if a pipe is valid** RETURNS: TRUE if pipe valid, else FALSE*/LOCAL BOOL validatePipe ( USBD_PIPE_HANDLE pipeHandle, /* pipe to be validated */ pUSBD_PIPE *ppPipe /* ptr to USBD_PIPE if valid */ ) { if (usbHandleValidate (pipeHandle, USBD_PIPE_SIG, (pVOID *) ppPipe) != OK || (*ppPipe)->pipeDeletePending || (*ppPipe)->pNode->nodeDeletePending) return FALSE; return TRUE; }/***************************************************************************** validateUrb - Performs validation checks on URB** Checks the URB length set in the URB_HEADER against the <expectedLen>* passed by the caller. If <pClient> is not NULL, also attempts to* validate the USBD_CLIENT_HANDLE. If successful, stores the client* handle in <pClient>** RETURNS: S_usbdLib_xxxx*/LOCAL int validateUrb ( pVOID pUrb, UINT16 expectedLen, pUSBD_CLIENT *ppClient ) { pURB_HEADER pHeader = (pURB_HEADER) pUrb; if (initCount == 0) return S_usbdLib_NOT_INITIALIZED; if (pHeader->urbLength != expectedLen) return S_usbdLib_BAD_PARAM; if (ppClient != NULL) { if (!validateClient (pHeader->handle, ppClient)) { return S_usbdLib_BAD_HANDLE; } } return OK; }/***************************************************************************** setUrbResult - Sets URB_HEADER.status and .result fields** Based on the <result> parameter passed by the caller, set the * status and result fields in the URB_HEADER of <pUrb>. ** RETURNS: Value of <result> parameter*/LOCAL int setUrbResult ( pURB_HEADER pUrb, /* Completed URB */ int result /* S_usbdLib_xxxx code */ ) { if (result != PENDING) { pUrb->result = result; if (pUrb->callback != NULL) (*pUrb->callback) (pUrb); } return result; }/***************************************************************************** doShutdown - Shut down USBD core lib** RETURNS: N/A*/LOCAL VOID doShutdown (void) { /* unregister any clients which may still be registered */ pUSBD_CLIENT pClient; pUSBD_HCD pHcd; while ((pClient = usbListFirst (&clientList)) != NULL) usbdClientUnregister (pClient->handle); /* detach any HCDs which may still be attached */ while ((pHcd = usbListFirst (&hcdList)) != NULL) usbdHcdDetach (pHcd->attachToken); /* release the structure guard mutex */ if (structMutex != NULL) { OSS_MUTEX_DESTROY (structMutex); structMutex = NULL; } /* Shut down libraries */ usbHandleShutdown (); ossShutdown (); }/***************************************************************************** fncInitialize - Initialize USBD** RETURNS: S_usbdLib_xxxx*/LOCAL int fncInitialize ( pURB_HEADER pUrb ) { int s = OK; if (initCount == 0) { /* Initialize the osServices library */ if (ossInitialize () != OK) return S_usbdLib_GENERAL_FAULT; if (usbHandleInitialize (0 /* use default */) != OK) { ossShutdown (); return S_usbdLib_GENERAL_FAULT; } ++initCount; /* Initialize the lists of HCDs and clients */ if (OSS_MUTEX_CREATE (&structMutex) != OK) s = S_usbdLib_OUT_OF_RESOURCES; memset (&hcdList, 0, sizeof (hcdList)); memset (&clientList, 0, sizeof (clientList)); } if (s == OK) { /* Register an internal client for hub I/O, etc. */ internalClient = NULL; if (usbdClientRegister (INTERNAL_CLIENT_NAME, &internalClient) != OK) s = S_usbdLib_GENERAL_FAULT; } if (s != OK) { doShutdown (); initCount = 0; } return s; }/***************************************************************************** fncShutdown - Shuts down USBD** RETURNS: S_usbdLib_xxxx*/LOCAL int fncShutdown ( pURB_HEADER pUrb ) { int s; /* validate URB */ if ((s = validateUrb (pUrb, sizeof (*pUrb), NULL)) != OK) return s; if (initCount == 1) doShutdown (); --initCount; return s; }/***************************************************************************** clientThread - client callback thread** A separate clientThread() thread is spawned for each registered* client. This thread is responsible for invoking client callback* routines. Using a separate callback thread for each client helps to* ensure that one client's behavior (such as blocking) won't affect the* throughput of other client requests.** By convention, the <param> is a pointer to the USBD_CLIENT structure* for the associated client. This thread waits on the callback queue* in the client structure. At the time this thread is first created,* the USBD_CLIENT structure is only guaranteed to have an initialized* queue...other fields may not yet be initialized.** NOTE: This thread does not need to take the structMutex. The mainline* code ensures that the clientThread() for a given USBD_CLIENT is* terminated prior to dismantling the USBD_CLIENT structure.** RETURNS: N/A*/LOCAL VOID clientThread ( pVOID param /* thread parameter */ ) { pUSBD_CLIENT pClient = (pUSBD_CLIENT) param; USB_MESSAGE msg; pUSB_IRP pIrp; pNOTIFICATION pNotification; /* Execute messages from the callbackQueue until a CLIENT_FNC_TERMINATE message is received. */ do { if (usbQueueGet (pClient->callbackQueue, &msg, OSS_BLOCK) != OK) break; switch (msg.msg) { case CALLBACK_FNC_IRP_COMPLETE: /* invoke a client's IRP callback routine. The msg.lParam * is a pointer to the completed USB_IRP. */ pIrp = (pUSB_IRP) msg.lParam; if (pIrp->userCallback != NULL) (*pIrp->userCallback) (pIrp); break; case CALLBACK_FNC_NOTIFY_ATTACH: /* invoke a client's dynamic attach routine. The msg.lParam * is a pointer to a NOTIFICATION structure. * * NOTE: We dispose of the NOTIFICATION request after * consuming it. */ pNotification = (pNOTIFICATION) msg.lParam; (*pNotification->callback) (pNotification->nodeId, pNotification->attachCode, pNotification->configuration, pNotification->interface, pNotification->deviceClass, pNotification->deviceSubClass, pNotification->deviceProtocol); OSS_FREE (pNotification); break; case CALLBACK_FNC_MNGMT_EVENT: /* invoke a client's managment callback routine. The * msg.wParam is the management code and the msg.lParam is * the USBD_NODE_ID of the root for the affected bus. */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -