Files
m241Neelima/vxworks-6.9/target/src/drv/usb2/mouse/usb2Mse.c
T
2026-07-30 11:19:44 +05:30

1764 lines
50 KiB
C

/* usb2Mse.c - USB Mouse class driver using the WRS USB2 API */
/*
* Copyright (c) 2008-2011, 2013, 2015, 2018 Wind River Systems, Inc.
*
* The right to copy, distribute, modify, or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
01z,28aug18,whu Unblock the task pended on hInSem semaphore when close the
device (VXW6-86870)
01y,25feb15,j_x Correct the invalid statement of iosDrvInstall return (VXW6-84185)
01x,02jul13,wyy Remove compiler warning (WIND00423315)
01w,28apr13,ghs Add support of USB message (WIND00411952)
01v,04jan13,s_z Remove compiler warning (WIND00390357)
01u,01aug11,ghs Fix VxWorks version check macro (WIND00287708)
01t,22nov10,ghs Code Coverity CID(9703): CHECKED_RETURN (WIND00242477)
01s,06jul10,m_y Set all the resources to NULL after release (WIND00183499)
01r,30jun10,ghs Change display log when device remove(WIND00216586)
01q,24may10,m_y Add parameter valid check for usb robustness (WIND00183499)
01p,18may10,w_x USB transition to vxbDmaBufLib supporting 64 bit (WIND00193267)
01o,27apr10,j_x Add usb2HidProtoGet\Set ioctl for usbGen2Show (WIND00184395)
01n,30mar10,w_x Back port GEN2 class drivers for old VxWorks (WIND00192167)
01m,16mar10,pkr Get buffer size from descriptor. Some mice do not work with
buffer size 3 (WIND00203885)
01l,03mar10,j_x Changed for USB debug (WIND00184542)
01k,04mar10,m_y Cancel URB at close routine.(WIND00200272)
01j,13jan10,ghs vxWorks 6.9 LP64 adapting
01i,03nov09,w_x Fix URB callback and control URB cancel deadlock (WIND00189102)
01h,29oct09,ghs Change default debug level(WIND00188349)
01g,21oct09,w_x Modifications for Kernel API references (WIND00187268)
01f,27aug09,w_x Unify log mechanism and variable naming with some compiler
warning removal in USB GEN2 class drivers (WIND00178936)
01e,25aug09,w_x make sure selWakeupListTerm is called if registered
(WIND00175211)
01d,23apr09,w_x Coding convention changes
01c,26feb09,w_x Remove dead lock condition in usb2MseDeviceRemove
01b,24feb09,w_x Remove dead lock conditon in usb2MseDeviceAdd
01a,05Nov08,adh written
*/
/*
DESCRIPTION
This module implements the USB mouse class driver for the vxWorks operating
system. This is a character driver and is written using the Wind River USB
2.x API.
INITIALIZATION
This driver is initialized by calling usb2MseInit(), with a name parameter
specifying the default name of the device. The driver will register with the
USBD and thus will detect any existing connections as well as future device
connections.
Prior to calling usb2MseInit(), the caller must ensure that the USBD has been
properly initialized.
It is also the caller's responsibility to ensure that at least one USB HCD
(USB Host Controller Driver) is attached to the USBD before the mouse
operation can begin.
OTHER FUNCTIONS
usb2Mse.c also supports the ioctl interface. The following ioctl codes
are supported:
\ml
\m 1. FIONREAD
get num chars available to read.
\m 2. FIOSELECT
register the task for waking up when data is available.
\m 3. FIOUNSELECT
deregister the task for waking up when data is available.
\m 4. USB2_IOCTL_HID_IDLE_TIME_GET
get the current idle time as specified in the HID specification.
\m 5. USB2_IOCTL_HID_IDLE_TIME_SET
set the idle time as specified in the HID specification.
\me
DATA FLOW
For each USB mouse connected to the system, the USBD will attach each
interface of the device to the appropriate class driver deviceAdd routine.
The device is then mounted in the iosLib, and the application can start doing
I/O requsts to the device driver.
INCLUDE FILES: vxWorks.h selectLib.h semLib.h logLib.h errno.h errnoLib.h
iosLib.h rngLib.h usb2/usb2Mse.h
*/
/* includes */
#include <vxWorks.h>
#include <selectLib.h>
#include <semLib.h>
#include <logLib.h>
#include <errno.h>
#include <errnoLib.h>
#include <iosLib.h>
#include <rngLib.h>
#include <usb2/usb2Mse.h>
/* defines */
/* default device name */
#ifndef USB2_MSE_DEVICE_BASE_NAME
#define USB2_MSE_DEVICE_BASE_NAME "/usb2Mse/"
#endif
#ifndef USB2_MSE_DEFAULT_IN_BUFFER_NUM_ELEM
#define USB2_MSE_DEFAULT_IN_BUFFER_NUM_ELEM 1024
#endif
/* typedefs */
/* mouse device structure */
typedef struct usb2_mse_device
{
DEV_HDR deviceHeader; /* I/O system device header */
USB2_CLASS_DEVICE * pClassDevice; /* Generic class device info */
SEM_ID hInSem; /* signaling sem, in transfer*/
SEM_ID hReadMutex; /* Protect concurrent read */
USBHST_URB * pInUrb; /* In transfer URB */
UINT32 uInBufferNbElem; /* In ring buffer elements */
RING_ID hInRingBuffer; /* In ring buffer handle */
UINT8 bInEndPointAddr; /* In endpoint addr */
int deviceTimeout; /* Timeout (ms) to wait reqs. */
USB2_FILE_DESC * pReader; /* Reader file descriptor */
USB2_MSE_REPORT * pReport; /* Report structure read */
UINT16 uReportSize; /* Report structure read size */
UINT8 uIdleTime; /* Idle time */
BOOL bTransferInCourse; /* Is a transfer running? */
SEL_WAKEUP_LIST * pSelWakeupList; /* Select wakeup list */
BOOL bSelListInitialized; /* above list initialized */
} USB2_MSE_DEVICE;
/* locals */
LOCAL int usb2MseDrvNum = 0;
/* globals */
/*
* This will contain the Data used to register to the usbd,
* and some driver info
*/
USB2_CLASS_DRIVER * pUsb2MseDriver = NULL;
/*******************************************************************************
*
* usb2MseInUrbCompleteCallback - callback called when a in transfer is done
*
* This routine is called from the USBD on a interrupt in request
* completion.
*
* RETURNS: USBHST_SUCCESS, or other USBHST_STATUS value if there is any failure.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL USBHST_STATUS usb2MseInUrbCompleteCallback
(
pUSBHST_URB pUrb /* Pointer to the IN URB structure that is completed. */
)
{
USB2_MSE_DEVICE * pDevice = NULL;
STATUS status = ERROR;
USBHST_STATUS hstStatus = USBHST_SUCCESS;
size_t nBytes = 0;
if ((NULL == pUrb) || (NULL == pUrb->pContext))
{
USB2_MSE_ERR("Invalid Parameter\n", 1, 2, 3, 4, 5, 6);
return USBHST_INVALID_PARAMETER;
}
USB2_MSE_VDBG("usb2MseInUrbCompleteCallback(): "
"URB returned with result %p\n",
pUrb->nStatus, 2, 3, 4, 5, 6);
pDevice = (USB2_MSE_DEVICE* ) pUrb->pContext;
pDevice->bTransferInCourse = FALSE;
status = usb2TakeDevice (pDevice->pClassDevice);
if (ERROR == status)
{
USB2_MSE_ERR("usb2MseInUrbCompleteCallback(): "
"Cannot take device ownership\n",1,2,3,4,5,6);
return USBHST_FAILURE;
}
/*
* Fill the buffer for what we have been getting, if the URB
* has been transferred properly. If there is a transfer ERROR
* with the URB, that means that THIS URB is not proper,
* so ignore the content.We should only reporting
* full packets, do not insert partial packets into the ring
* buffer.
*/
if ((USBHST_SUCCESS == pUrb->nStatus) &&
(pUrb->uTransferLength >= sizeof(USB2_MSE_REPORT)))
{
nBytes = rngBufPut(pDevice->hInRingBuffer,
(char*) pDevice->pReport,
sizeof(USB2_MSE_REPORT));
if (pDevice->pReader)
{
if (0 < selWakeupListLen(pDevice->pSelWakeupList) )
{
selWakeupAll (pDevice->pSelWakeupList, SELREAD);
}
}
/* Signal the waiting task that the transfer has finished */
semGive (pDevice->hInSem);
USB2_MSE_DBG("usb2MseInUrbCompleteCallback(): Inserted %d bytes"
"in the Device Ring buffer, %d bytes available \n",
nBytes, rngFreeBytes(pDevice->hInRingBuffer), 3, 4, 5, 6);
}
/*
* If there is no file descriptor,
* suspend communicating with the device
*/
if (NULL == pDevice->pReader)
{
USB2_MSE_DBG("usb2MseInUrbCompleteCallback(): File descriptor has "
"been closed, return here without submitting \n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDevice(pDevice->pClassDevice);
return USBHST_SUCCESS;
}
USBHST_FILL_INTERRUPT_URB(pDevice->pInUrb,
pDevice->pClassDevice->hDevice,
pDevice->bInEndPointAddr,
(UCHAR*) pDevice->pReport,
pDevice->uReportSize,
USBHST_SHORT_TRANSFER_OK,
usb2MseInUrbCompleteCallback,
(void *) pDevice,
USBHST_SUCCESS
);
USB2_MSE_VDBG("usb2MseInUrbCompleteCallback(): "
"Resubmitting URB...\n", 1, 2, 3, 4, 5, 6);
/* Prepare requesting data */
pDevice->bTransferInCourse = TRUE;
hstStatus = usbHstURBSubmit(pDevice->pInUrb);
if (USBHST_SUCCESS != hstStatus)
{
pDevice->bTransferInCourse = FALSE;
/* Something wrong with the device */
USB2_MSE_ERR("usb2MseInUrbCompleteCallback():"
"Submitting URB failed : %d\n", hstStatus, 2, 3, 4, 5, 6);
}
USB2_MSE_VDBG("usb2MseInUrbCompleteCallback(): "
"URB Submitted with Status %d\n", hstStatus, 2, 3, 4, 5, 6);
/* And return */
usb2ReleaseDevice(pDevice->pClassDevice);
return (hstStatus);
}
/*******************************************************************************
*
* usb2MseIosOpen - io open call
*
* This routine checks the IO of the device, and creates a file descriptor
* to allow user application to read the mouse data.
*
* RETURNS: pointer to the USB2_FILE_DESC, or ERROR if any failure.
*
* ERRNO: EIO, ENOMEM
*
* \NOMANUAL
*/
LOCAL ULONG usb2MseIosOpen
(
DEV_HDR * pDevHdr,
char * notUsed,
int flags,
int mode
)
{
USB2_MSE_DEVICE * pDevice = (USB2_MSE_DEVICE * ) pDevHdr;
USB2_FILE_DESC * pFd; /* File descriptor structure used */
USBHST_STATUS hstStatus;
USB2_MSE_VDBG ("usb2MseIosOpen(): Opening the Mouse : "
"mode 0x%X, flags 0x%X\n", mode, flags, 3, 4, 5, 6);
if (OK != usb2TakeDevice (pDevice->pClassDevice))
{
USB2_MSE_ERR ("usb2MseIosOpen(): "
"Cannot take device ownership\n",
1, 2, 3, 4, 5, 6);
errnoSet(EINVAL);
return (ULONG)ERROR;
}
/*
* We don't want the device to be created and do not support
* write to a mouse device, so refuse these flags
*/
if ((O_RDWR & flags) || (O_WRONLY & flags) || (O_CREAT & flags ))
{
USB2_MSE_ERR("usb2MseIosOpen():"
"Device not writable/creatable \n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDevice(pDevice->pClassDevice);
errnoSet(EINVAL);
return (ULONG)ERROR;
}
/*
* And we support only one fd reading at the time, so if the
* pDevice->pReader is not NULL, then someone has already opened
* the device, so we should return with ERROR here.
*/
if (NULL != pDevice->pReader)
{
USB2_MSE_ERR("usb2MseIosOpen(): Driver only "
"allows one reader, another fd is open, return error \n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDevice (pDevice->pClassDevice);
errnoSet (EINVAL);
return (ULONG)ERROR;
}
/* Create the file descriptor structure */
pFd = (USB2_FILE_DESC *) OSS_CALLOC (sizeof(USB2_FILE_DESC));
if (NULL == pFd)
{
USB2_MSE_ERR ("usb2MseIosOpen():Cannot allocate data\n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDevice(pDevice->pClassDevice);
errnoSet(ENOMEM);
return (ULONG)ERROR;
}
/* Initialize the file descriptor structure */
pFd->pDevice = pDevice;
pFd->fdType = (UINT32)flags;
pDevice->pReader = pFd;
/* Flush the ring buffer so that no previous data is in it */
rngFlush(pDevice->hInRingBuffer);
USB2_MSE_DBG ("usb2MseIosOpen(): Device set to READ %p \n",
pFd, 2, 3, 4, 5, 6);
USBHST_FILL_INTERRUPT_URB(pDevice->pInUrb,
pDevice->pClassDevice->hDevice,
pDevice->bInEndPointAddr,
(UCHAR*) pDevice->pReport,
pDevice->uReportSize,
USBHST_SHORT_TRANSFER_OK,
usb2MseInUrbCompleteCallback,
(void *) pDevice,
USBHST_SUCCESS
);
USB2_MSE_VDBG("usb2MseIosOpen(): Submit an URB to start getting data \n",
1, 2, 3, 4, 5, 6);
/*
* Submitting the URB starts the I/O on this instance of the mouse
*/
pDevice->bTransferInCourse = TRUE;
if ((hstStatus = usbHstURBSubmit(pDevice->pInUrb)) != USBHST_SUCCESS)
{
USB2_MSE_ERR("usb2MseIosOpen(): usbHstURBSubmit failed %d\n",
hstStatus, 2, 3, 4, 5, 6);
errnoSet (EIO);
pDevice->bTransferInCourse = FALSE;
pDevice->pReader = NULL;
OSS_FREE (pFd);
usb2ReleaseDevice(pDevice->pClassDevice);
return (ULONG)ERROR;
}
usb2ReleaseDevice(pDevice->pClassDevice);
return (ULONG) pFd;
}
/*******************************************************************************
*
* usb2MseIosClose - io close call
*
* This routine closes the FD to this device.
*
* RETURNS: OK, or ERROR if there is any failure.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL int usb2MseIosClose
(
USB2_FILE_DESC * pFd /* File descriptor used by the application */
)
{
USB2_MSE_DEVICE * pDevice = pFd->pDevice;
USB2_MSE_DBG("usb2MseIosClose(): Closing the Mouse %s\n",
pDevice->deviceHeader.name, 2, 3, 4, 5, 6);
if (OK != usb2TakeDevice (pDevice->pClassDevice))
{
USB2_MSE_ERR("usb2MseIosClose():"
"Cannot take device ownership\n", 1, 2, 3, 4, 5, 6);
return ERROR;
}
if (pDevice->pReader == pFd)
{
USB2_MSE_VDBG("usb2MseIosClose(): Reset device reader to NULL.\n",
1, 2, 3, 4, 5, 6);
pDevice->pReader = NULL;
if (pDevice->hInSem)
(void) semFlush(pDevice->hInSem);
}
/* Cancel the active URB */
(void) usbHstURBCancel(pDevice->pInUrb);
OSS_FREE (pFd);
usb2ReleaseDevice(pDevice->pClassDevice);
return OK;
}
/*******************************************************************************
*
* usb2MseIosRead - io read call
*
* This routine reads the device and stores data to the application buffer.
*
* RETURNS: ERROR or number of bytes read.
*
* ERRNO: EIO
*
* \NOMANUAL
*/
LOCAL ssize_t usb2MseIosRead
(
USB2_FILE_DESC * pFd, /* File descriptor used by application */
char * pBuffer, /* Buffer to read to */
size_t bfrSize /* Number of bytes to read */
)
{
USB2_MSE_DEVICE * pDevice = pFd->pDevice;
STATUS status = ERROR;
size_t nBytes = 0;
USB2_MSE_VDBG("usb2MseIosRead(): Start a read %d bytes, to buffer %p\n",
bfrSize, pBuffer, 3, 4, 5, 6);
/* Take the device, and check for usability */
status = usb2TakeDevice (pDevice->pClassDevice);
if (OK != status)
{
USB2_MSE_ERR("usb2MseIosRead(): "
"Cannot take device ownership\n",
1, 2, 3, 4, 5, 6);
errnoSet(EIO);
return ERROR;
}
/* How many data is already here ? */
nBytes = rngNBytes(pDevice->hInRingBuffer);
USB2_MSE_VDBG("usb2MseIosRead(): We have %d bytes in the buffer\n",
nBytes, 2, 3, 4, 5, 6);
/*
* If nBytes is 0, that means that there is nothing
* in the buffer, so wait for data
*/
if (0 == nBytes)
{
status = semTake(pDevice->hReadMutex, WAIT_FOREVER);
if (OK != status)
{
USB2_MSE_ERR("usb2MseIosRead(): "
"Cannot take hReadMutex ownership\n",
1, 2, 3, 4, 5, 6);
errnoSet(EIO);
usb2ReleaseDevice (pDevice->pClassDevice);
return ERROR;
}
/* Release the device mutex so that the URB callback can take it */
usb2ReleaseDevice (pDevice->pClassDevice);
/* Do the actual wait */
status = semTake (pDevice->hInSem, WAIT_FOREVER);
/* if any error occured during the wait */
if (OK != status || pDevice->pReader == NULL)
{
USB2_MSE_ERR("usb2MseIosRead(): "
"Cannot take hInIntSem ownership\n",
1, 2, 3, 4, 5, 6);
errnoSet(EIO);
semGive(pDevice->hReadMutex);
return ERROR;
}
semGive(pDevice->hReadMutex);
status = usb2TakeDevice (pDevice->pClassDevice);
if (OK != status)
{
USB2_MSE_ERR("usb2MseIosRead(): "
"Cannot take device ownership\n",
1, 2, 3, 4, 5, 6);
errnoSet(EIO);
return ERROR;
}
}
/* Copy to the application buffer the data we have */
nBytes = rngBufGet(pDevice->hInRingBuffer, pBuffer, (size_t)bfrSize);
usb2ReleaseDevice (pDevice->pClassDevice);
return (ssize_t)nBytes;
}
/*******************************************************************************
*
* usb2MseIosWrite - IO write call
*
* This routine writes to the device from the application buffer.
*
* RETURNS: ERROR or number of bytes written.
*
* ERRNO: EIO
*
* \NOMANUAL
*/
LOCAL ssize_t usb2MseIosWrite
(
USB2_FILE_DESC * pFd, /* fd struct returned by open */
UCHAR * pBuffer, /* application buffer */
size_t bfrSize /* size to write */
)
{
USB2_MSE_ERR("usb2MseIosWrite(): Not supported for writing to mouse\n",
1, 2, 3, 4, 5, 6);
errnoSet(EINVAL);
return ERROR;
}
/*******************************************************************************
*
* usb2MseIosIoctl - ioctl call
*
* This routine implements the ioctl call for the USB GEN2 mouse class driver.
* The following ioctl codes are supported:
*
* \ml
*
* \m 1. FIONREAD
* get num chars available to read.
*
* \m 2. FIOSELECT
* register the task for waking up when data is available.
*
* \m 3. FIOUNSELECT
* deregister the task for waking up when data is available.
*
* \m 4. USB2_IOCTL_HID_IDLE_TIME_GET
* get the current idle time as specified in the HID specification.
*
* \m 5. USB2_IOCTL_HID_IDLE_TIME_SET
* set the idle time as specified in the HID specification.
* \me
*
* RETURNS: OK, or ERROR if anything failed.
*
* ERRNO: EINVAL
*
* \NOMANUAL
*/
LOCAL int usb2MseIosIoctl
(
USB2_FILE_DESC * pFd, /* Filedescriptor to use */
int function, /* Function to use (see above) */
void * arg /* Argument to use */
)
{
USBHST_STATUS hstStatus = USBHST_SUCCESS;
STATUS retVal = ERROR;
USB2_MSE_DEVICE * pDevice = pFd->pDevice;
USB2_MSE_VDBG("usb2MseIosIoctl(): Function 0x%X, argument %p\n",
function, arg, 3, 4, 5, 6);
/* Parameter checkings */
switch (function)
{
case USB2_IOCTL_HID_IDLE_TIME_GET:
case USB2_IOCTL_HID_IDLE_TIME_SET:
case USB2_IOCTL_HID_PROTO_GET:
case USB2_IOCTL_HID_PROTO_SET:
case FIONREAD:
case FIOSELECT:
case FIOUNSELECT:
if (NULL == arg)
{
USB2_MSE_ERR("usb2MseIosIoctl(): invalid parameter\n",
1, 2, 3, 4, 5, 6);
errnoSet (EINVAL);
return ERROR;
}
}
retVal = usb2TakeDevice (pDevice->pClassDevice);
if (OK != retVal)
{
USB2_MSE_ERR("usb2MseIosIoctl(): "
"Cannot take device ownership\n",
1, 2, 3, 4, 5, 6);
return ERROR;
}
if ((function == USB2_IOCTL_HID_IDLE_TIME_GET) ||
(function == USB2_IOCTL_HID_IDLE_TIME_SET) ||
(function == USB2_IOCTL_HID_PROTO_GET) ||
(function == USB2_IOCTL_HID_PROTO_SET))
{
/*
* NOTE:
*
* These functions need to submit URBs on the control pipe,
* in the mean time the data pipe URB may complete and
* also need to take the device mutex, thus it is possible
* to have dead lock condition. To remove the possible
* dead lock, we do not take device mutex while waiting for
* control pipe to complete, but to wait on the control pipe
* mutex, so these pipes can operate concurrently.
*/
retVal = semTake (pDevice->pClassDevice->hSetupMutex, WAIT_FOREVER);
if (OK != retVal)
{
USB2_MSE_ERR("usb2MseIosIoctl(): "
"Cannot take setup mutex ownership\n",
1, 2, 3, 4, 5, 6);
/* Failed to take control pipe mutex, return with failre. */
usb2ReleaseDevice (pDevice->pClassDevice);
return ERROR;
}
/*
* Release the device so that other pipes can operate
* while control pipe is waiting for complete.
*/
usb2ReleaseDevice (pDevice->pClassDevice);
}
switch (function)
{
case FIONREAD:
*(size_t *)arg = rngNBytes (pDevice->hInRingBuffer);
retVal = OK;
/* Release device mutex */
usb2ReleaseDevice (pDevice->pClassDevice);
break;
case FIOSELECT:
selNodeAdd (pDevice->pSelWakeupList, (SEL_WAKEUP_NODE *) arg);
if (rngNBytes (pDevice->hInRingBuffer) > 0)
{
selWakeup ((SEL_WAKEUP_NODE *) arg);
}
retVal = OK;
/* Release device mutex */
usb2ReleaseDevice (pDevice->pClassDevice);
break;
case FIOUNSELECT:
selNodeDelete (pDevice->pSelWakeupList, (SEL_WAKEUP_NODE *)arg);
retVal = OK;
/* Release device mutex */
usb2ReleaseDevice (pDevice->pClassDevice);
break;
case USB2_IOCTL_HID_IDLE_TIME_GET:
USB2_MSE_VDBG("usb2MseIosIoctl():USB2_IOCTL_MSE_IDDLE_TIME_GET\n",
1, 2, 3, 4, 5, 6);
hstStatus = usb2HidIdleTimeGet(pDevice->pClassDevice,
(UINT8*) arg, pDevice->deviceTimeout);
retVal = ((USBHST_SUCCESS == hstStatus) ? OK : ERROR);
/* Release the control pipe mutex */
semGive(pDevice->pClassDevice->hSetupMutex);
break;
case USB2_IOCTL_HID_IDLE_TIME_SET:
USB2_MSE_VDBG("usb2MseIosIoctl():USB2_IOCTL_MSE_IDDLE_TIME_SET\n",
1, 2, 3, 4, 5, 6);
hstStatus = usb2HidIdleTimeSet(pDevice->pClassDevice,
(UINT16)(*(UINT16 *)arg),
pDevice->deviceTimeout);
retVal = ((USBHST_SUCCESS == hstStatus) ? OK : ERROR);
/* Release the control pipe mutex */
semGive(pDevice->pClassDevice->hSetupMutex);
break;
case USB2_IOCTL_HID_PROTO_GET:
hstStatus = usb2HidProtoGet(pDevice->pClassDevice,
(UINT8*) arg, pDevice->deviceTimeout);
retVal = ((USBHST_SUCCESS == hstStatus) ? OK : ERROR);
/* Release the control pipe mutex */
semGive(pDevice->pClassDevice->hSetupMutex);
USB2_MSE_VDBG("IDDLE_PROTO_GET=%d, resualt=0x%x \n",
(*(UINT8 *)arg), retVal, 3, 4, 5, 6);
break;
case USB2_IOCTL_HID_PROTO_SET:
hstStatus = usb2HidProtoSet(pDevice->pClassDevice,
(*(UCHAR *)arg), pDevice->deviceTimeout);
retVal = ((USBHST_SUCCESS == hstStatus) ? OK : ERROR);
/* Release the control pipe mutex */
semGive(pDevice->pClassDevice->hSetupMutex);
USB2_MSE_VDBG("IDDLE_PROTO_SET=%d, resualt=0x%x \n",
(*(UCHAR *)arg), retVal, 3, 4, 5, 6);
break;
default:
USB2_MSE_WARN("usb2MseIosIoctl(): Not supported ioctl - "
"(function : 0x%X, argument : %p)\n",
function, arg, 3, 4, 5, 6);
errnoSet(ENOTSUP);
retVal = ERROR;
/* Release device mutex */
usb2ReleaseDevice (pDevice->pClassDevice);
break;
}
return retVal;
}
/*******************************************************************************
*
* usb2MseDelete - delete device related structures
*
* This routine is to delete all the device related structures.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL void usb2MseDelete
(
USB2_MSE_DEVICE * pDevice
)
{
if (pDevice)
{
if (pDevice->hInSem)
semDelete(pDevice->hInSem);
if (pDevice->hInRingBuffer)
rngDelete(pDevice->hInRingBuffer);
if (pDevice->pInUrb)
OSS_FREE(pDevice->pInUrb);
if (pDevice->pReport)
OSS_FREE(pDevice->pReport);
if (pDevice->hReadMutex)
{
/* Mutex should be taken before delete it */
semTake(pDevice->hReadMutex, WAIT_FOREVER);
semDelete(pDevice->hReadMutex);
}
if (pDevice->pSelWakeupList)
{
if (pDevice->bSelListInitialized == TRUE)
{
selWakeupListTerm(pDevice->pSelWakeupList);
}
OSS_FREE (pDevice->pSelWakeupList);
}
pDevice->hInSem = NULL;
pDevice->hInRingBuffer = NULL;
pDevice->pReport = NULL;
pDevice->pInUrb = NULL;
pDevice->hReadMutex = NULL;
pDevice->pSelWakeupList = NULL;
if (pDevice->pClassDevice != NULL)
{
usb2ClassDeviceDelete(pDevice->pClassDevice);
/*
* The routine usb2ClassDeviceDelete will free the "pDevice->pClassDevice"
* So we'd better set this pointer to NULL. As we may call
* usb2ReleaseDevice(pDevice->pClassDevice) after the delete process.
* If we don't set this pointer to NULL, may exception happened.
*/
pDevice->pClassDevice = NULL;
}
OSS_FREE(pDevice);
}
}
/*******************************************************************************
*
* usb2MseDeleteCallback - delete the device if no transfer active
*
* This routine is to delete all the device related structures if there is
* no active transfer on any of the pipes.
*
* RETURNS: OK if device deleted, ERROR if transfer still active.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL STATUS usb2MseDeleteCallback
(
USB2_MSE_DEVICE * pDevice
)
{
if (NULL == pDevice)
{
USB2_MSE_ERR("usb2MseDeleteCallback(): Device Pointer is NULL\n",
1, 2, 3, 4, 5, 6);
return ERROR;
}
/* Check if a transfer is still active */
if (TRUE == pDevice->bTransferInCourse)
return ERROR;
if (OK != semTake(pDevice->pClassDevice->hSetupMutex, 0))
{
USB2_MSE_ERR("usb2MseDeleteCallback(): Control Transfer STILL active\n",
1, 2, 3, 4, 5, 6);
return ERROR;
}
if (OK != semTake(pDevice->hReadMutex,0))
{
USB2_MSE_ERR("usb2MseDeleteCallback(): Read mutex taken by others\n",
1, 2, 3, 4, 5, 6);
semGive(pDevice->hInSem);
return ERROR;
}
usb2MseDelete(pDevice);
return OK;
}
/*******************************************************************************
*
* usb2MseCreate - create device related structures
*
* This routine creates all the device related structures.
*
* RETURNS: pointer to USB2_MSE_DEVICE, or NULL if there is any failure.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL USB2_MSE_DEVICE * usb2MseCreate
(
USB2_CLASS_DEVICE * pUsb2ClassDevice,
UINT8 bInEndpointAddr,
UINT16 wMaxPacketSize
)
{
USB2_MSE_DEVICE * pDevice;
pDevice = (USB2_MSE_DEVICE *)OSS_CALLOC (sizeof(USB2_MSE_DEVICE));
if (pDevice == NULL)
{
USB2_MSE_ERR("usb2MseCreate(): "
"pDevice data allocation failed\n", 1, 2, 3, 4, 5, 6);
return NULL;
}
pDevice->pClassDevice = pUsb2ClassDevice;
pDevice->hInSem = semBCreate(SEM_Q_FIFO, SEM_EMPTY);
if (NULL == pDevice->hInSem)
{
USB2_MSE_ERR("usb2MseCreate(): hInIntSem semaphore creation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
pDevice->hReadMutex = semMCreate(USB2_MUTEX_CREATION_OPTS);
if (NULL == pDevice->hReadMutex)
{
USB2_MSE_ERR("usb2MseCreate(): pReadMutex Mutex Creation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
pDevice->pInUrb = (USBHST_URB *)OSS_CALLOC(sizeof(USBHST_URB));
if (pDevice->pInUrb == NULL)
{
USB2_MSE_ERR("usb2MseCreate(): pInUrb allocation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
pDevice->uInBufferNbElem = USB2_MSE_DEFAULT_IN_BUFFER_NUM_ELEM;
pDevice->hInRingBuffer = rngCreate(USB2_MSE_DEFAULT_IN_BUFFER_NUM_ELEM
* sizeof(USB2_MSE_REPORT));
if (pDevice->hInRingBuffer == NULL)
{
USB2_MSE_ERR("usb2MseCreate(): pInRingBuffer allocation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
if (wMaxPacketSize < sizeof(USB2_MSE_REPORT))
pDevice->uReportSize = sizeof(USB2_MSE_REPORT);
else
pDevice->uReportSize = wMaxPacketSize;
pDevice->pReport = (USB2_MSE_REPORT *) OSS_CALLOC(pDevice->uReportSize);
if (NULL == pDevice->pReport)
{
USB2_MSE_ERR("usb2MseCreate(): pReport allocation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
pDevice->pSelWakeupList = (SEL_WAKEUP_LIST *)
OSS_CALLOC(sizeof (SEL_WAKEUP_LIST));
if (NULL == pDevice->pSelWakeupList)
{
USB2_MSE_ERR("usb2MseCreate(): pSelWakeupList allocation failed\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return NULL;
}
selWakeupListInit (pDevice->pSelWakeupList);
pDevice->bSelListInitialized = TRUE;
pDevice->bInEndPointAddr = bInEndpointAddr;
pDevice->pReader = NULL;
pDevice->deviceTimeout = USB2_DEFAULT_TIMEOUT;
pDevice->bTransferInCourse = FALSE;
return pDevice;
}
/*******************************************************************************
*
* usb2MseDeviceAdd - device add method of USBD interface
*
* This routine is called by the USBD each time a new USB mass storage device
* is attached to the system. This routine is responsible for identifying the
* device, configuring it and creating the device structure that enables use
* of the device.
*
* RETURNS: USBHST_SUCCESS, or USBHST_FAILURE if there is any failure.
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL USBHST_STATUS usb2MseDeviceAdd
(
UINT32 hDevice, /* device handler returned by usbd */
UINT8 bInterfaceNumber, /* interface number found by the usbd */
UINT8 uSpeed, /* speed of the device */
void ** ppDriverData /* place to put the device data*/
)
{
USB2_MSE_DEVICE * pDevice = NULL;
STATUS status = ERROR;
USBHST_STATUS hstStatus = USBHST_FAILURE;
pUSBD_INTERFACE_INFO pInterface = NULL;
pUSBD_DEVICE_INFO pDeviceInfo = NULL;
pUSBHST_CONFIG_DESCRIPTOR pCurrentConfiguration = NULL;
USB2_CLASS_DEVICE * pUsb2ClassDevice = NULL;
UINT8 uInEndPointAddr = 0;
UINT8 configurationIndex = 0;
UINT8 uAlternateSetting = 0;
USBHST_INTERFACE_DESCRIPTOR * pInterfaceDesc;
USBHST_ENDPOINT_DESCRIPTOR * pEndPointDesc;
UINT16 wMaxPacketSize;
USB_TRANSFER_SETUP_INFO xferSetup;
USB2_MSE_INFO("Attaching mouse "
"(hDevice 0x%X, interface %d, speed %d)\n",
hDevice, bInterfaceNumber, uSpeed, 4, 5, 6);
/* Get the device information, for the descriptors */
usbdTranslateDeviceHandle(hDevice, &pDeviceInfo);
if (NULL == pDeviceInfo )
{
USB2_MSE_ERR("usb2MseDeviceAdd(): Mouse is apparently "
"not connected anymore, the USBD pDeviceInfo is NULL\n",
1, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
pCurrentConfiguration = (pUSBHST_CONFIG_DESCRIPTOR)
pDeviceInfo->pCurrentConfiguration;
if (NULL == pCurrentConfiguration)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): pCurrentConfiguration NULL\n",
1, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
configurationIndex = (UINT8)(pCurrentConfiguration->bConfigurationValue -1);
if (usbHstSetConfiguration (hDevice,configurationIndex ) != OK)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): Failed to set configuration - "
"device not added.\n", 1, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
pInterface = &(pDeviceInfo->pInterfacesInfo[bInterfaceNumber]);
uAlternateSetting = pInterface->uAlternateSetting;
USB2_MSE_VDBG("usb2MseDeviceAdd(): Setting Interface %d \n",
bInterfaceNumber, 2, 3, 4, 5, 6);
if ((hstStatus = usbHstSetInterface(hDevice,
bInterfaceNumber,
uAlternateSetting))
!= USBHST_SUCCESS)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): Failed to set interface - "
"device not added \n", 1, 2, 3, 4, 5, 6);
/*
* If a device only supports a default setting for the
* specified interface, then a STALL may be returned in
* the Status stage of the request. And in this case we
* should continue as this is a control pipe protocol STALL
* and will be cleared automatically when the device
* receives the next setup packet.
*/
if (hstStatus != USBHST_STALL_ERROR)
return USBHST_FAILURE;
}
USB2_MSE_VDBG("usb2MseDeviceAdd(): Searching for endpoints... \n",
1, 2, 3, 4, 5, 6);
pInterfaceDesc = usb2FindInterface(pDeviceInfo,
bInterfaceNumber,
uAlternateSetting);
if (NULL == pInterfaceDesc)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): No such interface"
" bInterfaceNumber %d, uAlternateSetting %d on device\n",
bInterfaceNumber, uAlternateSetting, 3, 4, 5, 6);
return USBHST_FAILURE;
}
/* Find the must-have interrupt in endpoint */
pEndPointDesc = usb2FindEndpoint((UCHAR* )pInterfaceDesc,
USB2_ATTR_INTERRUPT,
USB2_ENDPOINT_IN,
0,
0,
0);
if (NULL == pEndPointDesc)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): NO IN endpoint found\n",
1, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
uInEndPointAddr = pEndPointDesc->bEndpointAddress;
wMaxPacketSize = OS_UINT16_LE_TO_CPU(pEndPointDesc->wMaxPacketSize);
/* Set up the trasnfer requirment */
OS_MEMSET(&xferSetup, 0, sizeof(USB_TRANSFER_SETUP_INFO));
xferSetup.uMaxTransferSize = max(_CACHE_ALIGN_SIZE, wMaxPacketSize);
xferSetup.uMaxNumReqests = 1;
xferSetup.uFlags = 0;
hstStatus = usbHstPipePrepare(hDevice,
pEndPointDesc->bEndpointAddress,
&xferSetup);
if (hstStatus != USBHST_SUCCESS)
{
USB2_MSE_ERR("Interrupt IN at 0x%x set up failed\n",
pEndPointDesc->bEndpointAddress, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
status = usb2TakeDriver(pUsb2MseDriver);
if (OK != status)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): Driver mutex not taken\n",
1, 2, 3, 4, 5, 6);
return USBHST_FAILURE;
}
USB2_MSE_VDBG("usb2MseDeviceAdd(): Building & Filling the "
"Generic Device structure, driver %p, hDevice 0x%X, config 0x%X, "
"interface 0x%X, altSetting 0x%X... \n",
pUsb2MseDriver,
hDevice,
configurationIndex,
bInterfaceNumber,
uAlternateSetting, 6);
pUsb2ClassDevice = usb2ClassDeviceCreate (pUsb2MseDriver,
hDevice,
configurationIndex,
bInterfaceNumber,
uAlternateSetting);
if (NULL == pUsb2ClassDevice)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): usb2ClassDeviceCreate failed\n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDriver(pUsb2MseDriver);
return USBHST_FAILURE;
}
USB2_MSE_VDBG("usb2MseDeviceAdd(): Building & Filling the "
"Mouse structure, pUsb2ClassDevice %p, uInEndPointAddr %p"
"wMaxPacketSize %x\n", pUsb2ClassDevice,
uInEndPointAddr, wMaxPacketSize, 4, 5, 6);
pDevice = usb2MseCreate(pUsb2ClassDevice, uInEndPointAddr, wMaxPacketSize);
if (NULL == pDevice)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): usb2MseCreate failed\n",
1, 2, 3, 4, 5, 6);
usb2ClassDeviceDelete(pUsb2ClassDevice);
pUsb2ClassDevice = NULL;
usb2ReleaseDriver(pUsb2MseDriver);
return USBHST_FAILURE;
}
usb2ReleaseDriver(pUsb2MseDriver);
USB2_MSE_VDBG("usb2MseDeviceAdd(): Setting USB2_HID_PROTO_BOOT\n",
1, 2, 3, 4, 5, 6);
hstStatus = usb2HidProtoSet(pDevice->pClassDevice,
USB2_HID_PROTO_BOOT,
pDevice->deviceTimeout );
if (USBHST_SUCCESS != hstStatus)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): Could not Set Boot Protocol\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return USBHST_FAILURE;
}
/*
* Set the idle time to infinite, so that the mouse reports a change
* only when a change does exist
*/
hstStatus = usb2HidIdleTimeSet(pDevice->pClassDevice,
USB2_HID_IDLE_INFINITE,
pDevice->deviceTimeout);
if (USBHST_SUCCESS != hstStatus)
{
USB2_MSE_WARN("usb2MseDeviceAdd(): Could not set idle time, continue\n",
1, 2, 3, 4, 5, 6);
/* Go and ignore this as it is acceptable for this failure */
}
USB2_MSE_VDBG("usb2MseDeviceAdd(): Adding device %s to IO driver %d\n",
pDevice->pClassDevice->pDeviceName,
usb2MseDrvNum,
3, 4, 5, 6);
status = iosDevAdd(&pDevice->deviceHeader,
pDevice->pClassDevice->pDeviceName,
usb2MseDrvNum);
if (OK != status)
{
USB2_MSE_ERR("usb2MseDeviceAdd(): iosDevAdd failed.\n",
1, 2, 3, 4, 5, 6);
usb2MseDelete(pDevice);
return USBHST_FAILURE;
}
USB2_MSE_INFO("Mouse device %s is up and running...\n",
pDevice->deviceHeader.name, 2, 3, 4, 5, 6);
*ppDriverData = pDevice;
usbMsgPost(USBMSG_GEN2_MSE_DEVREADY,
pDevice,
pDevice->pClassDevice->pDeviceName);
return USBHST_SUCCESS;
}
/*******************************************************************************
*
* usb2MseDeviceRemove - device remove method of USBD interface
*
* This routine is called by the USBD each time a device is removed from the
* system. This routine is responsible for ensuring all outstanding IO requests
* are completed or aborted and tearing down the I/O structure.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL void usb2MseDeviceRemove
(
UINT32 hDevice, /* Device handler provided by the USBD */
void * pDriverData /* Driver structure returned by add routine */
)
{
STATUS status = ERROR;
USB2_MSE_DEVICE * pDevice = pDriverData;
USB2_MSE_DBG("Removing mouse (hDevice 0x%X, pDevice %p)\n",
hDevice,
pDevice, 3, 4, 5, 6);
usbMsgPost(USBMSG_GEN2_MSE_DEVREMOVED,
pDevice,
pDevice->pClassDevice->pDeviceName);
status = usb2TakeDriver(pUsb2MseDriver);
if (OK != status)
{
USB2_MSE_ERR("usb2MseDeviceRemove(): Cannot take driver ownership\n",
1, 2, 3, 4, 5, 6);
return;
}
status = usb2TakeDevice(pDevice->pClassDevice);
if (OK != status)
{
USB2_MSE_ERR("usb2MseDeviceRemove(): "
"Cannot take device ownership\n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDriver(pUsb2MseDriver);
return;
}
if (pDevice->bSelListInitialized == TRUE)
{
selWakeupListTerm(pDevice->pSelWakeupList);
pDevice->bSelListInitialized = FALSE;
}
USB2_MSE_INFO("Delete device %s%d\n",
pDevice->pClassDevice->pDriver->pDefaultDriverName,
pDevice->pClassDevice->pNode->uDeviceIndex, 3, 4, 5, 6);
if (iosDevDelete(&pDevice->deviceHeader) != OK)
{
USB2_MSE_WARN("IOS Dev Delete Fail\n",
1, 2, 3, 4, 5, 6);
}
usb2DeviceDeleteMsgPost(
pDevice->pClassDevice,
usb2MseDeleteCallback,
pDevice
);
/*
* Release the device mutex since the usb2MseDeleteCallback
* will need to take the device mutex in order to delete the
* mutex with respect to the rule "mutex should be taken before
* delete it"
*/
usb2ReleaseDevice(pDevice->pClassDevice);
usb2ReleaseDriver(pUsb2MseDriver);
}
/*******************************************************************************
*
* usb2MseSuspendResume - suspend or resume method of the driver
*
* This routine is called by the USBD to suspend or resume the USB device.
* Right now there is nothing to do, so this routine simply returns.
*
* RETURNS: N/A
*
* ERRNO: N/A
*
* \NOMANUAL
*/
LOCAL void usb2MseSuspendResume
(
UINT32 hDevice,
void * pDriver
)
{
USB2_MSE_WARN("usb2MseSuspendResume(): UNSUPPORTED...\n",
1, 2, 3, 4, 5, 6);
}
/*******************************************************************************
*
* usb2MseInit - register the USB Mouse class driver with the USBD
*
* This routine is called once to register the mouse class driver with the
* USBD. Multiple instances of the mouse are supported, the driver
* shall be initialized only once.
*
* RETURNS: OK, or ERROR if the the driver could not be initialized.
*
* ERRNO: N/A
*/
STATUS usb2MseInit
(
char * pName /* Default base name that will be used, or NULL if no names */
)
{
USBHST_STATUS hstStatus;
USB2_MSE_VDBG("usb2MseInit(): Initializing the mouse driver...\n",
1, 2, 3, 4, 5, 6);
/* If already initialized, ignore and return. */
if (NULL != pUsb2MseDriver)
{
USB2_MSE_WARN("usb2MseInit(): Driver already initialized, return...\n",
1, 2, 3, 4, 5, 6);
return OK;
}
/* If no valid parameter is given, take the driver default name. */
if (NULL == pName)
pUsb2MseDriver = usb2ClassDriverCreate (USB2_MSE_DEVICE_BASE_NAME);
else
pUsb2MseDriver = usb2ClassDriverCreate (pName);
/* If the driver cannot be created, return with ERROR. */
if (NULL == pUsb2MseDriver)
{
USB2_MSE_ERR("usb2MseInit(): Driver cannot be created\n",
1, 2, 3, 4, 5, 6);
return ERROR;
}
if (OK != usb2TakeDriver(pUsb2MseDriver))
{
USB2_MSE_ERR("usb2MseInit(): Driver cannot be taken\n",
1, 2, 3, 4, 5, 6);
usb2ClassDriverDelete(pUsb2MseDriver);
pUsb2MseDriver = NULL;
return ERROR;
}
USB2_MSE_VDBG("usb2MseInit(): Creating the ioLib driver...\n",
1, 2, 3, 4, 5, 6);
usb2MseDrvNum = iosDrvInstall ((DRV_CREATE_PTR) NULL, /* No create routine */
(DRV_REMOVE_PTR) NULL, /* No delete routine */
(DRV_OPEN_PTR) usb2MseIosOpen, /* Open routine */
(DRV_CLOSE_PTR) usb2MseIosClose,/* Close routine */
(DRV_READ_PTR) usb2MseIosRead, /* Read routine */
(DRV_WRITE_PTR) usb2MseIosWrite, /* no write routine */
(DRV_IOCTL_PTR) usb2MseIosIoctl);/* ioctl routine */
if (ERROR == usb2MseDrvNum )
{
USB2_MSE_VDBG("usb2MseInit(): IO Driver Not installed\n",
1, 2, 3, 4, 5, 6);
usb2ClassDriverDelete(pUsb2MseDriver);
pUsb2MseDriver = NULL;
return USBHST_FAILURE;
}
pUsb2MseDriver->hstDriver.bFlagVendorSpecific = FALSE;
pUsb2MseDriver->hstDriver.uVendorIDorClass = USB2_HID_CLASS;
pUsb2MseDriver->hstDriver.uProductIDorSubClass = USBD_NOTIFY_ALL;
pUsb2MseDriver->hstDriver.uBCDUSBorProtocol = USB2_MSE_PROTOCOL;
pUsb2MseDriver->hstDriver.addDevice = usb2MseDeviceAdd;
pUsb2MseDriver->hstDriver.removeDevice = usb2MseDeviceRemove;
pUsb2MseDriver->hstDriver.suspendDevice = usb2MseSuspendResume;
pUsb2MseDriver->hstDriver.resumeDevice = usb2MseSuspendResume;
USB2_MSE_VDBG("usb2MseInit(): Registering the USBD Part:\n",
1, 2, 3, 4, 5, 6);
USB2_MSE_VDBG("usb2MseInit(): Vendorspecific : 0x%X :\n",
pUsb2MseDriver->hstDriver.bFlagVendorSpecific, 2, 3, 4, 5, 6);
USB2_MSE_VDBG("usb2MseInit(): uVendorIDorClass : 0x%X :\n",
pUsb2MseDriver->hstDriver.uVendorIDorClass, 2, 3, 4, 5, 6);
USB2_MSE_VDBG("usb2MseInit(): uProductIDorSubClass : 0x%X :\n",
pUsb2MseDriver->hstDriver.uProductIDorSubClass, 2, 3, 4, 5, 6);
USB2_MSE_VDBG("usb2MseInit(): uBCDUSBorProtocol : 0x%X :\n",
pUsb2MseDriver->hstDriver.uBCDUSBorProtocol, 2, 3, 4, 5, 6);
/* Register the client with USBD */
USB2_MSE_VDBG("usb2MseInit(): registering the client with USBD...\n",
1, 2, 3, 4, 5, 6);
hstStatus = usbHstDriverRegister (&pUsb2MseDriver->hstDriver,
NULL
/* VxWorks 6.6 and above has a 3rd parameter specfying the name of the driver */
#if (_WRS_VXWORKS_MAJOR > 6) || \
((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
,
"usbGen2Mouse"
#endif
);
if (hstStatus != USBHST_SUCCESS)
{
USB2_MSE_ERR("usb2MseInit(): cannot register with USBD...\n",
1, 2, 3, 4, 5, 6);
iosDrvRemove(usb2MseDrvNum, TRUE);
usb2MseDrvNum = 0;
usb2ClassDriverDelete(pUsb2MseDriver);
pUsb2MseDriver = NULL;
return ERROR;
}
USB2_MSE_DBG("usb2MseInit(): Class driver registration succeeded.\n",
1, 2, 3, 4, 5, 6);
usb2ReleaseDriver(pUsb2MseDriver);
return OK;
}
/*******************************************************************************
*
* usb2MseDeinit - unregister the USB mouse class driver from the USBD
*
* This routine is to de-initialize the mouse driver from the USBD, and to free
* all related resources.
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
void usb2MseDeinit
(
void
)
{
USBHST_STATUS hstStatus;
BOOL driverEmpty;
if (OK != usb2TakeDriver(pUsb2MseDriver))
{
USB2_MSE_ERR("usb2MseDeinit(): Driver mutex not taken\n",
1, 2, 3, 4, 5, 6);
return;
}
hstStatus = usbHstDriverDeregister(&(pUsb2MseDriver->hstDriver));
if (hstStatus != USBHST_SUCCESS)
{
USB2_MSE_ERR("usb2MseDeinit(): "
"usbHstDriverDeregister failed %d\n",
hstStatus, 2, 3, 4, 5, 6);
usb2ReleaseDriver(pUsb2MseDriver);
return;
}
driverEmpty = usb2DriverIsEmpty (pUsb2MseDriver);
while (FALSE == driverEmpty)
{
usb2ReleaseDriver(pUsb2MseDriver);
taskDelay(sysClkRateGet());
if (OK != usb2TakeDriver(pUsb2MseDriver))
{
USB2_MSE_ERR("usb2MseDeinit(): Driver mutex not taken\n",
1, 2, 3, 4, 5, 6);
return;
}
driverEmpty = usb2DriverIsEmpty (pUsb2MseDriver);
}
if (usb2MseDrvNum > 0)
{
iosDrvRemove(usb2MseDrvNum, FALSE);
usb2MseDrvNum = 0;
}
usb2ClassDriverDelete(pUsb2MseDriver);
pUsb2MseDriver = NULL;
USB2_MSE_DBG("usb2MseDeinit(): Class driver deregistration succeeded.\n",
1, 2, 3, 4, 5, 6);
return;
}