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,const uint8_t * const report)132 void wrapper_input_report_done(const struct device *dev,
133 const uint8_t *const report)
134 {
135 ARG_UNUSED(report);
136
137 const struct hid_ops *legacy_ops = get_legacy_ops(dev);
138
139 if (legacy_ops != NULL && legacy_ops->int_in_ready != NULL) {
140 legacy_ops->int_in_ready(dev);
141 }
142 }
143
wrapper_output_report(const struct device * dev,const uint16_t len,const uint8_t * const buf)144 void wrapper_output_report(const struct device *dev,
145 const uint16_t len, const uint8_t *const buf)
146 {
147 ARG_UNUSED(dev);
148 ARG_UNUSED(len);
149 ARG_UNUSED(buf);
150
151 __ASSERT(false, "Output report callback is not supported");
152 }
153
154 static struct hid_device_ops wrapper_ops = {
155 .get_report = wrapper_get_report,
156 .set_report = wrapper_set_report,
157 .set_idle = wrapper_set_idle,
158 .set_protocol = wrapper_set_protocol,
159 .input_report_done = wrapper_input_report_done,
160 .output_report = wrapper_output_report,
161 };
162
hid_int_ep_write(const struct device * dev,const uint8_t * data,uint32_t data_len,uint32_t * bytes_ret)163 int hid_int_ep_write(const struct device *dev,
164 const uint8_t *data, uint32_t data_len, uint32_t *bytes_ret)
165 {
166 int ret;
167
168 ret = hid_device_submit_report(dev, data_len, data);
169 if (bytes_ret != NULL) {
170 *bytes_ret = ret == 0 ? data_len : 0;
171 }
172
173 return ret;
174 }
175
hid_int_ep_read(const struct device * dev,uint8_t * data,uint32_t max_data_len,uint32_t * ret_bytes)176 int hid_int_ep_read(const struct device *dev,
177 uint8_t *data, uint32_t max_data_len, uint32_t *ret_bytes)
178 {
179 ARG_UNUSED(dev);
180 ARG_UNUSED(data);
181 ARG_UNUSED(max_data_len);
182 ARG_UNUSED(ret_bytes);
183
184 LOG_ERR("Not supported");
185
186 return -ENOTSUP;
187 }
188
usb_hid_set_proto_code(const struct device * dev,uint8_t proto_code)189 int usb_hid_set_proto_code(const struct device *dev, uint8_t proto_code)
190 {
191 ARG_UNUSED(dev);
192 ARG_UNUSED(proto_code);
193
194 LOG_WRN("Protocol code is set using DT property protocol-code");
195
196 return 0;
197 }
198
usb_hid_init(const struct device * dev)199 int usb_hid_init(const struct device *dev)
200 {
201 LOG_DBG("It does nothing for dev %s", dev->name);
202
203 return 0;
204 }
205
usb_hid_register_device(const struct device * dev,const uint8_t * desc,size_t size,const struct hid_ops * ops)206 void usb_hid_register_device(const struct device *dev,
207 const uint8_t *desc, size_t size,
208 const struct hid_ops *ops)
209 {
210 for (unsigned int i = 0; i < ARRAY_SIZE(wrappers); i++) {
211 if (wrappers[i].dev == dev) {
212 wrappers[i].legacy_ops = ops;
213 if (hid_device_register(dev, desc, size, wrappers[i].ops)) {
214 LOG_ERR("Failed to register HID device");
215 }
216 }
217 }
218
219 }
220