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 <andrei.emeltchenko@intel.com>
This commit is contained in:
parent
c725a90084
commit
ca85890dc2
2 changed files with 435 additions and 186 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ LOG_MODULE_REGISTER(usb_hid);
|
|||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue