1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "usbd_hid_internal.h"
8
9 #include <stdint.h>
10 #include <assert.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/usb/usbd.h>
14 #include <zephyr/usb/class/usb_hid.h>
15 #include <zephyr/usb/class/usbd_hid.h>
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(hid_api, CONFIG_USBD_HID_LOG_LEVEL);
19
hid_device_submit_report(const struct device * dev,const uint16_t size,const uint8_t * const report)20 int hid_device_submit_report(const struct device *dev,
21 const uint16_t size, const uint8_t *const report)
22 {
23 const struct hid_device_driver_api *api = dev->api;
24
25 return api->submit_report(dev, size, report);
26 }
27
hid_device_register(const struct device * dev,const uint8_t * const rdesc,const uint16_t rsize,const struct hid_device_ops * const ops)28 int hid_device_register(const struct device *dev,
29 const uint8_t *const rdesc, const uint16_t rsize,
30 const struct hid_device_ops *const ops)
31 {
32 const struct hid_device_driver_api *api = dev->api;
33
34 return api->dev_register(dev, rdesc, rsize, ops);
35 }
36
37 /* Legacy HID API wrapper below */
38
39 struct legacy_wrapper {
40 const struct device *dev;
41 const struct hid_ops *legacy_ops;
42 struct hid_device_ops *ops;
43 };
44
45 static struct hid_device_ops wrapper_ops;
46
47 #define DT_DRV_COMPAT zephyr_hid_device
48
49 #define USBD_HID_WRAPPER_DEFINE(n) \
50 { \
51 .dev = DEVICE_DT_GET(DT_DRV_INST(n)), \
52 .ops = &wrapper_ops, \
53 },
54
55 static struct legacy_wrapper wrappers[] = {
56 DT_INST_FOREACH_STATUS_OKAY(USBD_HID_WRAPPER_DEFINE)
57 };
58
get_legacy_ops(const struct device * dev)59 static const struct hid_ops *get_legacy_ops(const struct device *dev)
60 {
61 for (unsigned int i = 0; i < ARRAY_SIZE(wrappers); i++) {
62 if (wrappers[i].dev == dev) {
63 return wrappers[i].legacy_ops;
64 }
65 }
66
67 return NULL;
68 }
69
wrapper_get_report(const struct device * dev,const uint8_t type,const uint8_t id,const uint16_t len,uint8_t * const buf)70 int wrapper_get_report(const struct device *dev,
71 const uint8_t type, const uint8_t id,
72 const uint16_t len, uint8_t *const buf)
73 {
74 const struct hid_ops *legacy_ops = get_legacy_ops(dev);
75 struct usb_setup_packet setup = {
76 .bmRequestType = 0,
77 .bRequest = 0,
78 .wValue = (type << 8) | id,
79 .wIndex = 0,
80 .wLength = len,
81 };
82 uint8_t *d = buf;
83 int l = len;
84
85 if (legacy_ops != NULL && legacy_ops->get_report != NULL) {
86 return legacy_ops->get_report(dev, &setup, &l, &d);
87 }
88
89 return -ENOTSUP;
90 }
91
wrapper_set_report(const struct device * dev,const uint8_t type,const uint8_t id,const uint16_t len,const uint8_t * const buf)92 int wrapper_set_report(const struct device *dev,
93 const uint8_t type, const uint8_t id,
94 const uint16_t len, const uint8_t *const buf)
95 {
96 const struct hid_ops *legacy_ops = get_legacy_ops(dev);
97 struct usb_setup_packet setup = {
98 .bmRequestType = 0,
99 .bRequest = 0,
100 .wValue = (type << 8) | id,
101 .wIndex = 0,
102 .wLength = len,
103 };
104 uint8_t *d = (void *)buf;
105 int l = len;
106
107 if (legacy_ops != NULL && legacy_ops->set_report != NULL) {
108 return legacy_ops->set_report(dev, &setup, &l, &d);
109 }
110
111 return -ENOTSUP;
112 }
113
wrapper_set_idle(const struct device * dev,const uint8_t id,const uint32_t duration)114 void wrapper_set_idle(const struct device *dev,
115 const uint8_t id, const uint32_t duration)
116 {
117 if (id != 0U) {
118 LOG_ERR("Set Idle for %s ID %u duration %u cannot be propagated",
119 dev->name, id, duration);
120 }
121 }
122
wrapper_set_protocol(const struct device * dev,const uint8_t proto)123 void wrapper_set_protocol(const struct device *dev, const uint8_t proto)
124 {
125 const struct hid_ops *legacy_ops = get_legacy_ops(dev);
126
127 if (legacy_ops != NULL && legacy_ops->protocol_change != NULL) {
128 legacy_ops->protocol_change(dev, proto);
129 }
130 }
131
wrapper_input_report_done(const struct device * dev)132 void wrapper_input_report_done(const struct device *dev)
133 {
134 const struct hid_ops *legacy_ops = get_legacy_ops(dev);
135
136 if (legacy_ops != NULL && legacy_ops->int_in_ready != NULL) {
137 legacy_ops->int_in_ready(dev);
138 }
139 }
140
wrapper_output_report(const struct device * dev,const uint16_t len,const uint8_t * const buf)141 void wrapper_output_report(const struct device *dev,
142 const uint16_t len, const uint8_t *const buf)
143 {
144 ARG_UNUSED(dev);
145 ARG_UNUSED(len);
146 ARG_UNUSED(buf);
147
148 __ASSERT(false, "Output report callback is not supported");
149 }
150
151 static struct hid_device_ops wrapper_ops = {
152 .get_report = wrapper_get_report,
153 .set_report = wrapper_set_report,
154 .set_idle = wrapper_set_idle,
155 .set_protocol = wrapper_set_protocol,
156 .input_report_done = wrapper_input_report_done,
157 .output_report = wrapper_output_report,
158 };
159
hid_int_ep_write(const struct device * dev,const uint8_t * data,uint32_t data_len,uint32_t * bytes_ret)160 int hid_int_ep_write(const struct device *dev,
161 const uint8_t *data, uint32_t data_len, uint32_t *bytes_ret)
162 {
163 int ret;
164
165 ret = hid_device_submit_report(dev, data_len, data);
166 if (bytes_ret != NULL) {
167 *bytes_ret = ret == 0 ? data_len : 0;
168 }
169
170 return ret;
171 }
172
hid_int_ep_read(const struct device * dev,uint8_t * data,uint32_t max_data_len,uint32_t * ret_bytes)173 int hid_int_ep_read(const struct device *dev,
174 uint8_t *data, uint32_t max_data_len, uint32_t *ret_bytes)
175 {
176 ARG_UNUSED(dev);
177 ARG_UNUSED(data);
178 ARG_UNUSED(max_data_len);
179 ARG_UNUSED(ret_bytes);
180
181 LOG_ERR("Not supported");
182
183 return -ENOTSUP;
184 }
185
usb_hid_set_proto_code(const struct device * dev,uint8_t proto_code)186 int usb_hid_set_proto_code(const struct device *dev, uint8_t proto_code)
187 {
188 ARG_UNUSED(dev);
189 ARG_UNUSED(proto_code);
190
191 LOG_WRN("Protocol code is set using DT property protocol-code");
192
193 return 0;
194 }
195
usb_hid_init(const struct device * dev)196 int usb_hid_init(const struct device *dev)
197 {
198 LOG_DBG("It does nothing for dev %s", dev->name);
199
200 return 0;
201 }
202
usb_hid_register_device(const struct device * dev,const uint8_t * desc,size_t size,const struct hid_ops * ops)203 void usb_hid_register_device(const struct device *dev,
204 const uint8_t *desc, size_t size,
205 const struct hid_ops *ops)
206 {
207 for (unsigned int i = 0; i < ARRAY_SIZE(wrappers); i++) {
208 if (wrappers[i].dev == dev) {
209 wrappers[i].legacy_ops = ops;
210 if (hid_device_register(dev, desc, size, wrappers[i].ops)) {
211 LOG_ERR("Failed to register HID device");
212 }
213 }
214 }
215
216 }
217