//***************************************************************************** // // usbhhid.c - This file contains the host HID driver. // // Copyright (c) 2008-2010 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of AM1808 StarterWare USB Library, resused from revision 6288 of the // stellaris USB Library // //***************************************************************************** #include "hw_types.h" #include "usb.h" #include "usblib.h" #include "usbhid.h" #include "usbhost.h" #include "usbhhid.h" extern tUSBHCD g_sUSBHCD[]; static void * HIDDriverOpen(tUSBHostDevice *pDevice, unsigned int ulDeviceInst); static void HIDDriverClose(void *pvInstance); //***************************************************************************** // //! \addtogroup usblib_host_class //! @{ // //***************************************************************************** //***************************************************************************** // // The instance data storage for attached hid devices. // //***************************************************************************** tHIDInstance g_HIDDevice[] = { { 0, 0, 0, USBH_HID_DEV_NONE, 0, 0 }, { 0, 0, 0, USBH_HID_DEV_NONE, 0, 1 } }; //***************************************************************************** // //! This constant global structure defines the HID Class Driver that is //! provided with the USB library. // //***************************************************************************** const tUSBHostClassDriver g_USBHIDClassDriver = { USB_CLASS_HID, HIDDriverOpen, HIDDriverClose, 0 }; //***************************************************************************** // //! This function is used to open an instance of a HID device. //! //! \param eDeviceType is the type of device that should be loaded for this //! instance of the HID device. //! \param pfnCallback is the function that will be called whenever changes //! are detected for this device. //! \param ulCBData is the data that will be returned in when the pfnCallback //! function is called. //! //! This function creates an instance of an specific type of HID device. The //! \e eDeviceType parameter is one subclass/protocol values of the types //! specified in enumerated types tHIDSubClassProtocol. Only devices that //! enumerate with this type will be called back via the \e pfnCallback //! function. The \e pfnCallback parameter is the callback function for any //! events that occur for this device type. The \e pfnCallback function must //! point to a valid function of type \e tUSBCallback for this call to complete //! successfully. To release this device instance the caller of USBHHIDOpen() //! should call USBHHIDClose() and pass in the value returned from the //! USBHHIDOpen() call. //! //! \return This function returns and instance value that should be used with //! any other APIs that require an instance value. If a value of 0 is returned //! then the device instance could not be created. // //***************************************************************************** unsigned int USBHHIDOpen(unsigned int ulIndex,tHIDSubClassProtocol eDeviceType, tUSBCallback pfnCallback, unsigned int ulCBData) { // // Only one callback is supported. // if(g_HIDDevice[ulIndex].pfnCallback) { return (0); } // // Save the instance data for this device. // g_HIDDevice[ulIndex].ulIndex = ulIndex; g_HIDDevice[ulIndex].pfnCallback = pfnCallback; g_HIDDevice[ulIndex].eDeviceType = eDeviceType; g_HIDDevice[ulIndex].ulCBData = ulCBData; // // Return the device instance pointer. // return((unsigned int)&g_HIDDevice[ulIndex]); } //***************************************************************************** // //! This function is used to release an instance of a HID device. //! //! \param ulHIDInstance is the instance value for a HID device to release. //! //! This function releases an instance of a HID device that was created by a //! call to USBHHIDOpen(). This call is required to allow other HID devices //! to be enumerated after another HID device has been disconnected. The //! \e ulHIDInstance parameter should hold the value that was returned from the //! previous call to USBHHIDOpen(). //! //! \return None. // //***************************************************************************** void USBHHIDClose(unsigned int ulHIDInstance) { tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulHIDInstance; // // Disable any more notification from the HID layer. // pHIDInstance->pfnCallback = 0; pHIDInstance->eDeviceType = USBH_HID_DEV_NONE; } //***************************************************************************** // // This function handles callbacks for the interrupt IN endpoint. // //***************************************************************************** static void HIDIntINCallback(unsigned int ulIndex, unsigned int ulPipe, unsigned int ulEvent) { switch (ulEvent) { // // Handles a request to schedule a new request on the interrupt IN // pipe. // case USB_EVENT_SCHEDULER: { USBHCDPipeSchedule(ulIndex, ulPipe, 0, 1); break; } // // Called when new data is available on the interrupt IN pipe. // case USB_EVENT_RX_AVAILABLE: { // // Send the report data to the USB host HID device class driver. // g_HIDDevice[ulIndex].pfnCallback((void *)g_HIDDevice[ulIndex].ulCBData, USB_EVENT_RX_AVAILABLE, ulPipe, 0); break; } } } //***************************************************************************** // //! This function is used to open an instance of the HID driver. //! //! \param pDevice is a pointer to the device information structure. //! //! This function will attempt to open an instance of the HID driver based on //! the information contained in the pDevice structure. This call can fail if //! there are not sufficient resources to open the device. The function will //! return a value that should be passed back into USBHIDClose() when the //! driver is no longer needed. //! //! \return The function will return a pointer to a HID driver instance. // //***************************************************************************** static void * HIDDriverOpen(tUSBHostDevice *pDevice, unsigned int ulInstance) { int iIdx; tEndpointDescriptor *pEndpointDescriptor; tInterfaceDescriptor *pInterface; tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulInstance; unsigned int ulIndex = pHIDInstance->ulIndex; // // Don't allow the device to be opened without closing first. // if(pHIDInstance->pDevice) { return (0); } // // Get the interface descriptor. // pInterface = USBDescGetInterface(pDevice->pConfigDescriptor, 0, 0); if((pInterface->bInterfaceSubClass != USB_HID_SCLASS_BOOT) || (pInterface->bInterfaceProtocol != pHIDInstance->eDeviceType)) { return(0); } // // Save the device pointer. // pHIDInstance->pDevice = pDevice; for(iIdx = 0; iIdx < 3; iIdx++) { // // Get the first endpoint descriptor. // pEndpointDescriptor = USBDescGetInterfaceEndpoint(pInterface, iIdx, 256); // // If no more endpoints then break out. // if(pEndpointDescriptor == 0) { break; } // // Interrupt // if((pEndpointDescriptor->bmAttributes & USB_EP_ATTR_TYPE_M) == USB_EP_ATTR_INT) { // // Interrupt IN. // if(pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_IN) { pHIDInstance->ulIntInPipe = USBHCDPipeAlloc(ulIndex, USBHCD_PIPE_INTR_IN, pDevice->ulAddress, HIDIntINCallback); USBHCDPipeConfig(ulIndex, pHIDInstance->ulIntInPipe, pEndpointDescriptor->wMaxPacketSize, pEndpointDescriptor->bInterval, (pEndpointDescriptor->bEndpointAddress & USB_EP_DESC_NUM_M)); } } } // // If there is a callback function call it to inform the application that // the device has been enumerated. // if(pHIDInstance->pfnCallback != 0) { pHIDInstance->pfnCallback((void *)pHIDInstance->ulCBData, USB_EVENT_CONNECTED, (unsigned int)pHIDInstance, 0); } // // Save the device pointer. // pHIDInstance->pDevice = pDevice; return (pHIDInstance); } //***************************************************************************** // //! This function is used to release an instance of the HID driver. //! //! \param pvInstance is an instance pointer that needs to be released. //! //! This function will free up any resources in use by the HID driver instance //! that is passed in. The \e pvInstance pointer should be a valid value that //! was returned from a call to USBHIDOpen(). //! //! \return None. // //***************************************************************************** static void HIDDriverClose(void *pvInstance) { tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)pvInstance; // // No device so just exit. // if(pHIDInstance->pDevice == 0) { return; } // // Reset the device pointer. // pHIDInstance->pDevice = 0; // // Free the Interrupt IN pipe. // if(pHIDInstance->ulIntInPipe != 0) { USBHCDPipeFree(pHIDInstance->ulIndex, pHIDInstance->ulIntInPipe); } // // If the callback exists, call it with an Open event. // if(pHIDInstance->pfnCallback != 0) { pHIDInstance->pfnCallback((void *)pHIDInstance->ulCBData, USB_EVENT_DISCONNECTED, (unsigned int)&pHIDInstance, 0); } } //***************************************************************************** // //! This function is used to set the idle timeout for a HID device. //! //! \param ulInstance is the value that was returned from the call to //! USBHHIDOpen(). //! \param ucDuration is the duration of the timeout in milliseconds. //! \param ucReportID is the report identifier to set the timeout on. //! //! This function will send the Set Idle command to a HID device to set the //! idle timeout for a given report. The length of the timeout is specified //! by the \e ucDuration parameter and the report the timeout for is in the //! \e ucReportID value. //! //! \return Always returns 0. // //***************************************************************************** unsigned int USBHHIDSetIdle(unsigned int ulInstance, unsigned char ucDuration, unsigned char ucReportID) { tUSBRequest SetupPacket; tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulInstance; // // This is a Class specific interface OUT request. // SetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE; // // Request a Device Descriptor. // SetupPacket.bRequest = USBREQ_SET_IDLE; SetupPacket.wValue = (ucDuration << 8) | ucReportID; // // Set this on interface 1. // SetupPacket.wIndex = 0; // // This is always 0 for this request. // SetupPacket.wLength = 0; // // Put the setup packet in the buffer. // USBHCDControlTransfer(pHIDInstance->ulIndex, &SetupPacket, pHIDInstance->pDevice->ulAddress, 0, 0, MAX_PACKET_SIZE_EP0); return (0); } //***************************************************************************** // //! This function can be used to retrieve the report descriptor for a given //! device instance. //! //! \param ulInstance is the value that was returned from the call to //! USBHHIDOpen(). //! \param pucBuffer is the memory buffer to use to store the report //! descriptor. //! \param ulSize is the size in bytes of the buffer pointed to by //! \e pucBuffer. //! //! This function is used to return a report descriptor from a HID device //! instance so that it can determine how to interpret reports that are //! returned from the device indicated by the \e ulInstance parameter. //! This call is blocking and will return the number of bytes read into the //! \e pucBuffer. //! //! \return Returns the number of bytes read into the \e pucBuffer. // //***************************************************************************** unsigned int USBHHIDGetReportDescriptor(unsigned int ulInstance, unsigned char *pucBuffer, unsigned int ulSize) { tUSBRequest SetupPacket; unsigned int ulBytes; tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulInstance; // // This is a Standard Device IN request. // SetupPacket.bmRequestType = USB_RTYPE_DIR_IN | USB_RTYPE_STANDARD | USB_RTYPE_INTERFACE; // // Request a Report Descriptor. // SetupPacket.bRequest = USBREQ_GET_DESCRIPTOR; SetupPacket.wValue = USB_HID_DTYPE_REPORT << 8; // // Index is always 0 for device requests. // SetupPacket.wIndex = 0; // // All devices must have at least an 8 byte max packet size so just ask // for 8 bytes to start with. // SetupPacket.wLength = ulSize; // // Now get the full descriptor now that the actual maximum packet size // is known. // ulBytes = USBHCDControlTransfer( pHIDInstance->ulIndex, &SetupPacket, pHIDInstance->pDevice->ulAddress, pucBuffer, ulSize, pHIDInstance->pDevice->DeviceDescriptor.bMaxPacketSize0); return (ulBytes); } //***************************************************************************** // //! This function is used to set or clear the boot protocol state of a device. //! //! \param ulInstance is the value that was returned from the call to //! USBHHIDOpen(). //! \param ulBootProtocol is either zero or non-zero to indicate which protocol //! to use for the device. //! //! A USB host device can use this function to set the protocol for a connected //! HID device. This is commonly used to set keyboards and mice into their //! simplified boot protocol modes to fix the report structure to a know //! state. //! //! \return This function returns 0. // //***************************************************************************** unsigned int USBHHIDSetProtocol(unsigned int ulInstance, unsigned int ulBootProtocol) { tUSBRequest SetupPacket; tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulInstance; // // This is a Standard Device IN request. // SetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE; // // Request a Report Descriptor. // SetupPacket.bRequest = USBREQ_SET_PROTOCOL; if(ulBootProtocol) { // // Boot Protocol. // SetupPacket.wValue = 0; } else { // // Report Protocol. // SetupPacket.wValue = 1; } // // Index is always 0 for device requests. // SetupPacket.wIndex = 0; // // Always 0. // SetupPacket.wLength = 0; // // Now get the full descriptor now that the actual maximum packet size // is known. // USBHCDControlTransfer( pHIDInstance->ulIndex, &SetupPacket, pHIDInstance->pDevice->ulAddress, 0, 0, pHIDInstance->pDevice->DeviceDescriptor.bMaxPacketSize0); return (0); } //***************************************************************************** // //! This function is used to retrieve a report from a HID device. //! //! \param ulInstance is the value that was returned from the call to //! USBHHIDOpen(). //! \param ulInterface is the interface to retrieve the report from. //! \param pucData is the memory buffer to use to store the report. //! \param ulSize is the size in bytes of the buffer pointed to by //! \e pucBuffer. //! //! This function is used to retrieve a report from a USB pipe. It is usually //! called when the USB HID layer has detected a new data available in a USB //! pipe. The USB HID host device code will receive a //! \b USB_EVENT_RX_AVAILABLE event when data is available, allowing the //! callback function to retrieve the data. //! //! \return Returns the number of bytes read from report. // //***************************************************************************** unsigned int USBHHIDGetReport(unsigned int ulInstance, unsigned int ulInterface, unsigned char *pucData, unsigned int ulSize) { tHIDInstance *pHIDInstance; // // Cast the instance pointer to the correct type for ease of use. // pHIDInstance = (tHIDInstance *)ulInstance; // // Read the Data out. // ulSize = USBHCDPipeReadNonBlocking(pHIDInstance->ulIndex, pHIDInstance ->ulIntInPipe, pucData, ulSize); // // Return the number of bytes read from the interrupt in pipe. // return(ulSize); } //***************************************************************************** // //! This function is used to send a report to a HID device. //! //! \param ulInstance is the value that was returned from the call to //! USBHHIDOpen(). //! \param ulInterface is the interface to send the report to. //! \param pucData is the memory buffer to use to store the report. //! \param ulSize is the size in bytes of the buffer pointed to by //! \e pucBuffer. //! //! This function is used to send a report to a USB HID device. It can be //! only be called from outside the callback context as this function will not //! return from the call until the data has been sent successfully. //! //! \return Returns the number of bytes sent to the device. // //***************************************************************************** unsigned int USBHHIDSetReport(unsigned int ulInstance, unsigned int ulInterface, unsigned char *pucData, unsigned int ulSize) { tUSBRequest SetupPacket; tHIDInstance *pHIDInstance; pHIDInstance = (tHIDInstance *)ulInstance; // // This is a Standard Device IN request. // SetupPacket.bmRequestType = USB_RTYPE_DIR_OUT | USB_RTYPE_CLASS | USB_RTYPE_INTERFACE; // // Request a Report Descriptor. // SetupPacket.bRequest = USBREQ_SET_REPORT; SetupPacket.wValue = USB_HID_REPORT_OUTPUT << 8; // // Index is always 0 for device requests. // SetupPacket.wIndex = (unsigned short)ulInterface; // // Always 0. // SetupPacket.wLength = ulSize; // // Now get the full descriptor now that the actual maximum packet size // is known. // USBHCDControlTransfer(pHIDInstance->ulIndex, &SetupPacket, pHIDInstance ->pDevice->ulAddress, pucData, ulSize, pHIDInstance ->pDevice->DeviceDescriptor.bMaxPacketSize0); return (ulSize); } //***************************************************************************** // //! @} // //*****************************************************************************