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