source: mainline/uspace/lib/usb/src/dev.c@ 2745176

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2745176 was 2745176, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libusb: Hide/remove unused functions.

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * Copyright (c) 2011 Vojtech Horky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <usb/dev.h>
31#include <usb/hc.h>
32#include <errno.h>
33#include <usb_iface.h>
34#include <str.h>
35#include <stdio.h>
36
37#define MAX_DEVICE_PATH 1024
38
39/** Find host controller handle, address and iface number for the device.
40 *
41 * @param[in] device_handle Device devman handle.
42 * @param[out] hc_handle Where to store handle of host controller
43 * controlling device with @p device_handle handle.
44 * @param[out] address Place to store the device's address
45 * @param[out] iface Place to stoer the assigned USB interface number.
46 * @return Error code.
47 */
48static int usb_get_info_by_handle(devman_handle_t device_handle,
49 devman_handle_t *hc_handle, usb_address_t *address, int *iface)
50{
51 async_sess_t *parent_sess =
52 devman_parent_device_connect(EXCHANGE_ATOMIC, device_handle,
53 IPC_FLAG_BLOCKING);
54 if (!parent_sess)
55 return ENOMEM;
56
57 async_exch_t *exch = async_exchange_begin(parent_sess);
58 if (!exch) {
59 async_hangup(parent_sess);
60 return ENOMEM;
61 }
62
63 usb_address_t tmp_address;
64 devman_handle_t tmp_handle;
65 int tmp_iface;
66
67 if (address) {
68 const int ret = usb_get_my_address(exch, &tmp_address);
69 if (ret != EOK) {
70 async_exchange_end(exch);
71 async_hangup(parent_sess);
72 return ret;
73 }
74 }
75
76 if (hc_handle) {
77 const int ret = usb_get_hc_handle(exch, &tmp_handle);
78 if (ret != EOK) {
79 async_exchange_end(exch);
80 async_hangup(parent_sess);
81 return ret;
82 }
83 }
84
85 if (iface) {
86 const int ret = usb_get_my_interface(exch, &tmp_iface);
87 switch (ret) {
88 case ENOTSUP:
89 /* Implementing GET_MY_INTERFACE is voluntary. */
90 tmp_iface = -1;
91 case EOK:
92 break;
93 default:
94 async_exchange_end(exch);
95 async_hangup(parent_sess);
96 return ret;
97 }
98 }
99
100 if (hc_handle)
101 *hc_handle = tmp_handle;
102
103 if (address)
104 *address = tmp_address;
105
106 if (iface)
107 *iface = tmp_iface;
108
109 async_exchange_end(exch);
110 async_hangup(parent_sess);
111
112 return EOK;
113}
114
115static inline int usb_get_hc_by_handle(devman_handle_t dev, devman_handle_t *hc)
116{
117 return usb_get_info_by_handle(dev, hc, NULL, NULL);
118}
119
120static inline int usb_get_address_by_handle(
121 devman_handle_t dev, usb_address_t *address)
122{
123 return usb_get_info_by_handle(dev, NULL, address, NULL);
124}
125
126static bool try_parse_bus_and_address(const char *path,
127 char **func_start,
128 devman_handle_t *out_hc_handle, usb_address_t *out_device_address)
129{
130 uint64_t sid;
131 size_t address;
132 int rc;
133 char *ptr;
134
135 rc = str_uint64_t(path, &ptr, 10, false, &sid);
136 if (rc != EOK) {
137 return false;
138 }
139 if ((*ptr == ':') || (*ptr == '.')) {
140 ptr++;
141 } else {
142 return false;
143 }
144 rc = str_size_t(ptr, func_start, 10, false, &address);
145 if (rc != EOK) {
146 return false;
147 }
148 rc = usb_ddf_get_hc_handle_by_sid(sid, out_hc_handle);
149 if (rc != EOK) {
150 return false;
151 }
152 if (out_device_address != NULL) {
153 *out_device_address = (usb_address_t) address;
154 }
155 return true;
156}
157
158static int get_device_handle_by_address(devman_handle_t hc_handle, int addr,
159 devman_handle_t *dev_handle)
160{
161 usb_hc_connection_t conn;
162 usb_hc_connection_initialize(&conn, hc_handle);
163
164 const int rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
165
166 return rc;
167}
168
169/** Resolve handle and address of USB device from its path.
170 *
171 * This is a wrapper working on best effort principle.
172 * If the resolving fails, if will not give much details about what
173 * is wrong.
174 * Typically, error from this function would be reported to the user
175 * as "bad device specification" or "device does not exist".
176 *
177 * The path can be specified in following format:
178 * - devman path (e.g. /hw/pci0/.../usb01_a5
179 * - bus number and device address (e.g. 5.1)
180 * - bus number, device address and device function (e.g. 2.1/HID0/keyboard)
181 *
182 * @param[in] dev_path Path to the device.
183 * @param[out] out_hc_handle Where to store handle of a parent host controller.
184 * @param[out] out_dev_addr Where to store device (USB) address.
185 * @param[out] out_dev_handle Where to store device handle.
186 * @return Error code.
187 */
188int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
189 usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
190{
191 if (dev_path == NULL) {
192 return EBADMEM;
193 }
194
195 bool found_hc = false;
196 bool found_addr = false;
197 devman_handle_t hc_handle, dev_handle;
198 usb_address_t dev_addr = -1;
199 int rc;
200 bool is_bus_addr;
201 char *func_start = NULL;
202 char *path = NULL;
203
204 /* First try the BUS.ADDR format. */
205 is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
206 &hc_handle, &dev_addr);
207 if (is_bus_addr) {
208 found_hc = true;
209 found_addr = true;
210 /*
211 * Now get the handle of the device. We will need that
212 * in both cases. If there is only BUS.ADDR, it will
213 * be the handle to be returned to the caller, otherwise
214 * we will need it to resolve the path to which the
215 * suffix would be appended.
216 */
217 /* If there is nothing behind the BUS.ADDR, we will
218 * get the device handle from the host controller.
219 * Otherwise, we will
220 */
221 rc = get_device_handle_by_address(hc_handle, dev_addr,
222 &dev_handle);
223 if (rc != EOK) {
224 return rc;
225 }
226 if (str_length(func_start) > 0) {
227 char tmp_path[MAX_DEVICE_PATH];
228 rc = devman_fun_get_path(dev_handle,
229 tmp_path, MAX_DEVICE_PATH);
230 if (rc != EOK) {
231 return rc;
232 }
233 rc = asprintf(&path, "%s%s", tmp_path, func_start);
234 if (rc < 0) {
235 return ENOMEM;
236 }
237 } else {
238 /* Everything is resolved. Get out of here. */
239 goto copy_out;
240 }
241 } else {
242 path = str_dup(dev_path);
243 if (path == NULL) {
244 return ENOMEM;
245 }
246 }
247
248 /* First try to get the device handle. */
249 rc = devman_fun_get_handle(path, &dev_handle, 0);
250 if (rc != EOK) {
251 free(path);
252 /* Invalid path altogether. */
253 return rc;
254 }
255
256 /* Remove suffixes and hope that we will encounter device node. */
257 while (str_length(path) > 0) {
258 /* Get device handle first. */
259 devman_handle_t tmp_handle;
260 rc = devman_fun_get_handle(path, &tmp_handle, 0);
261 if (rc != EOK) {
262 free(path);
263 return rc;
264 }
265
266 /* Try to find its host controller. */
267 if (!found_hc) {
268 rc = usb_get_hc_by_handle(tmp_handle, &hc_handle);
269 if (rc == EOK) {
270 found_hc = true;
271 }
272 }
273
274 /* Try to get its address. */
275 if (!found_addr) {
276 rc = usb_get_address_by_handle(tmp_handle, &dev_addr);
277 if (rc == 0) {
278 found_addr = true;
279 }
280 }
281
282 /* Speed-up. */
283 if (found_hc && found_addr) {
284 break;
285 }
286
287 /* Remove the last suffix. */
288 char *slash_pos = str_rchr(path, '/');
289 if (slash_pos != NULL) {
290 *slash_pos = 0;
291 }
292 }
293
294 free(path);
295
296 if (!found_addr || !found_hc) {
297 return ENOENT;
298 }
299
300copy_out:
301 if (out_dev_addr != NULL) {
302 *out_dev_addr = dev_addr;
303 }
304 if (out_hc_handle != NULL) {
305 *out_hc_handle = hc_handle;
306 }
307 if (out_dev_handle != NULL) {
308 *out_dev_handle = dev_handle;
309 }
310
311 return EOK;
312}
Note: See TracBrowser for help on using the repository browser.