📄 usbkeyboardlib.c
字号:
( SIO_CHAN *pChan, /* channel */ int callbackType, /* type of callback */ STATUS (*callback) (), /* callback */ void *callbackArg /* parameter to callback */ ) { pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan; switch (callbackType) { case SIO_CALLBACK_GET_TX_CHAR: pSioChan->getTxCharCallback = callback; pSioChan->getTxCharArg = callbackArg; return OK; case SIO_CALLBACK_PUT_RCV_CHAR: pSioChan->putRxCharCallback = callback; pSioChan->putRxCharArg = callbackArg; return OK; default: return ENOSYS; } }/***************************************************************************** usbKeyboardPollOutput - output a character in polled mode** The USB keyboard SIO driver does not support output to the keyboard.** RETURNS: EIO*/LOCAL int usbKeyboardPollOutput ( SIO_CHAN *pChan, char outChar ) { return EIO; }/***************************************************************************** usbKeyboardPollInput - poll the device for input** RETURNS: OK if a character arrived, EIO on device error, EAGAIN* if the input buffer if empty, ENOSYS if the device is interrupt-only.*/LOCAL int usbKeyboardPollInput ( SIO_CHAN *pChan, char *thisChar ) { pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan; int status = OK; /* validate parameters */ if (thisChar == NULL) return EIO; OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK); /* Check if the input queue is empty. */ if (pSioChan->inQueueCount == 0) status = EAGAIN; else { /* Return a character from the input queue. */ *thisChar = nextInChar (pSioChan); } OSS_MUTEX_RELEASE (kbdMutex); return status; }/***************************************************************************** initKbdIrp - Initialize IRP to listen for input on interrupt pipe** RETURNS: TRUE if able to submit IRP successfully, else FALSE*/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*/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); OSS_MUTEX_RELEASE (kbdMutex); }/***************************************************************************** typematicThread - Updates typematic state for each active channel** RETURNS: N/A*/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*/LOCAL BOOL configureSioChan ( pUSB_KBD_SIO_CHAN pSioChan ) { pUSB_CONFIG_DESCR pCfgDescr; pUSB_INTERFACE_DESCR pIfDescr; pUSB_ENDPOINT_DESCR pEpDescr; UINT8 bfr [USB_MAX_DESCR_LEN]; pUINT8 pBfr; UINT16 actLen; UINT16 ifNo; UINT16 maxPacketSize; /* 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, sizeof (bfr), bfr, &actLen) != OK) return FALSE; if ((pCfgDescr = usbDescrParse (bfr, actLen, USB_DESCR_CONFIGURATION)) == NULL) return FALSE; /* Look for the interface indicated in the pSioChan structure. */ ifNo = 0; pBfr = bfr; while ((pIfDescr = usbDescrParseSkip (&pBfr, &actLen, USB_DESCR_INTERFACE)) != NULL) { if (ifNo == pSioChan->interface) break; ifNo++; } if (pIfDescr == NULL) return FALSE; /* Retrieve the endpoint descriptor following the identified interface * descriptor. */ if ((pEpDescr = usbDescrParseSkip (&pBfr, &actLen, USB_DESCR_ENDPOINT)) == NULL) return FALSE; /* Select the configuration. */ if (usbdConfigurationSet (usbdHandle, pSioChan->nodeId, pCfgDescr->configurationValue, pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT) != OK) 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) return FALSE; /* Set the keyboard idle time to infinite. */ if (usbHidIdleSet (usbdHandle, pSioChan->nodeId, pSioChan->interface, 0 /* no report ID */, 0 /* infinite */) != OK) 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) return FALSE; /* Initiate IRP to listen for input on interrupt pipe */ if (!initKbdIrp (pSioChan)) return FALSE; return TRUE; }/***************************************************************************** destroyAttachRequest - disposes of an ATTACH_REQUEST structure** RETURNS: N/A*/LOCAL VOID destroyAttachRequest ( pATTACH_REQUEST pRequest ) { /* Unlink request */ usbListUnlink (&pRequest->reqLink); /* 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*/LOCAL VOID destroySioChan ( pUSB_KBD_SIO_CHAN pSioChan ) { /* Unlink the structure. */ usbListUnlink (&pSioChan->sioLink); /* Release pipe if one has been allocated. Wait for the IRP to be * cancelled if necessary. */ if (pSioChan->pipeHandle != NULL) usbdPipeDestroy (usbdHandle, pSioChan->pipeHandle); while (pSioChan->irpInUse) OSS_THREAD_SLEEP (1); /* Release structure. */ 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*/LOCAL pUSB_KBD_SIO_CHAN createSioChan ( USBD_NODE_ID nodeId, UINT16 configuration, UINT16 interface ) { pUSB_KBD_SIO_CHAN pSioChan; UINT16 i; /* Try to allocate space for a new keyboard struct */ if ((pSioChan = OSS_CALLOC (sizeof (*pSioChan))) == NULL) return NULL; if ((pSioChan->pBootReport = OSS_MALLOC_ALIGN ( (sizeof (*pSioChan->pBootReport) + CACHE_LINE_SIZE - 1) / CACHE_LINE_SIZE, CACHE_LINE_SIZE, TRUE)) == NULL) { OSS_FREE (pSioChan); return NULL; } pSioChan->sioChan.pDrvFuncs = &usbKeyboardSioDrvFuncs; pSioChan->nodeId = nodeId; pSioChan->connected = TRUE; pSioChan->mode = SIO_MODE_POLL; pSioChan->configuration = configuration; pSioChan->interface = interface; for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) pSioChan->activeScanCodes [i] = NOTKEY; /* Try to configure the keyboard. */ if (!configureSioChan (pSioChan)) { destroySioChan (pSioChan); return NULL; } /* Link the newly created structure. */ usbListLink (&sioList, pSioChan, &pSioChan->sioLink, LINK_TAIL); return pSioChan; }/***************************************************************************** findSioChan - Searches for a USB_KBD_SIO_CHAN for indicated node ID** RETURNS: pointer to matching USB_KBD_SIO_CHAN or NULL if not found*/LOCAL pUSB_KBD_SIO_CHAN findSioChan ( USBD_NODE_ID nodeId ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -