source: mainline/uspace/lib/usb/src/resolve.c@ a9ab7f47

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

Add function for resolving USB paths

The great function is called usb_resolve_device_handle() and
accepts full HW path as well as BUS.ADDR specification including
super bombastic hack USB.ADDR/path/to/function.

  • 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 libusb
30 * @{
31 */
32/** @file
33 *
34 */
35#include <inttypes.h>
36#include <usb/driver.h>
37#include <usb/hc.h>
38#include <devman.h>
39#include <errno.h>
40#include <str.h>
41#include <stdio.h>
42
43#define MAX_DEVICE_PATH 1024
44
45static bool try_parse_bus_and_address(const char *path,
46 char **func_start,
47 devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
48{
49 size_t class_index;
50 size_t address;
51 int rc;
52 char *ptr;
53
54 rc = str_size_t(path, &ptr, 10, false, &class_index);
55 if (rc != EOK) {
56 return false;
57 }
58 if ((*ptr == ':') || (*ptr == '.')) {
59 ptr++;
60 } else {
61 return false;
62 }
63 rc = str_size_t(ptr, func_start, 10, false, &address);
64 if (rc != EOK) {
65 return false;
66 }
67 rc = usb_ddf_get_hc_handle_by_class(class_index, out_hc_handle);
68 if (rc != EOK) {
69 return false;
70 }
71 if (out_device_address != NULL) {
72 *out_device_address = (usb_address_t) address;
73 }
74 return true;
75}
76
77static int get_device_handle_by_address(devman_handle_t hc_handle, int addr,
78 devman_handle_t *dev_handle)
79{
80 int rc;
81 usb_hc_connection_t conn;
82
83 usb_hc_connection_initialize(&conn, hc_handle);
84 rc = usb_hc_connection_open(&conn);
85 if (rc != EOK) {
86 return rc;
87 }
88
89 rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
90
91 usb_hc_connection_close(&conn);
92
93 return rc;
94}
95
96/** Resolve handle and address of USB device from its path.
97 *
98 * This is a wrapper working on best effort principle.
99 * If the resolving fails, if will not give much details about what
100 * is wrong.
101 * Typically, error from this function would be reported to the user
102 * as "bad device specification" or "device does not exist".
103 *
104 * The path can be specified in following format:
105 * - devman path (e.g. /hw/pci0/.../usb01_a5
106 * - bus number and device address (e.g. 5.1)
107 * - bus number, device address and device function (e.g. 2.1/HID0/keyboard)
108 *
109 * @param[in] dev_path Path to the device.
110 * @param[out] out_hc_handle Where to store handle of a parent host controller.
111 * @param[out] out_dev_addr Where to store device (USB) address.
112 * @param[out] out_dev_handle Where to store device handle.
113 * @return Error code.
114 */
115int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
116 usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
117{
118 if (dev_path == NULL) {
119 return EBADMEM;
120 }
121
122 bool found_hc = false;
123 bool found_addr = false;
124 devman_handle_t hc_handle, dev_handle;
125 usb_address_t dev_addr = -1;
126 int rc;
127 bool is_bus_addr;
128 char *func_start = NULL;
129 char *path = NULL;
130
131 /* First try the BUS.ADDR format. */
132 is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
133 &hc_handle, &dev_addr);
134 if (is_bus_addr) {
135 found_hc = true;
136 found_addr = true;
137 /*
138 * Now get the handle of the device. We will need that
139 * in both cases. If there is only BUS.ADDR, it will
140 * be the handle to be returned to the caller, otherwise
141 * we will need it to resolve the path to which the
142 * suffix would be appended.
143 */
144 /* If there is nothing behind the BUS.ADDR, we will
145 * get the device handle from the host controller.
146 * Otherwise, we will
147 */
148 rc = get_device_handle_by_address(hc_handle, dev_addr,
149 &dev_handle);
150 if (rc != EOK) {
151 return rc;
152 }
153 if (str_length(func_start) > 0) {
154 char tmp_path[MAX_DEVICE_PATH ];
155 rc = devman_get_device_path(dev_handle,
156 tmp_path, MAX_DEVICE_PATH);
157 if (rc != EOK) {
158 return rc;
159 }
160 rc = asprintf(&path, "%s%s", tmp_path, func_start);
161 if (rc < 0) {
162 return ENOMEM;
163 }
164 } else {
165 /* Everything is resolved. Get out of here. */
166 goto copy_out;
167 }
168 } else {
169 path = str_dup(dev_path);
170 if (path == NULL) {
171 return ENOMEM;
172 }
173 }
174
175 /* First try to get the device handle. */
176 rc = devman_device_get_handle(path, &dev_handle, 0);
177 if (rc != EOK) {
178 free(path);
179 /* Invalid path altogether. */
180 return rc;
181 }
182
183 /* Remove suffixes and hope that we will encounter device node. */
184 while (str_length(path) > 0) {
185 /* Get device handle first. */
186 devman_handle_t tmp_handle;
187 rc = devman_device_get_handle(path, &tmp_handle, 0);
188 if (rc != EOK) {
189 free(path);
190 return rc;
191 }
192
193 /* Try to find its host controller. */
194 if (!found_hc) {
195 rc = usb_hc_find(tmp_handle, &hc_handle);
196 if (rc == EOK) {
197 found_hc = true;
198 }
199 }
200
201 /* Try to get its address. */
202 if (!found_addr) {
203 dev_addr = usb_hc_get_address_by_handle(tmp_handle);
204 if (dev_addr >= 0) {
205 found_addr = true;
206 }
207 }
208
209 /* Speed-up. */
210 if (found_hc && found_addr) {
211 break;
212 }
213
214 /* Remove the last suffix. */
215 char *slash_pos = str_rchr(path, '/');
216 if (slash_pos != NULL) {
217 *slash_pos = 0;
218 }
219 }
220
221 free(path);
222
223 if (!found_addr || !found_hc) {
224 return ENOENT;
225 }
226
227copy_out:
228 if (out_dev_addr != NULL) {
229 *out_dev_addr = dev_addr;
230 }
231 if (out_hc_handle != NULL) {
232 *out_hc_handle = hc_handle;
233 }
234 if (out_dev_handle != NULL) {
235 *out_dev_handle = dev_handle;
236 }
237
238 return EOK;
239}
240
241
242/**
243 * @}
244 */
245
Note: See TracBrowser for help on using the repository browser.