usb: hid: boot protocol
Set_Protocol and Get_Protocol requests are handled now.
Tested with USB3CV.
Signed-off-by: Marcin Szymczyk <Marcin.Szymczyk@nordicsemi.no>
diff --git a/include/usb/class/usb_hid.h b/include/usb/class/usb_hid.h
index 8e42765..dae10c9 100644
--- a/include/usb/class/usb_hid.h
+++ b/include/usb/class/usb_hid.h
@@ -60,6 +60,7 @@
typedef int (*hid_cb_t)(struct usb_setup_packet *setup, s32_t *len,
u8_t **data);
typedef void (*hid_int_ready_callback)(void);
+typedef void (*hid_protocol_cb_t)(u8_t protocol);
typedef void (*hid_idle_cb_t)(u16_t report_id);
struct hid_ops {
@@ -69,6 +70,7 @@
hid_cb_t set_report;
hid_cb_t set_idle;
hid_cb_t set_protocol;
+ hid_protocol_cb_t protocol_change;
hid_idle_cb_t on_idle;
/*
* int_in_ready is an optional callback that is called when
@@ -162,6 +164,10 @@
#define COLLECTION_PHYSICAL 0x00
#define COLLECTION_APPLICATION 0x01
+/* Protocols */
+#define HID_PROTOCOL_BOOT 0x00
+#define HID_PROTOCOL_REPORT 0x01
+
/* Register HID device */
void usb_hid_register_device(const u8_t *desc, size_t size,
const struct hid_ops *op);
diff --git a/samples/subsys/usb/hid/prj.conf b/samples/subsys/usb/hid/prj.conf
index d2b92ed..638dba4 100644
--- a/samples/subsys/usb/hid/prj.conf
+++ b/samples/subsys/usb/hid/prj.conf
@@ -2,6 +2,7 @@
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_HID=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr HID sample"
+CONFIG_USB_HID_BOOT_PROTOCOL=y
CONFIG_LOG=y
CONFIG_USB_DRIVER_LOG_LEVEL_ERR=y
diff --git a/samples/subsys/usb/hid/src/main.c b/samples/subsys/usb/hid/src/main.c
index 9f231a9..1e84e46 100644
--- a/samples/subsys/usb/hid/src/main.c
+++ b/samples/subsys/usb/hid/src/main.c
@@ -99,10 +99,17 @@
LOG_DBG("Idle callback: wrote %d bytes with ret %d", wrote, ret);
}
+static void protocol_cb(u8_t protocol)
+{
+ LOG_DBG("New protocol: %s", protocol == HID_PROTOCOL_BOOT ?
+ "boot" : "report");
+}
+
static const struct hid_ops ops = {
.int_in_ready = in_ready_cb,
.status_cb = status_cb,
.on_idle = idle_cb,
+ .protocol_change = protocol_cb,
};
void main(void)
diff --git a/subsys/usb/class/hid/Kconfig b/subsys/usb/class/hid/Kconfig
index 68ce374..220c9a5 100644
--- a/subsys/usb/class/hid/Kconfig
+++ b/subsys/usb/class/hid/Kconfig
@@ -45,4 +45,29 @@
Number of HID reports in the instance.
Must be equal or higher than highest report ID (if they are not consecutive).
+config USB_HID_BOOT_PROTOCOL
+ bool
+ prompt "Enable USB HID Boot Protocol handling"
+ help
+ Sets bInterfaceSubClass to 1 and enables Set_Protocol and Get_Protocol
+ requests handling.
+ See Chapter 4.2 of Device Class Definition for Human Interface Devices 1.11
+ for more information.
+
+if USB_HID_BOOT_PROTOCOL
+
+config USB_HID_PROTOCOL_CODE
+ int "HID protocol code"
+ default 0
+ range 0 2
+ help
+ Sets bIntefaceProtocol in HID instance.
+ 0 = None
+ 1 = Keyboard
+ 2 = Mouse
+ See Chapter 4.3 of Device Class Definition for Human Interface Devices 1.11
+ for more information.
+
+endif # USB_HID_BOOT_PROTOCOL
+
endif # USB_DEVICE_HID
diff --git a/subsys/usb/class/hid/core.c b/subsys/usb/class/hid/core.c
index 0583df6..bf5da76 100644
--- a/subsys/usb/class/hid/core.c
+++ b/subsys/usb/class/hid/core.c
@@ -44,8 +44,13 @@
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = HID_CLASS,
+#ifdef CONFIG_USB_HID_BOOT_PROTOCOL
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = CONFIG_USB_HID_PROTOCOL_CODE,
+#else
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
+#endif
.iInterface = 0,
},
.if0_hid = {
@@ -95,6 +100,9 @@
bool idle_id_report;
u8_t idle_rate[CONFIG_USB_HID_REPORTS + 1];
#endif
+#ifdef CONFIG_USB_HID_BOOT_PROTOCOL
+ u8_t protocol;
+#endif
} hid_device;
static int hid_on_get_idle(struct usb_setup_packet *setup, s32_t *len,
@@ -133,11 +141,22 @@
static int hid_on_get_protocol(struct usb_setup_packet *setup, s32_t *len,
u8_t **data)
{
- LOG_DBG("Get Protocol callback");
+#ifdef CONFIG_USB_HID_BOOT_PROTOCOL
+ if (setup->wValue) {
+ LOG_ERR("wValue should be 0");
+ return -ENOTSUP;
+ }
- /* TODO: Do something. */
+ u32_t size = sizeof(hid_device.protocol);
+ LOG_DBG("Get Protocol callback, protocol: %d", hid_device.protocol);
+
+ *data = &hid_device.protocol;
+ len = &size;
+ return 0;
+#else
return -ENOTSUP;
+#endif
}
static int hid_on_set_idle(struct usb_setup_packet *setup, s32_t *len,
@@ -205,11 +224,28 @@
static int hid_on_set_protocol(struct usb_setup_packet *setup, s32_t *len,
u8_t **data)
{
- LOG_DBG("Set Protocol callback");
+#ifdef CONFIG_USB_HID_BOOT_PROTOCOL
+ u16_t protocol = sys_le16_to_cpu(setup->wValue);
- /* TODO: Do something. */
+ if (protocol > HID_PROTOCOL_REPORT) {
+ LOG_ERR("Unsupported protocol: %u", protocol);
+ return -ENOTSUP;
+ }
+ LOG_DBG("Set Protocol callback, protocol: %u", protocol);
+
+ if (hid_device.protocol != protocol) {
+ hid_device.protocol = protocol;
+
+ if (hid_device.ops && hid_device.ops->protocol_change) {
+ hid_device.ops->protocol_change(protocol);
+ }
+ }
+
+ return 0;
+#else
return -ENOTSUP;
+#endif
}
static void usb_set_hid_report_size(u16_t size)
@@ -264,6 +300,9 @@
break;
case USB_DC_RESET:
LOG_DBG("USB device reset detected");
+#ifdef CONFIG_USB_HID_BOOT_PROTOCOL
+ hid_device.protocol = HID_PROTOCOL_REPORT;
+#endif
#ifdef CONFIG_USB_DEVICE_SOF
hid_clear_idle_ctx();
#endif