1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 * @brief USB HID subclass driver
15 * @see USB HID subclass specification
16 */
17#include <stdio.h>
18#include <string.h>
19
20#include "../services.h"
21#include "hid.h"
22#include "usbkbd.h"
23
24static inline struct usbreq
25__set_protocol_req(enum hid_protocol p, int iface) {
26    struct usbreq r = {
27        .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE),
28        .bRequest      = SET_PROTOCOL,
29        .wValue        = p,
30        .wIndex        = iface,
31        .wLength       = 0
32    };
33    return r;
34}
35
36static inline struct usbreq
37__get_protocol_req(int iface) {
38    struct usbreq r = {
39        .bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE),
40        .bRequest      = GET_PROTOCOL,
41        .wValue        = 0,
42        .wIndex        = iface,
43        .wLength       = 1
44    };
45    return r;
46}
47
48static inline struct usbreq
49__set_idle_req(int idle_ms, int id, int iface) {
50    struct usbreq r = {
51        .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE),
52        .bRequest      = SET_IDLE,
53        .wValue        = idle_ms << 8 | id,
54        .wIndex        = iface,
55        .wLength       = 0
56    };
57    return r;
58}
59
60
61static inline struct usbreq
62__get_report_req(enum hid_report_type type, int id, int iface, int len) {
63    struct usbreq r = {
64        .bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE),
65        .bRequest      = GET_REPORT,
66        .wValue        = type << 8 | id,
67        .wIndex        = iface,
68        .wLength       = len
69    };
70    return r;
71}
72
73static inline struct usbreq
74__set_report_req(enum hid_report_type type, int id, int iface, int len) {
75    struct usbreq r = {
76        .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE),
77        .bRequest      = SET_REPORT,
78        .wValue        = type << 8 | id,
79        .wIndex        = iface,
80        .wLength       = len
81    };
82    return r;
83}
84
85static int
86usb_hid_config_cb(void *token, int cfg, int iface, struct anon_desc *desc)
87{
88	struct usb_hid_device *hid;
89	struct config_desc *cdesc;
90	struct iface_desc *idesc;
91	struct hid_desc *hdesc;
92
93	if (!desc) {
94		return 0;
95	}
96
97	hid = (struct usb_hid_device *)token;
98
99	switch (desc->bDescriptorType) {
100	case CONFIGURATION:
101		cdesc = (struct config_desc*)desc;
102		hid->config = cdesc->bConfigurationValue;
103		break;
104	case INTERFACE:
105		idesc = (struct iface_desc *)desc;
106		if (idesc->bInterfaceSubClass == 1) {
107			hid->subclass = idesc->bInterfaceSubClass;
108			hid->protocol = idesc->bInterfaceProtocol;
109			hid->iface = idesc->bInterfaceNumber;
110		}
111		break;
112	case HID:
113		hdesc = (struct hid_desc *)desc;
114		if (!hid->subclass) {
115			if (hdesc->bReportDescriptorType== HID_REPORT) {
116				hid->report_size = hdesc->wReportDescriptorLength;
117			} else {
118				ZF_LOGD("Descriptor %u not supported!\n",
119					hdesc->bReportDescriptorType);
120			}
121		}
122		break;
123	default:
124		break;
125	}
126
127	return 0;
128}
129
130struct usb_hid_device *usb_hid_alloc(struct usb_dev *udev)
131{
132	int err;
133	struct usb_hid_device *hid;
134	struct xact xact;
135	struct usbreq *req;
136	int class;
137
138	if (!udev) {
139		ZF_LOGF("Invalid device\n");
140	}
141
142	hid = usb_malloc(sizeof(struct usb_hid_device));
143	if (!hid) {
144		ZF_LOGD("Not enough memory!\n");
145		return NULL;
146	}
147
148	hid->udev = udev;
149	hid->subclass = 0xFF;
150
151	/* Parse the descriptors */
152	err = usbdev_parse_config(udev, usb_hid_config_cb, hid);
153	if (err) {
154		ZF_LOGF("Invalid descriptors\n");
155	}
156
157	class = usbdev_get_class(udev);
158	if (class != USB_CLASS_HID) {
159		ZF_LOGD("Not a HID device(%d)\n", class);
160		usb_free(hid);
161		return NULL;
162	}
163
164	/* Activate configuration */
165	xact.len = sizeof(struct usbreq);
166	err = usb_alloc_xact(udev->dman, &xact, 1);
167	if (err) {
168		ZF_LOGF("Out of DMA memory\n");
169	}
170
171	/* Fill in the request */
172	xact.type = PID_SETUP;
173	req = xact_get_vaddr(&xact);
174	*req = __set_configuration_req(hid->config);
175
176	/* Send the request to the host */
177	err = usbdev_schedule_xact(udev, udev->ep_ctrl, &xact, 1, NULL, NULL);
178	if (err) {
179		ZF_LOGF("Transaction error\n");
180	}
181
182	usb_destroy_xact(udev->dman, &xact, 1);
183
184	return hid;
185}
186
187void usb_hid_free(struct usb_hid_device *hid)
188{
189	usb_free(hid);
190}
191
192int usb_hid_set_idle(struct usb_hid_device *hid, int idle_ms)
193{
194	int err;
195	struct usbreq *req;
196	struct xact xact;
197
198	xact.type = PID_SETUP;
199	xact.len = sizeof(struct usbreq);
200
201	err = usb_alloc_xact(hid->udev->dman, &xact, 1);
202	if (err) {
203		ZF_LOGF("Out of DMA memory\n");
204	}
205
206	req = xact_get_vaddr(&xact);
207	*req = __set_idle_req(idle_ms, 0, hid->iface);
208
209	err = usbdev_schedule_xact(hid->udev, hid->udev->ep_ctrl, &xact, 1, NULL, NULL);
210	if (err) {
211		ZF_LOGF("Transaction error\n");
212	}
213
214	usb_destroy_xact(hid->udev->dman, &xact, 1);
215
216	return err;
217}
218
219int usb_hid_get_idle(struct usb_hid_device *hid)
220{
221	return 0;
222}
223
224int usb_hid_get_report(struct usb_hid_device *hid, enum hid_report_type type, void *buf)
225{
226	return 0;
227}
228
229int usb_hid_set_report(struct usb_hid_device *hid, enum hid_report_type type,
230		void *buf, int size)
231{
232	int err;
233	struct usbreq *req;
234	struct xact xact[2];
235
236	xact[0].type = PID_SETUP;
237	xact[0].len = sizeof(struct usbreq);
238	xact[1].type = PID_OUT;
239	xact[1].len = size;
240
241	err = usb_alloc_xact(hid->udev->dman, xact, 2);
242	if (err) {
243		ZF_LOGF("Out of DMA memory\n");
244	}
245
246	req = xact_get_vaddr(&xact[0]);
247	*req = __set_report_req(REPORT_OUTPUT, 0, hid->iface, size);
248
249	memcpy(xact_get_vaddr(&xact[1]), buf, size);
250
251	err = usbdev_schedule_xact(hid->udev, hid->udev->ep_ctrl, xact, 2, NULL, NULL);
252	if (err) {
253		ZF_LOGF("Transaction error\n");
254	}
255
256	usb_destroy_xact(hid->udev->dman, xact, 2);
257
258	return err;
259}
260
261int usb_hid_get_protocol(struct usb_hid_device *hid)
262{
263	return 0;
264}
265
266int usb_hid_set_protocol(struct usb_hid_device *hid)
267{
268	return 0;
269}
270
271