source: mainline/uspace/drv/usbmid/explore.c@ 5857be2

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

USB MID uses the new framework

  • Property mode set to 100644
File size: 6.3 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 <usb/ddfiface.h>
43#include "usbmid.h"
44
45/** Operations of the device itself. */
46static ddf_dev_ops_t mid_device_ops = {
47 .interfaces[USB_DEV_IFACE] = &usb_iface_hub_impl
48};
49
50/** Find starting indexes of all interface descriptors in a configuration.
51 *
52 * @param config_descriptor Full configuration descriptor.
53 * @param config_descriptor_size Size of @p config_descriptor in bytes.
54 * @param interface_positions Array where to store indexes of interfaces.
55 * @param interface_count Size of @p interface_positions array.
56 * @return Number of found interfaces.
57 * @retval (size_t)-1 Error occured.
58 */
59static size_t find_interface_descriptors(uint8_t *config_descriptor,
60 size_t config_descriptor_size,
61 size_t *interface_positions, size_t interface_count)
62{
63 if (interface_count == 0) {
64 return (size_t) -1;
65 }
66
67 usb_dp_parser_data_t data = {
68 .data = config_descriptor,
69 .size = config_descriptor_size,
70 .arg = NULL
71 };
72
73 usb_dp_parser_t parser = {
74 .nesting = usb_dp_standard_descriptor_nesting
75 };
76
77 uint8_t *interface = usb_dp_get_nested_descriptor(&parser, &data,
78 data.data);
79 if (interface == NULL) {
80 return (size_t) -1;
81 }
82 if (interface[1] != USB_DESCTYPE_INTERFACE) {
83 return (size_t) -1;
84 }
85
86 size_t found_interfaces = 0;
87 interface_positions[found_interfaces] = interface - config_descriptor;
88 found_interfaces++;
89
90 while (interface != NULL) {
91 interface = usb_dp_get_sibling_descriptor(&parser, &data,
92 data.data, interface);
93 if ((interface != NULL)
94 && (found_interfaces < interface_count)
95 && (interface[1] == USB_DESCTYPE_INTERFACE)) {
96 interface_positions[found_interfaces]
97 = interface - config_descriptor;
98 found_interfaces++;
99 }
100 }
101
102 return found_interfaces;
103}
104
105/** Explore MID device.
106 *
107 * We expect that @p dev is initialized and session on control pipe is
108 * started.
109 *
110 * @param dev Device to be explored.
111 * @return Whether to accept this device from devman.
112 */
113bool usbmid_explore_device(usb_device_t *dev)
114{
115 int rc;
116
117 int dev_class = dev->descriptors.device.device_class;
118 if (dev_class != USB_CLASS_USE_INTERFACE) {
119 usb_log_warning(
120 "Device class: %d (%s), but expected class 0.\n",
121 dev_class, usb_str_class(dev_class));
122 usb_log_error("Not multi interface device, refusing.\n");
123 return false;
124 }
125
126 /* Short cuts to save on typing ;-). */
127 uint8_t *config_descriptor_raw = dev->descriptors.configuration;
128 size_t config_descriptor_size = dev->descriptors.configuration_size;
129 usb_standard_configuration_descriptor_t *config_descriptor =
130 (usb_standard_configuration_descriptor_t *) config_descriptor_raw;
131
132 size_t *interface_descriptors
133 = malloc(sizeof(size_t) * config_descriptor->interface_count);
134 if (interface_descriptors == NULL) {
135 usb_log_error("Out of memory (wanted %zuB).\n",
136 sizeof(size_t) * config_descriptor->interface_count);
137 free(config_descriptor_raw);
138 return false;
139 }
140 size_t interface_descriptors_count
141 = find_interface_descriptors(
142 config_descriptor_raw, config_descriptor_size,
143 interface_descriptors, config_descriptor->interface_count);
144
145 if (interface_descriptors_count == (size_t) -1) {
146 usb_log_error("Problem parsing configuration descriptor.\n");
147 free(interface_descriptors);
148 return false;
149 }
150
151 /* Select the first configuration */
152 rc = usb_request_set_configuration(&dev->ctrl_pipe,
153 config_descriptor->configuration_number);
154 if (rc != EOK) {
155 usb_log_error("Failed to set device configuration: %s.\n",
156 str_error(rc));
157 free(interface_descriptors);
158 return false;
159 }
160
161
162 /* Create control function */
163 ddf_fun_t *ctl_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, "ctl");
164 if (ctl_fun == NULL) {
165 usb_log_error("Failed to create control function.\n");
166 free(interface_descriptors);
167 return false;
168 }
169
170 ctl_fun->ops = &mid_device_ops;
171
172 rc = ddf_fun_bind(ctl_fun);
173 if (rc != EOK) {
174 usb_log_error("Failed to bind control function: %s.\n",
175 str_error(rc));
176 free(interface_descriptors);
177 return false;
178 }
179
180 /* Spawn interface children */
181 size_t i;
182 for (i = 0; i < interface_descriptors_count; i++) {
183 usb_standard_interface_descriptor_t *interface
184 = (usb_standard_interface_descriptor_t *)
185 (config_descriptor_raw + interface_descriptors[i]);
186 usb_log_debug2("Interface descriptor at index %zu (type %d).\n",
187 interface_descriptors[i], (int) interface->descriptor_type);
188 usb_log_info("Creating child for interface %d (%s).\n",
189 (int) interface->interface_number,
190 usb_str_class(interface->interface_class));
191 rc = usbmid_spawn_interface_child(dev, &dev->descriptors.device,
192 interface);
193 if (rc != EOK) {
194 usb_log_error("Failed to create interface child: %s.\n",
195 str_error(rc));
196 }
197 }
198
199 return true;
200}
201
202/**
203 * @}
204 */
Note: See TracBrowser for help on using the repository browser.