source: mainline/uspace/drv/usbhid/hiddev.c@ fbefd0e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fbefd0e was fbefd0e, checked in by Vojtech Horky <vojtechhorky@…>, 14 years ago

USB drivers less verbose on info level

  • Property mode set to 100644
File size: 12.9 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/**
56 * Retreives HID Report descriptor from the device.
57 *
58 * This function first parses the HID descriptor from the Interface descriptor
59 * to get the size of the Report descriptor and then requests the Report
60 * descriptor from the device.
61 *
62 * @param hid_dev HID device structure.
63 * @param config_desc Full configuration descriptor (including all nested
64 * descriptors).
65 * @param config_desc_size Size of the full configuration descriptor (in bytes).
66 * @param iface_desc Pointer to the interface descriptor inside the full
67 * configuration descriptor (@a config_desc) for the interface
68 * assigned with this device (@a hid_dev).
69 *
70 * @retval EOK if successful.
71 * @retval ENOENT if no HID descriptor could be found.
72 * @retval EINVAL if the HID descriptor or HID report descriptor have different
73 * size than expected.
74 * @retval ENOMEM if some allocation failed.
75 * @return Other value inherited from function usb_request_get_descriptor().
76 *
77 * @sa usb_request_get_descriptor()
78 */
79static int usbhid_dev_get_report_descriptor(usbhid_dev_t *hid_dev,
80 uint8_t *config_desc, size_t config_desc_size, uint8_t *iface_desc)
81{
82 assert(hid_dev != NULL);
83 assert(config_desc != NULL);
84 assert(config_desc_size != 0);
85 assert(iface_desc != NULL);
86
87 usb_dp_parser_t parser = {
88 .nesting = usb_dp_standard_descriptor_nesting
89 };
90
91 usb_dp_parser_data_t parser_data = {
92 .data = config_desc,
93 .size = config_desc_size,
94 .arg = NULL
95 };
96
97 /*
98 * First nested descriptor of interface descriptor.
99 */
100 uint8_t *d =
101 usb_dp_get_nested_descriptor(&parser, &parser_data, iface_desc);
102
103 /*
104 * Search through siblings until the HID descriptor is found.
105 */
106 while (d != NULL && *(d + 1) != USB_DESCTYPE_HID) {
107 d = usb_dp_get_sibling_descriptor(&parser, &parser_data,
108 iface_desc, d);
109 }
110
111 if (d == NULL) {
112 usb_log_fatal("No HID descriptor found!\n");
113 return ENOENT;
114 }
115
116 if (*d != sizeof(usb_standard_hid_descriptor_t)) {
117 usb_log_fatal("HID descriptor hass wrong size (%u, expected %u"
118 ")\n", *d, sizeof(usb_standard_hid_descriptor_t));
119 return EINVAL;
120 }
121
122 usb_standard_hid_descriptor_t *hid_desc =
123 (usb_standard_hid_descriptor_t *)d;
124
125 uint16_t length = hid_desc->report_desc_info.length;
126 size_t actual_size = 0;
127
128 /*
129 * Allocate space for the report descriptor.
130 */
131 hid_dev->report_desc = (uint8_t *)malloc(length);
132 if (hid_dev->report_desc == NULL) {
133 usb_log_fatal("Failed to allocate space for Report descriptor."
134 "\n");
135 return ENOMEM;
136 }
137
138 usb_log_debug("Getting Report descriptor, expected size: %u\n", length);
139
140 /*
141 * Get the descriptor from the device.
142 */
143 int rc = usb_request_get_descriptor(&hid_dev->ctrl_pipe,
144 USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE,
145 USB_DESCTYPE_HID_REPORT, 0,
146 hid_dev->iface, hid_dev->report_desc, length, &actual_size);
147
148 if (rc != EOK) {
149 return rc;
150 }
151
152 if (actual_size != length) {
153 free(hid_dev->report_desc);
154 hid_dev->report_desc = NULL;
155 usb_log_fatal("Report descriptor has wrong size (%u, expected "
156 "%u)\n", actual_size, length);
157 return EINVAL;
158 }
159
160 hid_dev->report_desc_size = length;
161
162 usb_log_debug("Done.\n");
163
164 return EOK;
165}
166
167/*----------------------------------------------------------------------------*/
168/**
169 * Retreives descriptors from the device, initializes pipes and stores
170 * important information from descriptors.
171 *
172 * Initializes the polling pipe described by the given endpoint description
173 * (@a poll_ep_desc).
174 *
175 * Information retreived from descriptors and stored in the HID device structure:
176 * - Assigned interface number (the interface controlled by this instance of
177 * the driver)
178 * - Polling interval (from the interface descriptor)
179 * - Report descriptor
180 *
181 * @param hid_dev HID device structure to be initialized.
182 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
183 * that has to be present in the device in order to
184 * successfuly initialize the structure.
185 *
186 * @sa usb_pipe_initialize_from_configuration(),
187 * usbhid_dev_get_report_descriptor()
188 */
189static int usbhid_dev_process_descriptors(usbhid_dev_t *hid_dev,
190 usb_endpoint_description_t *poll_ep_desc)
191{
192 assert(hid_dev != NULL);
193
194 usb_log_debug("Processing descriptors...\n");
195
196 int rc;
197
198 uint8_t *descriptors = NULL;
199 size_t descriptors_size;
200 rc = usb_request_get_full_configuration_descriptor_alloc(
201 &hid_dev->ctrl_pipe, 0, (void **) &descriptors, &descriptors_size);
202 if (rc != EOK) {
203 usb_log_error("Failed to retrieve config descriptor: %s.\n",
204 str_error(rc));
205 return rc;
206 }
207
208 /*
209 * Initialize the interrupt in endpoint.
210 */
211 usb_endpoint_mapping_t endpoint_mapping[1] = {
212 {
213 .pipe = &hid_dev->poll_pipe,
214 .description = poll_ep_desc,
215 .interface_no =
216 usb_device_get_assigned_interface(hid_dev->device)
217 }
218 };
219
220 rc = usb_pipe_initialize_from_configuration(
221 endpoint_mapping, 1, descriptors, descriptors_size,
222 &hid_dev->wire);
223
224 if (rc != EOK) {
225 usb_log_error("Failed to initialize poll pipe: %s.\n",
226 str_error(rc));
227 free(descriptors);
228 return rc;
229 }
230
231 if (!endpoint_mapping[0].present) {
232 usb_log_warning("Not accepting device.\n");
233 free(descriptors);
234 return EREFUSED; // probably not very good return value
235 }
236
237 usb_log_debug("Accepted device. Saving interface, and getting Report"
238 " descriptor.\n");
239
240 /*
241 * Save assigned interface number.
242 */
243 if (endpoint_mapping[0].interface_no < 0) {
244 usb_log_error("Bad interface number.\n");
245 free(descriptors);
246 return EINVAL;
247 }
248
249 hid_dev->iface = endpoint_mapping[0].interface_no;
250
251 assert(endpoint_mapping[0].interface != NULL);
252
253 /*
254 * Save polling interval
255 */
256 hid_dev->poll_interval = endpoint_mapping[0].descriptor->poll_interval;
257 assert(hid_dev->poll_interval > 0);
258
259 rc = usbhid_dev_get_report_descriptor(hid_dev,
260 descriptors, descriptors_size,
261 (uint8_t *)endpoint_mapping[0].interface);
262
263 free(descriptors);
264
265 if (rc != EOK) {
266 usb_log_warning("Problem with getting Report descriptor: %s.\n",
267 str_error(rc));
268 return rc;
269 }
270
271 rc = usb_hid_parse_report_descriptor(hid_dev->parser,
272 hid_dev->report_desc, hid_dev->report_desc_size);
273 if (rc != EOK) {
274 usb_log_warning("Problem parsing Report descriptor: %s.\n",
275 str_error(rc));
276 return rc;
277 }
278
279 usb_hid_descriptor_print(hid_dev->parser);
280
281 return EOK;
282}
283
284/*----------------------------------------------------------------------------*/
285/* API functions */
286/*----------------------------------------------------------------------------*/
287/**
288 * Creates new uninitialized HID device structure.
289 *
290 * @return Pointer to the new HID device structure, or NULL if an error occured.
291 */
292usbhid_dev_t *usbhid_dev_new(void)
293{
294 usbhid_dev_t *dev =
295 (usbhid_dev_t *)malloc(sizeof(usbhid_dev_t));
296
297 if (dev == NULL) {
298 usb_log_fatal("No memory!\n");
299 return NULL;
300 }
301
302 memset(dev, 0, sizeof(usbhid_dev_t));
303
304 dev->parser = (usb_hid_report_parser_t *)(malloc(sizeof(
305 usb_hid_report_parser_t)));
306 if (dev->parser == NULL) {
307 usb_log_fatal("No memory!\n");
308 free(dev);
309 return NULL;
310 }
311
312 dev->initialized = 0;
313
314 return dev;
315}
316
317/*----------------------------------------------------------------------------*/
318/**
319 * Properly destroys the HID device structure.
320 *
321 * @note Currently does not clean-up the used pipes, as there are no functions
322 * offering such functionality.
323 *
324 * @param hid_dev Pointer to the structure to be destroyed.
325 */
326void usbhid_dev_free(usbhid_dev_t **hid_dev)
327{
328 if (hid_dev == NULL || *hid_dev == NULL) {
329 return;
330 }
331
332 // free the report descriptor
333 if ((*hid_dev)->report_desc != NULL) {
334 free((*hid_dev)->report_desc);
335 }
336 // destroy the parser
337 if ((*hid_dev)->parser != NULL) {
338 usb_hid_free_report_parser((*hid_dev)->parser);
339 }
340
341 // TODO: cleanup pipes
342
343 free(*hid_dev);
344 *hid_dev = NULL;
345}
346
347/*----------------------------------------------------------------------------*/
348/**
349 * Initializes HID device structure.
350 *
351 * @param hid_dev HID device structure to be initialized.
352 * @param dev DDF device representing the HID device.
353 * @param poll_ep_desc Description of the polling (Interrupt In) endpoint
354 * that has to be present in the device in order to
355 * successfuly initialize the structure.
356 *
357 * @retval EOK if successful.
358 * @retval EINVAL if some argument is missing.
359 * @return Other value inherited from one of functions
360 * usb_device_connection_initialize_from_device(),
361 * usb_pipe_initialize_default_control(),
362 * usb_pipe_start_session(), usb_pipe_end_session(),
363 * usbhid_dev_process_descriptors().
364 *
365 * @sa usbhid_dev_process_descriptors()
366 */
367int usbhid_dev_init(usbhid_dev_t *hid_dev, ddf_dev_t *dev,
368 usb_endpoint_description_t *poll_ep_desc)
369{
370 usb_log_debug("Initializing HID device structure.\n");
371
372 if (hid_dev == NULL) {
373 usb_log_error("Failed to init HID device structure: no "
374 "structure given.\n");
375 return EINVAL;
376 }
377
378 if (dev == NULL) {
379 usb_log_error("Failed to init HID device structure: no device"
380 " given.\n");
381 return EINVAL;
382 }
383
384 if (poll_ep_desc == NULL) {
385 usb_log_error("No poll endpoint description given.\n");
386 return EINVAL;
387 }
388
389 hid_dev->device = dev;
390
391 int rc;
392
393 /*
394 * Initialize the backing connection to the host controller.
395 */
396 rc = usb_device_connection_initialize_from_device(&hid_dev->wire, dev);
397 if (rc != EOK) {
398 usb_log_error("Problem initializing connection to device: %s."
399 "\n", str_error(rc));
400 return rc;
401 }
402
403 /*
404 * Initialize device pipes.
405 */
406 rc = usb_pipe_initialize_default_control(&hid_dev->ctrl_pipe,
407 &hid_dev->wire);
408 if (rc != EOK) {
409 usb_log_error("Failed to initialize default control pipe: %s."
410 "\n", str_error(rc));
411 return rc;
412 }
413 rc = usb_pipe_probe_default_control(&hid_dev->ctrl_pipe);
414 if (rc != EOK) {
415 usb_log_error("Probing default control pipe failed: %s.\n",
416 str_error(rc));
417 return rc;
418 }
419
420 /*
421 * Initialize the report parser.
422 */
423 rc = usb_hid_parser_init(hid_dev->parser);
424 if (rc != EOK) {
425 usb_log_error("Failed to initialize report parser.\n");
426 return rc;
427 }
428
429 /*
430 * Get descriptors, parse descriptors and save endpoints.
431 */
432 rc = usb_pipe_start_session(&hid_dev->ctrl_pipe);
433 if (rc != EOK) {
434 usb_log_error("Failed to start session on the control pipe: %s"
435 ".\n", str_error(rc));
436 return rc;
437 }
438
439 rc = usbhid_dev_process_descriptors(hid_dev, poll_ep_desc);
440 if (rc != EOK) {
441 /* TODO: end session?? */
442 usb_pipe_end_session(&hid_dev->ctrl_pipe);
443 usb_log_error("Failed to process descriptors: %s.\n",
444 str_error(rc));
445 return rc;
446 }
447
448 rc = usb_pipe_end_session(&hid_dev->ctrl_pipe);
449 if (rc != EOK) {
450 usb_log_warning("Failed to start session on the control pipe: "
451 "%s.\n", str_error(rc));
452 return rc;
453 }
454
455 hid_dev->initialized = 1;
456 usb_log_debug("HID device structure initialized.\n");
457
458 return EOK;
459}
460
461/**
462 * @}
463 */
Note: See TracBrowser for help on using the repository browser.