From ca85890dc2e9e18d99779055c8d3f3a398bf3809 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Tue, 29 Jan 2019 11:47:59 +0200 Subject: [PATCH] usb: hid: Add HID Device concept Add HID Device associated with the instance of the HID. This allows to create several HID instances for multifunction composite device. Signed-off-by: Andrei Emeltchenko --- include/usb/class/usb_hid.h | 10 +- subsys/usb/class/hid/core.c | 611 +++++++++++++++++++++++++----------- 2 files changed, 435 insertions(+), 186 deletions(-) diff --git a/include/usb/class/usb_hid.h b/include/usb/class/usb_hid.h index 93187d29a22..e569c7b4cc6 100644 --- a/include/usb/class/usb_hid.h +++ b/include/usb/class/usb_hid.h @@ -236,17 +236,19 @@ struct hid_ops { /* Register HID device */ -void usb_hid_register_device(const u8_t *desc, size_t size, +void usb_hid_register_device(struct device *dev, const u8_t *desc, size_t size, const struct hid_ops *op); /* Write to hid interrupt endpoint */ -int hid_int_ep_write(const u8_t *data, u32_t data_len, u32_t *bytes_ret); +int hid_int_ep_write(const struct device *dev, const u8_t *data, u32_t data_len, + u32_t *bytes_ret); /* Read from hid interrupt endpoint */ -int hid_int_ep_read(u8_t *data, u32_t max_data_len, u32_t *ret_bytes); +int hid_int_ep_read(const struct device *dev, u8_t *data, u32_t max_data_len, + u32_t *ret_bytes); /* Initialize USB HID */ -int usb_hid_init(void); +int usb_hid_init(const struct device *dev); #ifdef __cplusplus } diff --git a/subsys/usb/class/hid/core.c b/subsys/usb/class/hid/core.c index c859abecabf..7ccaea5acbe 100644 --- a/subsys/usb/class/hid/core.c +++ b/subsys/usb/class/hid/core.c @@ -20,8 +20,8 @@ LOG_MODULE_REGISTER(usb_hid); #include -#define HID_INT_IN_EP_ADDR 0x81 -#define HID_INT_OUT_EP_ADDR 0x01 +#define HID_INT_IN_EP_ADDR 0x81 +#define HID_INT_OUT_EP_ADDR 0x01 #define HID_INT_IN_EP_IDX 0 #define HID_INT_OUT_EP_IDX 1 @@ -35,62 +35,89 @@ struct usb_hid_config { #endif } __packed; -USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_hid_config hid_cfg = { - /* Interface descriptor */ - .if0 = { - .bLength = sizeof(struct usb_if_descriptor), - .bDescriptorType = USB_INTERFACE_DESC, - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 1, - .bInterfaceClass = HID_CLASS, -#ifdef CONFIG_USB_HID_BOOT_PROTOCOL - .bInterfaceSubClass = 1, - .bInterfaceProtocol = CONFIG_USB_HID_PROTOCOL_CODE, +#if defined(CONFIG_USB_HID_BOOT_PROTOCOL) +#define INITIALIZER_IF \ + { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_INTERFACE_DESC, \ + .bInterfaceNumber = 0, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 1, \ + .bInterfaceClass = HID_CLASS, \ + .bInterfaceSubClass = 1, \ + .bInterfaceProtocol = CONFIG_USB_HID_PROTOCOL_CODE, \ + .iInterface = 0, \ + } #else - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, +#define INITIALIZER_IF \ + { \ + .bLength = sizeof(struct usb_if_descriptor), \ + .bDescriptorType = USB_INTERFACE_DESC, \ + .bInterfaceNumber = 0, \ + .bAlternateSetting = 0, \ + .bNumEndpoints = 1, \ + .bInterfaceClass = HID_CLASS, \ + .bInterfaceSubClass = 0, \ + .bInterfaceProtocol = 0, \ + .iInterface = 0, \ + } #endif - .iInterface = 0, - }, - .if0_hid = { - .bLength = sizeof(struct usb_hid_descriptor), - .bDescriptorType = USB_HID_DESC, - .bcdHID = sys_cpu_to_le16(USB_1_1), - .bCountryCode = 0, - .bNumDescriptors = 1, - .subdesc[0] = { - .bDescriptorType = USB_HID_REPORT_DESC, - /* - * descriptor length needs to be set - * after initialization - */ - .wDescriptorLength = 0, - }, - }, - .if0_int_in_ep = { - .bLength = sizeof(struct usb_ep_descriptor), - .bDescriptorType = USB_ENDPOINT_DESC, - .bEndpointAddress = HID_INT_IN_EP_ADDR, - .bmAttributes = USB_DC_EP_INTERRUPT, - .wMaxPacketSize = - sys_cpu_to_le16(CONFIG_HID_INTERRUPT_EP_MPS), - .bInterval = CONFIG_USB_HID_POLL_INTERVAL_MS, - }, -#ifdef CONFIG_ENABLE_HID_INT_OUT_EP - .if0_int_out_ep = { - .bLength = sizeof(struct usb_ep_descriptor), - .bDescriptorType = USB_ENDPOINT_DESC, - .bEndpointAddress = HID_INT_OUT_EP_ADDR, - .bmAttributes = USB_DC_EP_INTERRUPT, - .wMaxPacketSize = - sys_cpu_to_le16(CONFIG_HID_INTERRUPT_EP_MPS), - .bInterval = CONFIG_USB_HID_POLL_INTERVAL_MS, - }, -#endif -}; -static struct hid_device_info { +/* Descriptor length needs to be set after initialization */ +#define INITIALIZER_IF_HID \ + { \ + .bLength = sizeof(struct usb_hid_descriptor), \ + .bDescriptorType = USB_HID_DESC, \ + .bcdHID = sys_cpu_to_le16(USB_1_1), \ + .bCountryCode = 0, \ + .bNumDescriptors = 1, \ + .subdesc[0] = { \ + .bDescriptorType = USB_HID_REPORT_DESC, \ + .wDescriptorLength = 0, \ + }, \ + } + +#define INITIALIZER_IF_EP(addr, attr, mps) \ + { \ + .bLength = sizeof(struct usb_ep_descriptor), \ + .bDescriptorType = USB_ENDPOINT_DESC, \ + .bEndpointAddress = addr, \ + .bmAttributes = attr, \ + .wMaxPacketSize = sys_cpu_to_le16(mps), \ + .bInterval = CONFIG_USB_HID_POLL_INTERVAL_MS, \ + } + +#ifdef CONFIG_ENABLE_HID_INT_OUT_EP +#define DEFINE_HID_DESCR(x) \ + USBD_CLASS_DESCR_DEFINE(primary, x) \ + struct usb_hid_config hid_cfg_##x = { \ + /* Interface descriptor */ \ + .if0 = INITIALIZER_IF, \ + .if0_hid = INITIALIZER_IF_HID, \ + .if0_int_in_ep = \ + INITIALIZER_IF_EP(HID_INT_IN_EP_ADDR, \ + USB_DC_EP_INTERRUPT, \ + CONFIG_HID_INTERRUPT_EP_MPS), \ + .if0_int_out_ep = \ + INITIALIZER_IF_EP(HID_INT_OUT_EP_ADDR, \ + USB_DC_EP_INTERRUPT, \ + CONFIG_HID_INTERRUPT_EP_MPS), \ +} +#else +#define DEFINE_HID_DESCR(x) \ + USBD_CLASS_DESCR_DEFINE(primary, x) \ + struct usb_hid_config hid_cfg_##x = { \ + /* Interface descriptor */ \ + .if0 = INITIALIZER_IF, \ + .if0_hid = INITIALIZER_IF_HID, \ + .if0_int_in_ep = \ + INITIALIZER_IF_EP(HID_INT_IN_EP_ADDR, \ + USB_DC_EP_INTERRUPT, \ + CONFIG_HID_INTERRUPT_EP_MPS), \ +} +#endif + +struct hid_device_info { const u8_t *report_desc; size_t report_size; const struct hid_ops *ops; @@ -103,9 +130,53 @@ static struct hid_device_info { #ifdef CONFIG_USB_HID_BOOT_PROTOCOL u8_t protocol; #endif -} hid_device; + struct device *dev; + sys_snode_t node; +}; -static int hid_on_get_idle(struct usb_setup_packet *setup, s32_t *len, +static sys_slist_t usb_hid_devlist; + +static struct hid_device_info *get_dev_data_by_iface(u8_t iface_num) +{ + struct hid_device_info *dev_data; + + SYS_SLIST_FOR_EACH_CONTAINER(&usb_hid_devlist, dev_data, node) { + struct device *dev = dev_data->dev; + const struct usb_cfg_data *cfg = dev->config->config_info; + const struct usb_if_descriptor *if_desc = + cfg->interface_descriptor; + + if (if_desc->bInterfaceNumber == iface_num) { + return dev_data; + } + } + + LOG_DBG("Device data not found for iface number %u", iface_num); + return NULL; +} + +static struct hid_device_info *get_dev_data_by_ep(u8_t ep) +{ + struct hid_device_info *dev_data; + + SYS_SLIST_FOR_EACH_CONTAINER(&usb_hid_devlist, dev_data, node) { + struct device *dev = dev_data->dev; + const struct usb_cfg_data *cfg = dev->config->config_info; + const struct usb_ep_cfg_data *ep_data = cfg->endpoint; + + for (u8_t i = 0; i < cfg->num_endpoints; i++) { + if (ep_data[i].ep_addr == ep) { + return dev_data; + } + } + } + + LOG_DBG("Device data not found for ep %u", ep); + return NULL; +} + +static int hid_on_get_idle(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { #ifdef CONFIG_USB_DEVICE_SOF @@ -116,11 +187,11 @@ static int hid_on_get_idle(struct usb_setup_packet *setup, s32_t *len, return -ENOTSUP; } - u32_t size = sizeof(hid_device.idle_rate[report_id]); + u32_t size = sizeof(dev_data->idle_rate[report_id]); LOG_DBG("Get Idle callback, report_id: %d", report_id); - *data = &hid_device.idle_rate[report_id]; + *data = &dev_data->idle_rate[report_id]; len = &size; return 0; #else @@ -128,7 +199,8 @@ static int hid_on_get_idle(struct usb_setup_packet *setup, s32_t *len, #endif } -static int hid_on_get_report(struct usb_setup_packet *setup, s32_t *len, +static int hid_on_get_report(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { LOG_DBG("Get Report callback"); @@ -138,7 +210,8 @@ static int hid_on_get_report(struct usb_setup_packet *setup, s32_t *len, return -ENOTSUP; } -static int hid_on_get_protocol(struct usb_setup_packet *setup, s32_t *len, +static int hid_on_get_protocol(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { #ifdef CONFIG_USB_HID_BOOT_PROTOCOL @@ -147,11 +220,11 @@ static int hid_on_get_protocol(struct usb_setup_packet *setup, s32_t *len, return -ENOTSUP; } - u32_t size = sizeof(hid_device.protocol); + u32_t size = sizeof(dev_data->protocol); - LOG_DBG("Get Protocol callback, protocol: %d", hid_device.protocol); + LOG_DBG("Get Protocol callback, protocol: %d", dev_data->protocol); - *data = &hid_device.protocol; + *data = &dev_data->protocol; len = &size; return 0; #else @@ -159,7 +232,8 @@ static int hid_on_get_protocol(struct usb_setup_packet *setup, s32_t *len, #endif } -static int hid_on_set_idle(struct usb_setup_packet *setup, s32_t *len, +static int hid_on_set_idle(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { #ifdef CONFIG_USB_DEVICE_SOF @@ -173,35 +247,35 @@ static int hid_on_set_idle(struct usb_setup_packet *setup, s32_t *len, LOG_DBG("Set Idle callback, rate: %d, report_id: %d", rate, report_id); - hid_device.idle_rate[report_id] = rate; + dev_data->idle_rate[report_id] = rate; if (rate == 0) { /* Clear idle */ bool clear = true; for (u16_t i = 1; i <= CONFIG_USB_HID_REPORTS; i++) { - if (hid_device.idle_rate[i] != 0) { + if (dev_data->idle_rate[i] != 0) { /* Report with non-zero id has idle rate. */ clear = false; break; } } if (clear) { - hid_device.idle_id_report = false; + dev_data->idle_id_report = false; LOG_DBG("Non-zero report idle rate OFF."); - if (hid_device.idle_rate[0] == 0) { - hid_device.idle_on = false; + if (dev_data->idle_rate[0] == 0) { + dev_data->idle_on = false; LOG_DBG("Idle rate OFF."); } } } else { /* Set idle */ - hid_device.idle_on = true; + dev_data->idle_on = true; LOG_DBG("Idle rate ON."); if (report_id != 0) { /* Report with non-zero id has idle rate set now. */ - hid_device.idle_id_report = true; + dev_data->idle_id_report = true; LOG_DBG("Non-zero report idle rate ON."); } } @@ -211,7 +285,8 @@ static int hid_on_set_idle(struct usb_setup_packet *setup, s32_t *len, #endif } -static int hid_on_set_report(struct usb_setup_packet *setup, s32_t *len, +static int hid_on_set_report(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { LOG_DBG("Set Report callback"); @@ -221,7 +296,8 @@ static int hid_on_set_report(struct usb_setup_packet *setup, s32_t *len, return -ENOTSUP; } -static int hid_on_set_protocol(struct usb_setup_packet *setup, s32_t *len, +static int hid_on_set_protocol(struct hid_device_info *dev_data, + struct usb_setup_packet *setup, s32_t *len, u8_t **data) { #ifdef CONFIG_USB_HID_BOOT_PROTOCOL @@ -234,11 +310,11 @@ static int hid_on_set_protocol(struct usb_setup_packet *setup, s32_t *len, LOG_DBG("Set Protocol callback, protocol: %u", protocol); - if (hid_device.protocol != protocol) { - hid_device.protocol = protocol; + if (dev_data->protocol != protocol) { + dev_data->protocol = protocol; - if (hid_device.ops && hid_device.ops->protocol_change) { - hid_device.ops->protocol_change(protocol); + if (dev_data->ops && dev_data->ops->protocol_change) { + dev_data->ops->protocol_change(protocol); } } @@ -248,41 +324,47 @@ static int hid_on_set_protocol(struct usb_setup_packet *setup, s32_t *len, #endif } -static void usb_set_hid_report_size(u16_t size) +static void usb_set_hid_report_size(const struct usb_cfg_data *cfg, u16_t size) { + struct usb_if_descriptor *if_desc = (void *)cfg->interface_descriptor; + struct usb_hid_config *desc = + CONTAINER_OF(if_desc, struct usb_hid_config, if0); + + LOG_DBG("if_desc %p desc %p size %u", if_desc, desc, size); + sys_put_le16(size, - (u8_t *)&(hid_cfg.if0_hid.subdesc[0].wDescriptorLength)); + (u8_t *)&(desc->if0_hid.subdesc[0].wDescriptorLength)); } #ifdef CONFIG_USB_DEVICE_SOF -void hid_clear_idle_ctx(void) +void hid_clear_idle_ctx(struct hid_device_info *dev_data) { - hid_device.idle_on = false; - hid_device.idle_id_report = false; + dev_data->idle_on = false; + dev_data->idle_id_report = false; for (u16_t i = 0; i <= CONFIG_USB_HID_REPORTS; i++) { - hid_device.sof_cnt[i] = 0; - hid_device.idle_rate[i] = 0; + dev_data->sof_cnt[i] = 0; + dev_data->idle_rate[i] = 0; } } -void hid_sof_handler(void) +void hid_sof_handler(struct hid_device_info *dev_data) { for (u16_t i = 0; i <= CONFIG_USB_HID_REPORTS; i++) { - if (hid_device.idle_rate[i]) { - hid_device.sof_cnt[i]++; + if (dev_data->idle_rate[i]) { + dev_data->sof_cnt[i]++; } - u32_t diff = abs((hid_device.idle_rate[i] * 4) - - hid_device.sof_cnt[i]); + u32_t diff = abs((dev_data->idle_rate[i] * 4) + - dev_data->sof_cnt[i]); - if (diff < (2 + (hid_device.idle_rate[i] / 10))) { - hid_device.sof_cnt[i] = 0; - if (hid_device.ops && hid_device.ops->on_idle) { - hid_device.ops->on_idle(i); + if (diff < (2 + (dev_data->idle_rate[i] / 10))) { + dev_data->sof_cnt[i] = 0; + if (dev_data->ops && dev_data->ops->on_idle) { + dev_data->ops->on_idle(i); } } - if (!hid_device.idle_id_report) { + if (!dev_data->idle_id_report) { /* Only report with 0 id has idle rate. * No need to check the whole array. */ @@ -292,7 +374,9 @@ void hid_sof_handler(void) } #endif -static void hid_status_cb(enum usb_dc_status_code status, const u8_t *param) +static void hid_do_status_cb(struct hid_device_info *dev_data, + enum usb_dc_status_code status, + const u8_t *param) { switch (status) { case USB_DC_ERROR: @@ -301,10 +385,10 @@ static void hid_status_cb(enum usb_dc_status_code status, const u8_t *param) case USB_DC_RESET: LOG_DBG("USB device reset detected"); #ifdef CONFIG_USB_HID_BOOT_PROTOCOL - hid_device.protocol = HID_PROTOCOL_REPORT; + dev_data->protocol = HID_PROTOCOL_REPORT; #endif #ifdef CONFIG_USB_DEVICE_SOF - hid_clear_idle_ctx(); + hid_clear_idle_ctx(dev_data); #endif break; case USB_DC_CONNECTED: @@ -324,8 +408,8 @@ static void hid_status_cb(enum usb_dc_status_code status, const u8_t *param) break; case USB_DC_SOF: #ifdef CONFIG_USB_DEVICE_SOF - if (hid_device.idle_on) { - hid_sof_handler(); + if (dev_data->idle_on) { + hid_sof_handler(dev_data); } #endif break; @@ -335,41 +419,87 @@ static void hid_status_cb(enum usb_dc_status_code status, const u8_t *param) break; } - if (hid_device.ops && hid_device.ops->status_cb) { - hid_device.ops->status_cb(status, param); + if (dev_data->ops && dev_data->ops->status_cb) { + dev_data->ops->status_cb(status, param); } } +#ifdef CONFIG_USB_COMPOSITE_DEVICE +static void hid_status_composite_cb(struct usb_cfg_data *cfg, + enum usb_dc_status_code status, + const u8_t *param) +{ + struct usb_if_descriptor *if_desc = (void *)cfg->interface_descriptor; + struct hid_device_info *dev_data; + + dev_data = get_dev_data_by_iface(if_desc->bInterfaceNumber); + if (!dev_data) { + LOG_WRN("Device data not found for interface %u", + if_desc->bInterfaceNumber); + return; + } + + hid_do_status_cb(dev_data, status, param); +} +#else +static void hid_status_cb(enum usb_dc_status_code status, const u8_t *param) +{ + struct hid_device_info *dev_data; + + /* Should be the only one element in the list */ + dev_data = CONTAINER_OF(sys_slist_peek_head(&usb_hid_devlist), + struct hid_device_info, node); + if (dev_data == NULL) { + LOG_WRN("Device data not found"); + return; + } + + hid_do_status_cb(dev_data, status, param); +} +#endif + static int hid_class_handle_req(struct usb_setup_packet *setup, s32_t *len, u8_t **data) { + struct hid_device_info *dev_data; + LOG_DBG("Class request: bRequest 0x%x bmRequestType 0x%x len %d", setup->bRequest, setup->bmRequestType, *len); + dev_data = get_dev_data_by_iface(setup->wIndex); + if (!dev_data) { + LOG_WRN("Device data not found for interface %u", + sys_le16_to_cpu(setup->wIndex)); + return -ENODEV; + } + if (REQTYPE_GET_DIR(setup->bmRequestType) == REQTYPE_DIR_TO_HOST) { switch (setup->bRequest) { case HID_GET_IDLE: - if (hid_device.ops && hid_device.ops->get_idle) { - return hid_device.ops->get_idle(setup, len, - data); + if (dev_data->ops && dev_data->ops->get_idle) { + return dev_data->ops->get_idle(setup, len, + data); } else { - return hid_on_get_idle(setup, len, data); + return hid_on_get_idle(dev_data, setup, len, + data); } break; case HID_GET_REPORT: - if (hid_device.ops && hid_device.ops->get_report) { - return hid_device.ops->get_report(setup, len, - data); + if (dev_data->ops && dev_data->ops->get_report) { + return dev_data->ops->get_report(setup, len, + data); } else { - return hid_on_get_report(setup, len, data); + return hid_on_get_report(dev_data, setup, len, + data); } break; case HID_GET_PROTOCOL: - if (hid_device.ops && hid_device.ops->get_protocol) { - return hid_device.ops->get_protocol(setup, len, - data); + if (dev_data->ops && dev_data->ops->get_protocol) { + return dev_data->ops->get_protocol(setup, len, + data); } else { - return hid_on_get_protocol(setup, len, data); + return hid_on_get_protocol(dev_data, setup, len, + data); } break; default: @@ -379,27 +509,30 @@ static int hid_class_handle_req(struct usb_setup_packet *setup, } else { switch (setup->bRequest) { case HID_SET_IDLE: - if (hid_device.ops && hid_device.ops->set_idle) { - return hid_device.ops->set_idle(setup, len, - data); + if (dev_data->ops && dev_data->ops->set_idle) { + return dev_data->ops->set_idle(setup, len, + data); } else { - return hid_on_set_idle(setup, len, data); + return hid_on_set_idle(dev_data, setup, len, + data); } break; case HID_SET_REPORT: - if (hid_device.ops && hid_device.ops->set_report) { - return hid_device.ops->set_report(setup, len, - data); + if (dev_data->ops && dev_data->ops->set_report) { + return dev_data->ops->set_report(setup, len, + data); } else { - return hid_on_set_report(setup, len, data); + return hid_on_set_report(dev_data, setup, len, + data); } break; case HID_SET_PROTOCOL: - if (hid_device.ops && hid_device.ops->set_protocol) { - return hid_device.ops->set_protocol(setup, len, - data); + if (dev_data->ops && dev_data->ops->set_protocol) { + return dev_data->ops->set_protocol(setup, len, + data); } else { - return hid_on_set_protocol(setup, len, data); + return hid_on_set_protocol(dev_data, setup, len, + data); } break; default: @@ -422,13 +555,26 @@ static int hid_custom_handle_req(struct usb_setup_packet *setup, REQTYPE_RECIP_INTERFACE && setup->bRequest == REQ_GET_DESCRIPTOR) { u8_t value = sys_le16_to_cpu(setup->wValue) >> 8; + struct hid_device_info *dev_data; + const struct usb_cfg_data *cfg; + const struct usb_hid_config *hid_desc; + + dev_data = get_dev_data_by_iface(setup->wIndex); + if (!dev_data) { + LOG_WRN("Device data not found for interface %u", + sys_le16_to_cpu(setup->wIndex)); + return -ENODEV; + } switch (value) { case HID_CLASS_DESCRIPTOR_HID: + cfg = dev_data->dev->config->config_info; + hid_desc = cfg->interface_descriptor; + LOG_DBG("Return HID Descriptor"); - *len = min(*len, hid_cfg.if0_hid.bLength); - *data = (u8_t *)&hid_cfg.if0_hid; + *len = min(*len, hid_desc->if0_hid.bLength); + *data = (u8_t *)&hid_desc->if0_hid; break; case HID_CLASS_DESCRIPTOR_REPORT: LOG_DBG("Return Report Descriptor"); @@ -437,12 +583,12 @@ static int hid_custom_handle_req(struct usb_setup_packet *setup, * it try read HID report descriptor, although we had * already tell it the right descriptor size. * So truncated wLength if it doesn't match. */ - if (*len != hid_device.report_size) { + if (*len != dev_data->report_size) { LOG_WRN("len %d doesn't match " "Report Descriptor size", *len); - *len = min(*len, hid_device.report_size); + *len = min(*len, dev_data->report_size); } - *data = (u8_t *)hid_device.report_desc; + *data = (u8_t *)dev_data->report_desc; break; default: return -ENOTSUP; @@ -456,92 +602,142 @@ static int hid_custom_handle_req(struct usb_setup_packet *setup, static void hid_int_in(u8_t ep, enum usb_dc_ep_cb_status_code ep_status) { - if (ep_status != USB_DC_EP_DATA_IN || - hid_device.ops == NULL || - hid_device.ops->int_in_ready == NULL) { + struct hid_device_info *dev_data; + + dev_data = get_dev_data_by_ep(ep); + if (dev_data == NULL) { + LOG_WRN("Device data not found for endpoint %u", ep); return; } - hid_device.ops->int_in_ready(); + + if (ep_status != USB_DC_EP_DATA_IN || dev_data->ops == NULL || + dev_data->ops->int_in_ready == NULL) { + return; + } + + dev_data->ops->int_in_ready(); } #ifdef CONFIG_ENABLE_HID_INT_OUT_EP static void hid_int_out(u8_t ep, enum usb_dc_ep_cb_status_code ep_status) { - if (ep_status != USB_DC_EP_DATA_OUT || - hid_device.ops == NULL || - hid_device.ops->int_out_ready == NULL) { + struct hid_device_info *dev_data; + + dev_data = get_dev_data_by_ep(ep); + if (dev_data == NULL) { + LOG_WRN("Device data not found for endpoint %u", ep); return; } - hid_device.ops->int_out_ready(); + + if (ep_status != USB_DC_EP_DATA_OUT || dev_data->ops == NULL || + dev_data->ops->int_out_ready == NULL) { + return; + } + + dev_data->ops->int_out_ready(); } #endif -/* Describe Endpoints configuration */ -static struct usb_ep_cfg_data hid_ep_data[] = { - { - .ep_cb = hid_int_in, - .ep_addr = HID_INT_IN_EP_ADDR - }, -#ifdef CONFIG_ENABLE_HID_INT_OUT_EP - { - .ep_cb = hid_int_out, - .ep_addr = HID_INT_OUT_EP_ADDR, +#define INITIALIZER_EP_DATA(cb, addr) \ + { \ + .ep_cb = cb, \ + .ep_addr = addr, \ + } +/* Describe Endpoints configuration */ +#ifdef CONFIG_ENABLE_HID_INT_OUT_EP +#define DEFINE_HID_EP(x) \ + static struct usb_ep_cfg_data hid_ep_data_##x[] = { \ + INITIALIZER_EP_DATA(hid_int_in, HID_INT_IN_EP_ADDR), \ + INITIALIZER_EP_DATA(hid_int_out, HID_INT_OUT_EP_ADDR), \ + } +#else +#define DEFINE_HID_EP(x) \ + static struct usb_ep_cfg_data hid_ep_data_##x[] = { \ + INITIALIZER_EP_DATA(hid_int_in, HID_INT_IN_EP_ADDR), \ } #endif -}; static void hid_interface_config(struct usb_desc_header *head, u8_t bInterfaceNumber) { - ARG_UNUSED(head); + struct usb_if_descriptor *if_desc = (struct usb_if_descriptor *)head; + struct usb_hid_config *desc = + CONTAINER_OF(if_desc, struct usb_hid_config, if0); - hid_cfg.if0.bInterfaceNumber = bInterfaceNumber; - hid_cfg.if0.bNumEndpoints = ARRAY_SIZE(hid_ep_data); + LOG_DBG(""); + + desc->if0.bInterfaceNumber = bInterfaceNumber; +#ifdef CONFIG_ENABLE_HID_INT_OUT_EP + desc->if0.bNumEndpoints = 2; +#endif } -USBD_CFG_DATA_DEFINE(hid) struct usb_cfg_data hid_config = { - .usb_device_description = NULL, - .interface_config = hid_interface_config, - .interface_descriptor = &hid_cfg.if0, - .cb_usb_status = hid_status_cb, - .interface = { - .class_handler = hid_class_handle_req, - .custom_handler = hid_custom_handle_req, - .payload_data = NULL, - }, - .num_endpoints = ARRAY_SIZE(hid_ep_data), - .endpoint = hid_ep_data, -}; +#ifdef CONFIG_USB_COMPOSITE_DEVICE +#define DEFINE_HID_CFG_DATA(x) \ + USBD_CFG_DATA_DEFINE(hid) \ + struct usb_cfg_data hid_config_##x = { \ + .usb_device_description = NULL, \ + .interface_config = hid_interface_config, \ + .interface_descriptor = &hid_cfg_##x.if0, \ + .cb_usb_status_composite = hid_status_composite_cb, \ + .interface = { \ + .class_handler = hid_class_handle_req, \ + .custom_handler = hid_custom_handle_req, \ + .payload_data = NULL, \ + }, \ + .num_endpoints = ARRAY_SIZE(hid_ep_data_##x), \ + .endpoint = hid_ep_data_##x, \ + } +#else +#define DEFINE_HID_CFG_DATA(x) \ + USBD_CFG_DATA_DEFINE(hid) \ + struct usb_cfg_data hid_config_##x = { \ + .usb_device_description = NULL, \ + .interface_config = hid_interface_config, \ + .interface_descriptor = &hid_cfg_##x.if0, \ + .cb_usb_status = hid_status_cb, \ + .interface = { \ + .class_handler = hid_class_handle_req, \ + .custom_handler = hid_custom_handle_req, \ + .payload_data = NULL, \ + }, \ + .num_endpoints = ARRAY_SIZE(hid_ep_data_##x), \ + .endpoint = hid_ep_data_##x, \ + } +#endif #if !defined(CONFIG_USB_COMPOSITE_DEVICE) static u8_t interface_data[CONFIG_USB_HID_MAX_PAYLOAD_SIZE]; #endif -int usb_hid_init(void) +int usb_hid_init(const struct device *dev) { - LOG_DBG("Initializing HID Device"); + struct usb_cfg_data *cfg = (void *)dev->config->config_info; + struct hid_device_info *dev_data = dev->driver_data; + + LOG_DBG("Initializing HID Device: dev %p", dev); /* * Modify Report Descriptor Size */ - usb_set_hid_report_size(hid_device.report_size); + usb_set_hid_report_size(cfg, dev_data->report_size); #ifndef CONFIG_USB_COMPOSITE_DEVICE int ret; - hid_config.interface.payload_data = interface_data; - hid_config.usb_device_description = usb_get_device_descriptor(); + cfg->interface.payload_data = interface_data; + cfg->usb_device_description = usb_get_device_descriptor(); /* Initialize the USB driver with the right configuration */ - ret = usb_set_config(&hid_config); + ret = usb_set_config(cfg); if (ret < 0) { LOG_ERR("Failed to config USB"); return ret; } /* Enable USB driver */ - ret = usb_enable(&hid_config); + ret = usb_enable(cfg); if (ret < 0) { LOG_ERR("Failed to enable USB"); return ret; @@ -551,27 +747,78 @@ int usb_hid_init(void) return 0; } -void usb_hid_register_device(const u8_t *desc, size_t size, - const struct hid_ops *ops) +void usb_hid_register_device(struct device *dev, const u8_t *desc, + size_t size, const struct hid_ops *ops) { - hid_device.report_desc = desc; - hid_device.report_size = size; + struct hid_device_info *dev_data = dev->driver_data; - hid_device.ops = ops; + dev_data->report_desc = desc; + dev_data->report_size = size; + + dev_data->ops = ops; + dev_data->dev = dev; + + sys_slist_append(&usb_hid_devlist, &dev_data->node); + + LOG_DBG("Added dev_data %p dev %p to devlist %p", dev_data, dev, + &usb_hid_devlist); } -int hid_int_ep_write(const u8_t *data, u32_t data_len, u32_t *bytes_ret) +int hid_int_ep_write(const struct device *dev, const u8_t *data, u32_t data_len, + u32_t *bytes_ret) { - return usb_write(hid_ep_data[HID_INT_IN_EP_IDX].ep_addr, data, + const struct usb_cfg_data *cfg = dev->config->config_info; + + return usb_write(cfg->endpoint[HID_INT_IN_EP_IDX].ep_addr, data, data_len, bytes_ret); } -int hid_int_ep_read(u8_t *data, u32_t max_data_len, u32_t *ret_bytes) +int hid_int_ep_read(const struct device *dev, u8_t *data, u32_t max_data_len, + u32_t *ret_bytes) { #ifdef CONFIG_ENABLE_HID_INT_OUT_EP - return usb_read(hid_ep_data[HID_INT_OUT_EP_IDX].ep_addr, + const struct usb_cfg_data *cfg = dev->config->config_info; + + return usb_read(cfg->endpoint[HID_INT_OUT_EP_IDX].ep_addr, data, max_data_len, ret_bytes); #else return -ENOTSUP; #endif } + +static const struct usb_hid_device_api { + void (*init)(void); +} hid_api; + +static int usb_hid_device_init(struct device *dev) +{ + LOG_DBG("Init HID Device: dev %p (%s)", dev, dev->config->name); + + return 0; +} + +#define DEFINE_HID_DEV_DATA(x) \ + struct hid_device_info usb_hid_dev_data_##x + +#define DEFINE_HID_DEVICE(x) \ + DEVICE_AND_API_INIT(usb_hid_device_##x, \ + CONFIG_USB_HID_DEVICE_NAME_##x, \ + &usb_hid_device_init, \ + &usb_hid_dev_data_##x, \ + &hid_config_##x, POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &hid_api) + +DEFINE_HID_DESCR(0); +DEFINE_HID_EP(0); +DEFINE_HID_CFG_DATA(0); +DEFINE_HID_DEV_DATA(0); +DEFINE_HID_DEVICE(0); + +#ifdef CONFIG_USB_HID_DEVICE_1 +DEFINE_HID_DESCR(1); +DEFINE_HID_EP(1); +DEFINE_HID_CFG_DATA(1); +DEFINE_HID_DEV_DATA(1); +DEFINE_HID_DEVICE(1); +#endif