diff options
| author | Damien | 2013-10-25 20:53:54 +0100 |
|---|---|---|
| committer | Damien | 2013-10-25 20:53:54 +0100 |
| commit | 58a1b4c6cf8b9675c56e9eebd0f620ec7b66d83f (patch) | |
| tree | eaa73f9969018ee88f5c013f63936c9665ecdcdd /stm/lib/usbd_pyb_core2.c | |
| parent | 2839168340b5ac9f947c01b42f7ddf960da81aa6 (diff) | |
Add USB HID support. Runs as an alternative to VCP+MSC.
Diffstat (limited to 'stm/lib/usbd_pyb_core2.c')
| -rw-r--r-- | stm/lib/usbd_pyb_core2.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/stm/lib/usbd_pyb_core2.c b/stm/lib/usbd_pyb_core2.c new file mode 100644 index 000000000..c1abda3e7 --- /dev/null +++ b/stm/lib/usbd_pyb_core2.c @@ -0,0 +1,323 @@ +#include <stdio.h>
+
+#include "usbd_ioreq.h"
+#include "usbd_desc.h"
+#include "usbd_req.h"
+#include "usbd_pyb_core.h"
+
+#define USB_PYB_CONFIG_DESC_SIZ (34)
+
+#define HID_MOUSE_REPORT_DESC_SIZE (74)
+
+#define HID_DESCRIPTOR_TYPE (0x21)
+#define HID_REPORT_DESC (0x22)
+
+#define HID_IN_EP (0x81)
+#define HID_IN_PACKET (4) /* maximum, and actual, packet size */
+
+/*********************************************
+ PYB Device library callbacks
+ *********************************************/
+
+static uint8_t usbd_pyb_Init (void *pdev, uint8_t cfgidx);
+static uint8_t usbd_pyb_DeInit (void *pdev, uint8_t cfgidx);
+static uint8_t usbd_pyb_Setup (void *pdev, USB_SETUP_REQ *req);
+static uint8_t usbd_pyb_DataIn (void *pdev, uint8_t epnum);
+
+/*********************************************
+ PYB specific management functions
+ *********************************************/
+
+static uint8_t *usbd_pyb_GetCfgDesc(uint8_t speed, uint16_t *length);
+
+__ALIGN_BEGIN static uint8_t USBD_HID_AltSet __ALIGN_END = 0;
+__ALIGN_BEGIN static uint8_t USBD_HID_Protocol __ALIGN_END = 0;
+__ALIGN_BEGIN static uint8_t USBD_HID_IdleState __ALIGN_END = 0;
+
+/* PYB interface class callbacks structure */
+USBD_Class_cb_TypeDef USBD_PYB_HID_cb =
+{
+ usbd_pyb_Init,
+ usbd_pyb_DeInit,
+ usbd_pyb_Setup,
+ NULL, // EP0_TxSent
+ NULL, // usbd_pyb_EP0_RxReady,
+ usbd_pyb_DataIn,
+ NULL, // usbd_pyb_DataOut,
+ NULL, // usbd_pyb_SOF,
+ NULL, // IsoINIncomplete
+ NULL, // IsoOUTIncomplete
+ usbd_pyb_GetCfgDesc,
+ // for OTG_HS support need to add other cfg desc here
+};
+
+/* USB PYB device Configuration Descriptor */
+__ALIGN_BEGIN static uint8_t usbd_pyb_CfgDesc[USB_PYB_CONFIG_DESC_SIZ] __ALIGN_END =
+{
+ //--------------------------------------------------------------------------
+ // Configuration Descriptor
+ 0x09, // bLength: Configuration Descriptor size
+ USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: Configuration
+ LOBYTE(USB_PYB_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes
+ HIBYTE(USB_PYB_CONFIG_DESC_SIZ),
+ 0x01, // bNumInterfaces: 1 interfaces
+ 0x01, // bConfigurationValue: Configuration value
+ 0x04, // iConfiguration: Index of string descriptor describing the configuration
+ 0x80, // bmAttributes: bus powered; 0xc0 for self powered
+ 0xfa, // bMaxPower: in units of 2mA
+
+ //--------------------------------------------------------------------------
+ // Interface Descriptor
+ 0x09, // bLength: Interface Descriptor size
+ USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: interface descriptor
+ 0x00, // bInterfaceNumber: Number of Interface
+ 0x00, // bAlternateSetting: Alternate setting
+ 0x01, // bNumEndpoints
+ 0x03, // bInterfaceClass: HID Class
+ 0x01, // bInterfaceSubClass: 0=no boot, 1=BOOT
+ 0x02, // nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse
+ 0x00, // iInterface:
+
+ // Descriptor of Joystick Mouse HID
+ 0x09, // bLength: HID Descriptor size
+ HID_DESCRIPTOR_TYPE, // bDescriptorType: HID
+ 0x11, // bcdHID: HID Class Spec release number, low byte
+ 0x01, // bcdHID: high byte
+ 0x00, // bCountryCode: Hardware target country (0=unsupported)
+ 0x01, // bNumDescriptors: Number of HID class descriptors to follow
+ HID_REPORT_DESC, // bDescriptorType: report
+ HID_MOUSE_REPORT_DESC_SIZE, // wItemLength: Total length of Report descriptor
+ 0x00,
+
+ // Endpoint IN descriptor
+ 0x07, // bLength: Endpoint descriptor length
+ USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type
+ HID_IN_EP, // bEndpointAddress: IN, address of HID
+ 0x03, // bmAttributes: Interrupt endpoint type
+ LOBYTE(HID_IN_PACKET), // wMaxPacketSize
+ HIBYTE(HID_IN_PACKET),
+ 0x0a, // bInterval: polling interval, units of 1ms
+};
+
+__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
+{
+ 0x05, 0x01,
+ 0x09, 0x02,
+ 0xA1, 0x01,
+ 0x09, 0x01,
+
+ 0xA1, 0x00,
+ 0x05, 0x09,
+ 0x19, 0x01,
+ 0x29, 0x03,
+
+ 0x15, 0x00,
+ 0x25, 0x01,
+ 0x95, 0x03,
+ 0x75, 0x01,
+
+ 0x81, 0x02,
+ 0x95, 0x01,
+ 0x75, 0x05,
+ 0x81, 0x01,
+
+ 0x05, 0x01,
+ 0x09, 0x30,
+ 0x09, 0x31,
+ 0x09, 0x38,
+
+ 0x15, 0x81,
+ 0x25, 0x7F,
+ 0x75, 0x08,
+ 0x95, 0x03,
+
+ 0x81, 0x06,
+ 0xC0, 0x09,
+ 0x3c, 0x05,
+ 0xff, 0x09,
+
+ 0x01, 0x15,
+ 0x00, 0x25,
+ 0x01, 0x75,
+ 0x01, 0x95,
+
+ 0x02, 0xb1,
+ 0x22, 0x75,
+ 0x06, 0x95,
+ 0x01, 0xb1,
+
+ 0x01, 0xc0
+};
+
+/**
+ * @brief usbd_pyb_Init
+ * Initilaize the PYB interface
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t usbd_pyb_Init(void *pdev, uint8_t cfgidx) {
+ // deinit first to reset
+ usbd_pyb_DeInit(pdev, cfgidx);
+
+ // Open EP IN
+ DCD_EP_Open(pdev,
+ HID_IN_EP,
+ HID_IN_PACKET,
+ USB_OTG_EP_INT);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_Init
+ * DeInitialize the CDC layer
+ * @param pdev: device instance
+ * @param cfgidx: Configuration index
+ * @retval status
+ */
+static uint8_t usbd_pyb_DeInit(void *pdev, uint8_t cfgidx) {
+ // Close HID EP
+ DCD_EP_Close(pdev, HID_IN_EP);
+
+ return USBD_OK;
+}
+
+#define HID_REQ_SET_PROTOCOL (0x0B)
+#define HID_REQ_GET_PROTOCOL (0x03)
+#define HID_REQ_SET_IDLE (0x0A)
+#define HID_REQ_GET_IDLE (0x02)
+#define HID_REQ_SET_REPORT (0x09) // used?
+#define HID_REQ_GET_REPORT (0x01) // used?
+
+/**
+ * @brief usbd_pyb_Setup
+ * Handle the CDC specific requests
+ * @param pdev: instance
+ * @param req: usb requests
+ * @retval status
+ */
+static uint8_t usbd_pyb_Setup(void *pdev, USB_SETUP_REQ *req) {
+ switch (req->bmRequest & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) {
+
+ // Standard Device Request ---------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_DEVICE):
+ break;
+
+ // Standard Interface Request ------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE):
+ switch (req->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR: // needed for HID; SU 0x81 0x06 0x2200 0x00 request
+ // wIndex & 0xff is the interface
+ if ((req->wIndex & 0xff) == 0) {
+ uint16_t len = 0;
+ uint8_t *pbuf = NULL;
+ if( req->wValue >> 8 == HID_REPORT_DESC) {
+ len = MIN(HID_MOUSE_REPORT_DESC_SIZE , req->wLength);
+ pbuf = HID_MOUSE_ReportDesc;
+ return USBD_CtlSendData (pdev, pbuf, len);
+ } else if( req->wValue >> 8 == HID_DESCRIPTOR_TYPE) {
+ pbuf = usbd_pyb_CfgDesc + 0x09 + 0x09;
+ len = MIN(0x09 , req->wLength);
+ return USBD_CtlSendData (pdev, pbuf, len);
+ }
+ }
+
+ case USB_REQ_GET_INTERFACE:
+ // wIndex & 0xff is the interface
+ if ((req->wIndex & 0xff) == 0) {
+ return USBD_CtlSendData(pdev, &USBD_HID_AltSet, 1);
+ }
+
+ case USB_REQ_SET_INTERFACE:
+ if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM) { // TODO
+ if ((req->wIndex & 0xff) == 0) {
+ USBD_HID_AltSet = req->wValue;
+ }
+ return USBD_OK;
+ }
+ }
+ break;
+
+ // Standard Endpoint Request -------------------------------------------
+ case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_ENDPOINT):
+ // req->wIndex is the endpoint number, including direction
+ break;
+
+ // CDC Class Requests ------------------------------
+ case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE):
+ // req->wIndex is the recipient interface number
+ if (req->wIndex == 0) {
+ // HID component
+ switch (req->bRequest) {
+ case HID_REQ_SET_PROTOCOL:
+ USBD_HID_Protocol = req->wValue;
+ return USBD_OK;
+
+ case HID_REQ_GET_PROTOCOL:
+ return USBD_CtlSendData(pdev, &USBD_HID_Protocol, 1);
+
+ case HID_REQ_SET_IDLE:
+ USBD_HID_IdleState = (req->wValue >> 8);
+ return USBD_OK;
+
+ case HID_REQ_GET_IDLE:
+ return USBD_CtlSendData(pdev, &USBD_HID_IdleState, 1);
+ }
+ }
+ break;
+ }
+
+ printf("SU %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex);
+
+ // invalid command
+ USBD_CtlError(pdev, req);
+ return USBD_FAIL;
+}
+
+/**
+ * @brief usbd_pyb_DataIn
+ * Data sent on non-control IN endpoint
+ * @param pdev: device instance
+ * @param epnum: endpoint number
+ * @retval status
+ */
+static uint8_t usbd_pyb_DataIn(void *pdev, uint8_t epnum) {
+ switch (epnum) {
+ case (HID_IN_EP & 0x7f):
+ /* Ensure that the FIFO is empty before a new transfer, this condition could
+ be caused by a new transfer before the end of the previous transfer */
+ DCD_EP_Flush(pdev, HID_IN_EP);
+ return USBD_OK;
+ }
+
+ printf("DI %x\n", epnum);
+
+ return USBD_OK;
+}
+
+/**
+ * @brief usbd_pyb_GetCfgDesc
+ * Return configuration descriptor
+ * @param speed : current device speed
+ * @param length : pointer data length
+ * @retval pointer to descriptor buffer
+ */
+static uint8_t *usbd_pyb_GetCfgDesc(uint8_t speed, uint16_t *length) {
+ *length = sizeof(usbd_pyb_CfgDesc);
+ return usbd_pyb_CfgDesc;
+}
+
+/**
+ * @brief USBD_HID_SendReport
+ * Send HID Report
+ * @param pdev: device instance
+ * @param buff: pointer to report (4 bytes: ?, x, y, ?)
+ * @retval status
+ */
+uint8_t USBD_HID_SendReport(USB_OTG_CORE_HANDLE *pdev, uint8_t *report, uint16_t len) {
+ if (pdev->dev.device_status == USB_OTG_CONFIGURED) {
+ DCD_EP_Tx(pdev, HID_IN_EP, report, len);
+ }
+ return USBD_OK;
+}
|
