source: mainline/uspace/drv/usbhid/hiddev.c@ 7351dc3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7351dc3 was 2f593872, checked in by Lubos Slovak <lubos.slovak@…>, 14 years ago

Printing of descriptor + turned on report parsing.

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2011 Lubos Slovak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup drvusbhid
30 * @{
31 */
32/**
33 * @file
34 * Generic USB HID device structure and API.
35 */
36
37#include <assert.h>
38#include <errno.h>
39#include <str_error.h>
40
41#include <ddf/driver.h>
42
43#include <usb/dp.h>
44#include <usb/debug.h>
45#include <usb/request.h>
46#include <usb/descriptor.h>
47#include <usb/classes/hid.h>
48#include <usb/pipes.h>
49
50#include "hiddev.h"
51
52/*----------------------------------------------------------------------------*/
53/* Non-API functions */
54/*----------------------------------------------------------------------------*/
55
56static int usbhid_dev_get_report_descriptor(usbhid_dev_t *hid_dev,
57 uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc)
58{
59 assert(hid_dev != NULL);
60 assert(config_desc != NULL);
61 assert(config_desc_size != 0);
62 assert(iface_desc != NULL);
63
64 usb_dp_parser_t parser = {
65 .nesting = usb_dp_standard_descriptor_nesting
66 };
67
68 usb_dp_parser_data_t parser_data = {
69 .data = config_desc,
70 .size = config_desc_size,
71 .arg = NULL
72 };
73
74 /*
75 * First nested descriptor of interface descriptor.
76 */
77 uint8_t *d =
78 usb_dp_get_nested_descriptor(&parser, &parser_data, iface_desc);
79
80 /*
81 * Search through siblings until the HID descriptor is found.
82 */
83 while (d != NULL && *(d + 1) != USB_DESCTYPE_HID) {
84 d = usb_dp_get_sibling_descriptor(&parser, &parser_data,
85 iface_desc, d);
86 }
87
88 if (d == NULL) {
89 usb_log_fatal("No HID descriptor found!\n");
90 return ENOENT;
91 }
92
93 if (*d != sizeof(usb_standard_hid_descriptor_t)) {
94 usb_log_fatal("HID descriptor hass wrong size (%u, expected %u"
95 ")\n", *d, sizeof(usb_standard_hid_descriptor_t));
96 return EINVAL;
97 }
98
99 usb_standard_hid_descriptor_t *hid_desc =
100 (usb_standard_hid_descriptor_t *)d;
101
102 uint16_t length = hid_desc->report_desc_info.length;
103 size_t actual_size = 0;
104
105 /*
106 * Allocate space for the report descriptor.
107 */
108 hid_dev->report_desc = (uint8_t *)malloc(length);
109 if (hid_dev->report_desc == NULL) {
110 usb_log_fatal("Failed to allocate space for Report descriptor."
111 "\n");
112 return ENOMEM;
113 }
114
115 usb_log_debug("Getting Report descriptor, expected size: %u\n", length);
116
117 /*
118 * Get the descriptor from the device.
119 */
120 int rc = usb_request_get_descriptor(&hid_dev->ctrl_pipe,
121 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
122 USB_DESCTYPE_HID_REPORT, 0,
123 hid_dev->iface, hid_dev->report_desc, length, &actual_size);
124
125 if (rc != EOK) {
126 return rc;
127 }
128
129 if (actual_size != length) {
130 free(hid_dev->report_desc);
131 hid_dev->report_desc = NULL;
132 usb_log_fatal("Report descriptor has wrong size (%u, expected "
133 "%u)\n", actual_size, length);
134 return EINVAL;
135 }
136
137 hid_dev->report_desc_size = length;
138
139 usb_log_debug("Done.\n");
140
141 return EOK;
142}
143
144/*----------------------------------------------------------------------------*/
145
146static int usbhid_dev_process_descriptors(usbhid_dev_t *hid_dev,
147 usb_endpoint_description_t *poll_ep_desc)
148{
149 assert(hid_dev != NULL);
150
151 usb_log_info("Processing descriptors...\n");
152
153 int rc;
154
155 uint8_t *descriptors = NULL;
156 size_t descriptors_size;
157 rc = usb_request_get_full_configuration_descriptor_alloc(
158 &hid_dev->ctrl_pipe, 0, (void **) &descriptors, &descriptors_size);
159 if (rc != EOK) {
160 usb_log_error("Failed to retrieve config descriptor: %s.\n",
161 str_error(rc));
162 return rc;
163 }
164
165 /*
166 * Initialize the interrupt in endpoint.
167 */
168 usb_endpoint_mapping_t endpoint_mapping[1] = {
169 {
170 .pipe = &hid_dev->poll_pipe,
171 .description = poll_ep_desc,
172 .interface_no =
173 usb_device_get_assigned_interface(hid_dev->device)
174 }
175 };
176
177 rc = usb_endpoint_pipe_initialize_from_configuration(
178 endpoint_mapping, 1, descriptors, descriptors_size,
179 &hid_dev->wire);
180
181 if (rc != EOK) {
182 usb_log_error("Failed to initialize poll pipe: %s.\n",
183 str_error(rc));
184 free(descriptors);
185 return rc;
186 }
187
188 if (!endpoint_mapping[0].present) {
189 usb_log_warning("Not accepting device.\n");
190 free(descriptors);
191 return EREFUSED; // probably not very good return value
192 }
193
194 usb_log_debug("Accepted device. Saving interface, and getting Report"
195 " descriptor.\n");
196
197 /*
198 * Save assigned interface number.
199 */
200 if (endpoint_mapping[0].interface_no < 0) {
201 usb_log_error("Bad interface number.\n");
202 free(descriptors);
203 return EINVAL;
204 }
205
206 hid_dev->iface = endpoint_mapping[0].interface_no;
207
208 assert(endpoint_mapping[0].interface != NULL);
209
210 /*
211 * Save polling interval
212 */
213 hid_dev->poll_interval = endpoint_mapping[0].descriptor->poll_interval;
214 assert(hid_dev->poll_interval > 0);
215
216 rc = usbhid_dev_get_report_descriptor(hid_dev,
217 descriptors, descriptors_size,
218 (uint8_t *)endpoint_mapping[0].interface);
219
220 free(descriptors);
221
222 if (rc != EOK) {
223 usb_log_warning("Problem with getting Report descriptor: %s.\n",
224 str_error(rc));
225 return rc;
226 }
227
228 rc = usb_hid_parse_report_descriptor(hid_dev->parser,
229 hid_dev->report_desc, hid_dev->report_desc_size);
230 if (rc != EOK) {
231 usb_log_warning("Problem parsing Report descriptor: %s.\n",
232 str_error(rc));
233 return rc;
234 }
235
236 usb_hid_descriptor_print(hid_dev->parser);
237
238 return EOK;
239}
240
241/*----------------------------------------------------------------------------*/
242/* API functions */
243/*----------------------------------------------------------------------------*/
244
245usbhid_dev_t *usbhid_dev_new(void)
246{
247 usbhid_dev_t *dev =
248 (usbhid_dev_t *)malloc(sizeof(usbhid_dev_t));
249
250 if (dev == NULL) {
251 usb_log_fatal("No memory!\n");
252 return NULL;
253 }
254
255 memset(dev, 0, sizeof(usbhid_dev_t));
256
257 dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
258 usb_hid_report_parser_t)));
259 if (dev->parser == NULL) {
260 usb_log_fatal("No memory!\n");
261 free(dev);
262 return NULL;
263 }
264
265 dev->initialized = 0;
266
267 return dev;
268}
269
270/*----------------------------------------------------------------------------*/
271
272void usbhid_dev_free(usbhid_dev_t **hid_dev)
273{
274 if (hid_dev == NULL || *hid_dev == NULL) {
275 return;
276 }
277
278 // free the report descriptor
279 if ((*hid_dev)->report_desc != NULL) {
280 free((*hid_dev)->report_desc);
281 }
282 // destroy the parser
283 if ((*hid_dev)->parser != NULL) {
284 usb_hid_free_report_parser((*hid_dev)->parser);
285 }
286
287 // TODO: cleanup pipes
288
289 free(*hid_dev);
290 *hid_dev = NULL;
291}
292
293/*----------------------------------------------------------------------------*/
294
295int usbhid_dev_init(usbhid_dev_t *hid_dev, ddf_dev_t *dev,
296 usb_endpoint_description_t *poll_ep_desc)
297{
298 usb_log_info("Initializing HID device structure.\n");
299
300 if (hid_dev == NULL) {
301 usb_log_error("Failed to init HID device structure: no "
302 "structure given.\n");
303 return EINVAL;
304 }
305
306 if (dev == NULL) {
307 usb_log_error("Failed to init HID device structure: no device"
308 " given.\n");
309 return EINVAL;
310 }
311
312 if (poll_ep_desc == NULL) {
313 usb_log_error("No poll endpoint description given.\n");
314 return EINVAL;
315 }
316
317 hid_dev->device = dev;
318
319 int rc;
320
321 /*
322 * Initialize the backing connection to the host controller.
323 */
324 rc = usb_device_connection_initialize_from_device(&hid_dev->wire, dev);
325 if (rc != EOK) {
326 usb_log_error("Problem initializing connection to device: %s."
327 "\n", str_error(rc));
328 return rc;
329 }
330
331 /*
332 * Initialize device pipes.
333 */
334 rc = usb_endpoint_pipe_initialize_default_control(&hid_dev->ctrl_pipe,
335 &hid_dev->wire);
336 if (rc != EOK) {
337 usb_log_error("Failed to initialize default control pipe: %s."
338 "\n", str_error(rc));
339 return rc;
340 }
341
342 /*
343 * Initialize the report parser.
344 */
345 rc = usb_hid_parser_init(hid_dev->parser);
346 if (rc != EOK) {
347 usb_log_error("Failed to initialize report parser.\n");
348 return rc;
349 }
350
351 /*
352 * Get descriptors, parse descriptors and save endpoints.
353 */
354 usb_endpoint_pipe_start_session(&hid_dev->ctrl_pipe);
355
356 rc = usbhid_dev_process_descriptors(hid_dev, poll_ep_desc);
357
358 usb_endpoint_pipe_end_session(&hid_dev->ctrl_pipe);
359 if (rc != EOK) {
360 usb_log_error("Failed to process descriptors: %s.\n",
361 str_error(rc));
362 return rc;
363 }
364
365 hid_dev->initialized = 1;
366 usb_log_info("HID device structure initialized.\n");
367
368 return EOK;
369}
370
371/**
372 * @}
373 */
Note: See TracBrowser for help on using the repository browser.