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

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

libusb: Add device_connection_t.

  • Property mode set to 100644
File size: 6.1 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/dev.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 uint64_t sid;
50 size_t address;
51 int rc;
52 char *ptr;
53
54 rc = str_uint64(path, &ptr, 10, false, &sid);
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_sid(sid, 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 usb_hc_connection_t conn;
81 usb_hc_connection_initialize(&conn, hc_handle);
82
83 const int rc = usb_hc_get_handle_by_address(&conn, addr, dev_handle);
84
85 return rc;
86}
87
88/** Resolve handle and address of USB device from its path.
89 *
90 * This is a wrapper working on best effort principle.
91 * If the resolving fails, if will not give much details about what
92 * is wrong.
93 * Typically, error from this function would be reported to the user
94 * as "bad device specification" or "device does not exist".
95 *
96 * The path can be specified in following format:
97 * - devman path (e.g. /hw/pci0/.../usb01_a5
98 * - bus number and device address (e.g. 5.1)
99 * - bus number, device address and device function (e.g. 2.1/HID0/keyboard)
100 *
101 * @param[in] dev_path Path to the device.
102 * @param[out] out_hc_handle Where to store handle of a parent host controller.
103 * @param[out] out_dev_addr Where to store device (USB) address.
104 * @param[out] out_dev_handle Where to store device handle.
105 * @return Error code.
106 */
107int usb_resolve_device_handle(const char *dev_path, devman_handle_t *out_hc_handle,
108 usb_address_t *out_dev_addr, devman_handle_t *out_dev_handle)
109{
110 if (dev_path == NULL) {
111 return EBADMEM;
112 }
113
114 bool found_hc = false;
115 bool found_addr = false;
116 devman_handle_t hc_handle, dev_handle;
117 usb_address_t dev_addr = -1;
118 int rc;
119 bool is_bus_addr;
120 char *func_start = NULL;
121 char *path = NULL;
122
123 /* First try the BUS.ADDR format. */
124 is_bus_addr = try_parse_bus_and_address(dev_path, &func_start,
125 &hc_handle, &dev_addr);
126 if (is_bus_addr) {
127 found_hc = true;
128 found_addr = true;
129 /*
130 * Now get the handle of the device. We will need that
131 * in both cases. If there is only BUS.ADDR, it will
132 * be the handle to be returned to the caller, otherwise
133 * we will need it to resolve the path to which the
134 * suffix would be appended.
135 */
136 /* If there is nothing behind the BUS.ADDR, we will
137 * get the device handle from the host controller.
138 * Otherwise, we will
139 */
140 rc = get_device_handle_by_address(hc_handle, dev_addr,
141 &dev_handle);
142 if (rc != EOK) {
143 return rc;
144 }
145 if (str_length(func_start) > 0) {
146 char tmp_path[MAX_DEVICE_PATH ];
147 rc = devman_fun_get_path(dev_handle,
148 tmp_path, MAX_DEVICE_PATH);
149 if (rc != EOK) {
150 return rc;
151 }
152 rc = asprintf(&path, "%s%s", tmp_path, func_start);
153 if (rc < 0) {
154 return ENOMEM;
155 }
156 } else {
157 /* Everything is resolved. Get out of here. */
158 goto copy_out;
159 }
160 } else {
161 path = str_dup(dev_path);
162 if (path == NULL) {
163 return ENOMEM;
164 }
165 }
166
167 /* First try to get the device handle. */
168 rc = devman_fun_get_handle(path, &dev_handle, 0);
169 if (rc != EOK) {
170 free(path);
171 /* Invalid path altogether. */
172 return rc;
173 }
174
175 /* Remove suffixes and hope that we will encounter device node. */
176 while (str_length(path) > 0) {
177 /* Get device handle first. */
178 devman_handle_t tmp_handle;
179 rc = devman_fun_get_handle(path, &tmp_handle, 0);
180 if (rc != EOK) {
181 free(path);
182 return rc;
183 }
184
185 /* Try to find its host controller. */
186 if (!found_hc) {
187 rc = usb_get_hc_by_handle(tmp_handle, &hc_handle);
188 if (rc == EOK) {
189 found_hc = true;
190 }
191 }
192
193 /* Try to get its address. */
194 if (!found_addr) {
195 dev_addr = usb_get_address_by_handle(tmp_handle);
196 if (dev_addr >= 0) {
197 found_addr = true;
198 }
199 }
200
201 /* Speed-up. */
202 if (found_hc && found_addr) {
203 break;
204 }
205
206 /* Remove the last suffix. */
207 char *slash_pos = str_rchr(path, '/');
208 if (slash_pos != NULL) {
209 *slash_pos = 0;
210 }
211 }
212
213 free(path);
214
215 if (!found_addr || !found_hc) {
216 return ENOENT;
217 }
218
219copy_out:
220 if (out_dev_addr != NULL) {
221 *out_dev_addr = dev_addr;
222 }
223 if (out_hc_handle != NULL) {
224 *out_hc_handle = hc_handle;
225 }
226 if (out_dev_handle != NULL) {
227 *out_dev_handle = dev_handle;
228 }
229
230 return EOK;
231}
232
233
234/**
235 * @}
236 */
237
Note: See TracBrowser for help on using the repository browser.