📄 usbkeyboardlib.c
字号:
return status;
}
/***************************************************************************
*
* initKbdIrp - Initialize IRP to listen for input on interrupt pipe
*
* This function intializes the IRP to listen on the interrupt pipe
*
* RETURNS: TRUE if able to submit IRP successfully, else FALSE
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL BOOL initKbdIrp
(
pUSB_KBD_SIO_CHAN pSioChan
)
{
pUSB_IRP pIrp = &pSioChan->irp;
/* Initialize IRP */
memset (pIrp, 0, sizeof (*pIrp));
pIrp->userPtr = pSioChan;
pIrp->irpLen = sizeof (*pIrp);
pIrp->userCallback = usbKeyboardIrpCallback;
pIrp->timeout = USB_TIMEOUT_NONE;
pIrp->transferLen = sizeof (HID_KBD_BOOT_REPORT);
pIrp->bfrCount = 1;
pIrp->bfrList [0].pid = USB_PID_IN;
pIrp->bfrList [0].pBfr = (pUINT8) pSioChan->pBootReport;
pIrp->bfrList [0].bfrLen = sizeof (HID_KBD_BOOT_REPORT);
/* Submit IRP */
if (usbdTransfer (usbdHandle, pSioChan->pipeHandle, pIrp) != OK)
return FALSE;
pSioChan->irpInUse = TRUE;
return TRUE;
}
/***************************************************************************
*
* usbKeyboardIrpCallback - Invoked upon IRP completion/cancellation
*
* Examines the cause of the IRP completion. If completion was successful,
* interprets the USB keyboard's boot report and re-submits the IRP.
*
* RETURNS: N/A
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL VOID usbKeyboardIrpCallback
(
pVOID p /* completed IRP */
)
{
pUSB_IRP pIrp = (pUSB_IRP) p;
pUSB_KBD_SIO_CHAN pSioChan = pIrp->userPtr;
OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
/* Was the IRP successful? */
if (pIrp->result == OK)
{
/* Interpret the keyboard report */
interpKbdReport (pSioChan);
}
/* Re-submit the IRP unless it was canceled - which would happen only
* during pipe shutdown (e.g., the disappearance of the device).
*/
pSioChan->irpInUse = FALSE;
if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
{
initKbdIrp (pSioChan);
}
else
{
if (!pSioChan->connected)
{
/* Release structure. */
if (pSioChan->pBootReport != NULL)
OSS_FREE (pSioChan->pBootReport);
OSS_FREE (pSioChan);
}
}
OSS_MUTEX_RELEASE (kbdMutex);
}
/***************************************************************************
*
* typematicThread - Updates typematic state for each active channel
*
* Updates typematic state for each active channel
*
* RETURNS: N/A
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL VOID typematicThread
(
pVOID param /* param not used by this thread */
)
{
pUSB_KBD_SIO_CHAN pSioChan;
while (!killTypematic)
{
OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
/* Walk the list of open channels and update the typematic
* state for each.
*/
pSioChan = usbListFirst (&sioList);
while (pSioChan != NULL)
{
updateTypematic (pSioChan);
pSioChan = usbListNext (&pSioChan->sioLink);
}
OSS_MUTEX_RELEASE (kbdMutex);
OSS_THREAD_SLEEP (TYPEMATIC_PERIOD);
}
typematicExit = TRUE;
}
/***************************************************************************
*
* configureSioChan - configure USB keyboard for operation
*
* Selects the configuration/interface specified in the <pSioChan>
* structure. These values come from the USBD dynamic attach callback,
* which in turn retrieved them from the configuration/interface
* descriptors which reported the device to be a keyboard.
*
* RETURNS: TRUE if successful, else FALSE if failed to configure channel
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL BOOL configureSioChan
(
pUSB_KBD_SIO_CHAN pSioChan
)
{
pUSB_CONFIG_DESCR pCfgDescr;
pUSB_INTERFACE_DESCR pIfDescr;
pUSB_ENDPOINT_DESCR pEpDescr;
UINT8 * pBfr;
UINT8 * pScratchBfr;
UINT16 actLen;
UINT16 ifNo;
UINT16 maxPacketSize;
if ((pBfr = OSS_MALLOC (USB_MAX_DESCR_LEN)) == NULL)
return FALSE;
/* Read the configuration descriptor to get the configuration selection
* value and to determine the device's power requirements.
*/
if (usbdDescriptorGet (usbdHandle,
pSioChan->nodeId,
USB_RT_STANDARD | USB_RT_DEVICE,
USB_DESCR_CONFIGURATION,
0,
0,
USB_MAX_DESCR_LEN,
pBfr,
&actLen)
!= OK)
{
OSS_FREE (pBfr);
return FALSE;
}
if ((pCfgDescr = usbDescrParse (pBfr,
actLen,
USB_DESCR_CONFIGURATION))
== NULL)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Look for the interface indicated in the pSioChan structure. */
ifNo = 0;
/*
* usbDescrParseSkip() modifies the value of the pointer it receives
* so we pass it a copy of our buffer pointer
*/
pScratchBfr = pBfr;
while ((pIfDescr = usbDescrParseSkip (&pScratchBfr,
&actLen,
USB_DESCR_INTERFACE))
!= NULL)
{
if (ifNo == pSioChan->interface)
break;
ifNo++;
}
if (pIfDescr == NULL)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Retrieve the endpoint descriptor following the identified interface
* descriptor.
*/
if ((pEpDescr = usbDescrParseSkip (&pScratchBfr,
&actLen,
USB_DESCR_ENDPOINT))
== NULL)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Select the configuration. */
if (usbdConfigurationSet (usbdHandle,
pSioChan->nodeId,
pCfgDescr->configurationValue,
pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT)
!= OK)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Select interface
*
* NOTE: Some devices may reject this command, and this does not represent
* a fatal error. Therefore, we ignore the return status.
*/
usbdInterfaceSet (usbdHandle,
pSioChan->nodeId,
pSioChan->interface,
pIfDescr->alternateSetting);
/* Select the keyboard boot protocol. */
if (usbHidProtocolSet (usbdHandle,
pSioChan->nodeId,
pSioChan->interface,
USB_HID_PROTOCOL_BOOT)
!= OK)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Set the keyboard idle time to infinite. */
if (usbHidIdleSet (usbdHandle,
pSioChan->nodeId,
pSioChan->interface,
0 /* no report ID */,
0 /* infinite */)
!= OK)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Turn off LEDs. */
setLedReport (pSioChan, 0);
/* Create a pipe to monitor input reports from the keyboard. */
maxPacketSize = *((pUINT8) &pEpDescr->maxPacketSize) |
(*(((pUINT8) &pEpDescr->maxPacketSize) + 1) << 8);
if (usbdPipeCreate (usbdHandle,
pSioChan->nodeId,
pEpDescr->endpointAddress,
pCfgDescr->configurationValue,
pSioChan->interface,
USB_XFRTYPE_INTERRUPT,
USB_DIR_IN,
maxPacketSize,
sizeof (HID_KBD_BOOT_REPORT),
pEpDescr->interval,
&pSioChan->pipeHandle)
!= OK)
{
OSS_FREE (pBfr);
return FALSE;
}
/* Initiate IRP to listen for input on interrupt pipe */
if (!initKbdIrp (pSioChan))
{
OSS_FREE (pBfr);
return FALSE;
}
OSS_FREE (pBfr);
return TRUE;
}
/***************************************************************************
*
* destroyAttachRequest - disposes of an ATTACH_REQUEST structure
*
* This function disposes of an ATTACH_REQUEST structure.
*
* RETURNS: N/A
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL VOID destroyAttachRequest
(
pATTACH_REQUEST pRequest
)
{
/* Unlink request */
usbListUnlinkProt (&pRequest->reqLink,kbdMutex);
/* Dispose of structure */
OSS_FREE (pRequest);
}
/***************************************************************************
*
* destroySioChan - disposes of a USB_KBD_SIO_CHAN structure
*
* Unlinks the indicated USB_KBD_SIO_CHAN structure and de-allocates
* resources associated with the channel.
*
* RETURNS: N/A
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL VOID destroySioChan
(
pUSB_KBD_SIO_CHAN pSioChan
)
{
/* Unlink the structure. */
usbListUnlinkProt (&pSioChan->sioLink,kbdMutex);
/* Release pipe if one has been allocated. Wait for the IRP to be
* cancelled if necessary.
*/
if (pSioChan->pipeHandle != NULL)
usbdPipeDestroy (usbdHandle, pSioChan->pipeHandle);
/* Release structure. */
if (!pSioChan->irpInUse)
{
if (pSioChan->pBootReport != NULL)
OSS_FREE (pSioChan->pBootReport);
OSS_FREE (pSioChan);
}
}
/***************************************************************************
*
* createSioChan - creates a new USB_KBD_SIO_CHAN structure
*
* Creates a new USB_KBD_SIO_CHAN structure for the indicated <nodeId>.
* If successful, the new structure is linked into the sioList upon
* return.
*
* <configuration> and <interface> identify the configuration/interface
* that first reported itself as a keyboard for this device.
*
* RETURNS: pointer to newly created structure, or NULL if failure
*
* ERRNO: none
*
*\NOMANUAL
*/
LOCAL pUSB_KBD_SIO_CHAN createSioChan
(
USBD_NODE_ID nodeId,
UINT16 configuration,
UINT16 interface
)
{
pUSB_KBD_SIO_CHAN pSioChan;
UINT16 i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -