source: mainline/uspace/drv/usbmid/explore.c@ 8ba18c6

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

Add USB multi interface device driver

Incomplete implementation of a pseudo-bus driver that spawns children
devices for each interface in multi interface device.

WARNING: does not work as the child device does not learn its USB address.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky
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 drvusbmid
30 * @{
31 */
32/**
33 * @file
34 * Exploration of available interfaces in the USB device.
35 */
36#include <errno.h>
37#include <str_error.h>
38#include <stdlib.h>
39#include <usb/classes/classes.h>
40#include <usb/request.h>
41#include <usb/dp.h>
42#include "usbmid.h"
43
44/** Allocate and retrieve full configuration descriptor.
45 *
46 * @param[in] dev USB device.
47 * @param[in] config_index Configuration index.
48 * @param[out] size Pointer where to store size of the allocated buffer.
49 * @return Allocated full configuration descriptor.
50 * @retval NULL Error occured.
51 */
52static void *get_configuration_descriptor(usbmid_device_t *dev,
53 size_t config_index, size_t *size)
54{
55 usb_standard_configuration_descriptor_t config_descriptor;
56 int rc = usb_request_get_bare_configuration_descriptor(&dev->ctrl_pipe,
57 config_index, &config_descriptor);
58 if (rc != EOK) {
59 usb_log_error("Failed getting configuration descriptor: %s.\n",
60 str_error(rc));
61 return NULL;
62 }
63
64 void *full_config_descriptor = malloc(config_descriptor.total_length);
65 if (full_config_descriptor == NULL) {
66 usb_log_fatal("Out of memory (wanted: %zuB).\n",
67 (size_t) config_descriptor.total_length);
68 return NULL;
69 }
70
71 size_t full_config_descriptor_size;
72 rc = usb_request_get_full_configuration_descriptor(&dev->ctrl_pipe,
73 config_index,
74 full_config_descriptor, config_descriptor.total_length,
75 &full_config_descriptor_size);
76 if (rc != EOK) {
77 usb_log_error("Failed getting configuration descriptor: %s.\n",
78 str_error(rc));
79 free(full_config_descriptor);
80 return NULL;
81 }
82
83 if (full_config_descriptor_size != config_descriptor.total_length) {
84 usb_log_error("Failed getting full configuration descriptor.\n");
85 free(full_config_descriptor);
86 return NULL;
87 }
88
89 if (size != NULL) {
90 *size = full_config_descriptor_size;
91 }
92
93 return full_config_descriptor;
94}
95
96/** Find starting indexes of all interface descriptors in a configuration.
97 *
98 * @param config_descriptor Full configuration descriptor.
99 * @param config_descriptor_size Size of @p config_descriptor in bytes.
100 * @param interface_positions Array where to store indexes of interfaces.
101 * @param interface_count Size of @p interface_positions array.
102 * @return Number of found interfaces.
103 * @retval (size_t)-1 Error occured.
104 */
105static size_t find_interface_descriptors(uint8_t *config_descriptor,
106 size_t config_descriptor_size,
107 size_t *interface_positions, size_t interface_count)
108{
109 if (interface_count == 0) {
110 return (size_t) -1;
111 }
112
113 usb_dp_parser_data_t data = {
114 .data = config_descriptor,
115 .size = config_descriptor_size,
116 .arg = NULL
117 };
118
119 usb_dp_parser_t parser = {
120 .nesting = usb_dp_standard_descriptor_nesting
121 };
122
123 uint8_t *interface = usb_dp_get_nested_descriptor(&parser, &data,
124 data.data);
125 if (interface == NULL) {
126 return (size_t) -1;
127 }
128 if (interface[1] != USB_DESCTYPE_INTERFACE) {
129 return (size_t) -1;
130 }
131
132 size_t found_interfaces = 0;
133 interface_positions[found_interfaces] = interface - config_descriptor;
134 found_interfaces++;
135
136 while (interface != NULL) {
137 interface = usb_dp_get_sibling_descriptor(&parser, &data,
138 data.data, interface);
139 if ((interface != NULL)
140 && (found_interfaces < interface_count)
141 && (interface[1] == USB_DESCTYPE_INTERFACE)) {
142 interface_positions[found_interfaces]
143 = interface - config_descriptor;
144 found_interfaces++;
145 }
146 }
147
148 return found_interfaces;
149}
150
151/** Explore MID device.
152 *
153 * We expect that @p dev is initialized and session on control pipe is
154 * started.
155 *
156 * @param dev Device to be explored.
157 * @return Whether to accept this device from devman.
158 */
159bool usbmid_explore_device(usbmid_device_t *dev)
160{
161 usb_standard_device_descriptor_t device_descriptor;
162 int rc = usb_request_get_device_descriptor(&dev->ctrl_pipe,
163 &device_descriptor);
164 if (rc != EOK) {
165 usb_log_error("Getting device descriptor failed: %s.\n",
166 str_error(rc));
167 return false;
168 }
169
170 if (device_descriptor.device_class != USB_CLASS_USE_INTERFACE) {
171 usb_log_warning(
172 "Device class: %d (%s), but expected class 0.\n",
173 device_descriptor.device_class,
174 usb_str_class(device_descriptor.device_class));
175 usb_log_error("Not multi interface device, refusing.\n");
176 return false;
177 }
178
179 size_t config_descriptor_size;
180 uint8_t *config_descriptor_raw = get_configuration_descriptor(dev, 0,
181 &config_descriptor_size);
182 if (config_descriptor_raw == NULL) {
183 return false;
184 }
185
186 usb_standard_configuration_descriptor_t *config_descriptor
187 = (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
188
189 size_t *interface_descriptors
190 = malloc(sizeof(size_t) * config_descriptor->interface_count);
191 if (interface_descriptors == NULL) {
192 usb_log_error("Out of memory (wanted %zuB).\n",
193 sizeof(size_t) * config_descriptor->interface_count);
194 free(config_descriptor_raw);
195 return false;
196 }
197 size_t interface_descriptors_count
198 = find_interface_descriptors(
199 config_descriptor_raw, config_descriptor_size,
200 interface_descriptors, config_descriptor->interface_count);
201
202 if (interface_descriptors_count == (size_t) -1) {
203 usb_log_error("Problem parsing configuration descriptor.\n");
204 free(config_descriptor_raw);
205 free(interface_descriptors);
206 return false;
207 }
208
209 usbmid_dump_descriptors(config_descriptor_raw, config_descriptor_size);
210
211 size_t i;
212 for (i = 0; i < interface_descriptors_count; i++) {
213 usb_standard_interface_descriptor_t *interface
214 = (usb_standard_interface_descriptor_t *)
215 (config_descriptor_raw + interface_descriptors[i]);
216 usb_log_debug("Interface descriptor at index %zu (type %d).\n",
217 interface_descriptors[i], (int) interface->descriptor_type);
218 usb_log_info("Creating child for interface %d (%s).\n",
219 (int) interface->interface_number,
220 usb_str_class(interface->interface_class));
221 rc = usbmid_spawn_interface_child(dev, &device_descriptor,
222 interface);
223 if (rc != EOK) {
224 usb_log_error("Failed to create interface child: %s.\n",
225 str_error(rc));
226 }
227 }
228
229 free(config_descriptor_raw);
230
231 return true;
232}
233
234/**
235 * @}
236 */
Note: See TracBrowser for help on using the repository browser.