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

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

Merged headers in libusb

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