source: mainline/uspace/lib/usbhost/src/ddf_helpers.c@ d8cdf39e

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

libusbhost: Drop hcd parameter from hcd_ddf_setup_hub.

Fix OHCI references in ddf_helpers.c

  • Property mode set to 100644
File size: 7.9 KB
Line 
1/*
2 * Copyright (c) 2012 Jan Vesely
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 libusbhost
30 * @{
31 */
32/** @file
33 *
34 */
35
36#include <usb_iface.h>
37#include <usb/debug.h>
38#include <errno.h>
39#include <str_error.h>
40
41#include "ddf_helpers.h"
42
43extern usbhc_iface_t hcd_iface;
44
45typedef struct hc_dev {
46 ddf_fun_t *hc_fun;
47 list_t devices;
48} hc_dev_t;
49
50static hc_dev_t *dev_to_hc_dev(ddf_dev_t *dev)
51{
52 return ddf_dev_data_get(dev);
53}
54
55hcd_t *dev_to_hcd(ddf_dev_t *dev)
56{
57 hc_dev_t *hc_dev = dev_to_hc_dev(dev);
58 if (!hc_dev || !hc_dev->hc_fun) {
59 usb_log_error("Invalid HCD device.\n");
60 return NULL;
61 }
62 return ddf_fun_data_get(hc_dev->hc_fun);
63}
64
65typedef struct usb_dev {
66 link_t link;
67 ddf_fun_t *fun;
68 usb_address_t address;
69 usb_speed_t speed;
70 devman_handle_t handle;
71} usb_dev_t;
72
73/** Get USB address assigned to root hub.
74 *
75 * @param[in] fun Root hub function.
76 * @param[out] address Store the address here.
77 * @return Error code.
78 */
79static int rh_get_my_address(ddf_fun_t *fun, usb_address_t *address)
80{
81 assert(fun);
82 if (address != NULL) {
83 usb_dev_t *usb_dev = ddf_fun_data_get(fun);
84 *address = usb_dev->address;
85 }
86 return EOK;
87}
88
89/** Gets handle of the respective hc (this device, hc function).
90 *
91 * @param[in] root_hub_fun Root hub function seeking hc handle.
92 * @param[out] handle Place to write the handle.
93 * @return Error code.
94 */
95static int rh_get_hc_handle(ddf_fun_t *fun, devman_handle_t *handle)
96{
97 assert(fun);
98
99 if (handle != NULL) {
100 usb_dev_t *usb_dev = ddf_fun_data_get(fun);
101 *handle = usb_dev->handle;
102 }
103 return EOK;
104}
105
106/** Root hub USB interface */
107static usb_iface_t usb_iface = {
108 .get_hc_handle = rh_get_hc_handle,
109 .get_my_address = rh_get_my_address,
110};
111/** Standard USB RH options (RH interface) */
112static ddf_dev_ops_t usb_ops = {
113 .interfaces[USB_DEV_IFACE] = &usb_iface,
114};
115
116/** Standard USB HC options (HC interface) */
117static ddf_dev_ops_t hc_ops = {
118 .interfaces[USBHC_DEV_IFACE] = &hcd_iface,
119};
120
121int hcd_ddf_add_usb_device(ddf_dev_t *parent,
122 usb_address_t address, usb_speed_t speed, const char *name,
123 const match_id_list_t *mids)
124{
125 assert(parent);
126 hc_dev_t *hc_dev = dev_to_hc_dev(parent);
127 devman_handle_t hc_handle = ddf_fun_get_handle(hc_dev->hc_fun);
128
129 char default_name[8]; /* usbxyzs */
130 if (!name) {
131 snprintf(default_name, sizeof(default_name) - 1,
132 "usb%u%c", address, usb_str_speed(speed)[0]);
133 name = default_name;
134 }
135
136 //TODO more checks
137 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);
138 if (!fun)
139 return ENOMEM;
140 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
141 if (!info) {
142 ddf_fun_destroy(fun);
143 return ENOMEM;
144 }
145 info->address = address;
146 info->speed = speed;
147 info->handle = hc_handle;
148 info->fun = fun;
149 link_initialize(&info->link);
150
151 ddf_fun_set_ops(fun, &usb_ops);
152 list_foreach(mids->ids, iter) {
153 match_id_t *mid = list_get_instance(iter, match_id_t, link);
154 ddf_fun_add_match_id(fun, mid->id, mid->score);
155 }
156
157 int ret = ddf_fun_bind(fun);
158 if (ret != EOK) {
159 ddf_fun_destroy(fun);
160 return ret;
161 }
162
163 ret = usb_device_manager_bind_address(&dev_to_hcd(parent)->dev_manager,
164 address, ddf_fun_get_handle(fun));
165 if (ret != EOK)
166 usb_log_warning("Failed to bind address: %s.\n",
167 str_error(ret));
168
169 list_append(&info->link, &hc_dev->devices);
170 return EOK;
171}
172
173/** Announce root hub to the DDF
174 *
175 * @param[in] device Host controller ddf device
176 * @param[in/out] address USB address of the root hub
177 * @return Error code
178 */
179int hcd_ddf_setup_hub(ddf_dev_t *device, usb_address_t *address)
180{
181 assert(address);
182 assert(device);
183
184 hcd_t *hcd = dev_to_hcd(device);
185
186 const usb_speed_t speed = hcd->dev_manager.max_speed;
187
188 int ret = usb_device_manager_request_address(&hcd->dev_manager,
189 address, false, speed);
190 if (ret != EOK) {
191 usb_log_error("Failed to get root hub address: %s\n",
192 str_error(ret));
193 return ret;
194 }
195
196#define CHECK_RET_UNREG_RETURN(ret, message...) \
197if (ret != EOK) { \
198 usb_log_error(message); \
199 usb_endpoint_manager_remove_ep( \
200 &hcd->ep_manager, *address, 0, \
201 USB_DIRECTION_BOTH, NULL, NULL); \
202 usb_device_manager_release_address( \
203 &hcd->dev_manager, *address); \
204 return ret; \
205} else (void)0
206
207 ret = usb_endpoint_manager_add_ep(
208 &hcd->ep_manager, *address, 0,
209 USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, speed, 64,
210 0, NULL, NULL);
211 CHECK_RET_UNREG_RETURN(ret,
212 "Failed to add root hub control endpoint: %s.\n", str_error(ret));
213
214 match_id_t mid = { .id = "usb&class=hub", .score = 100 };
215 link_initialize(&mid.link);
216 match_id_list_t mid_list;
217 init_match_ids(&mid_list);
218 add_match_id(&mid_list, &mid);
219
220 ret = hcd_ddf_add_usb_device(device, *address, speed, "rh", &mid_list);
221 CHECK_RET_UNREG_RETURN(ret,
222 "Failed to add hcd device: %s.\n", str_error(ret));
223
224 return EOK;
225#undef CHECK_RET_UNREG_RETURN
226}
227
228/** Initialize hc structures.
229 *
230 * @param[in] device DDF instance of the device to use.
231 *
232 * This function does all the ddf work for hc driver.
233 */
234int hcd_ddf_setup_device(ddf_dev_t *device, ddf_fun_t **hc_fun,
235 usb_speed_t max_speed, size_t bw, bw_count_func_t bw_count)
236{
237 if (device == NULL)
238 return EBADMEM;
239
240 hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
241 if (instance == NULL) {
242 usb_log_error("Failed to allocate HCD ddf structure.\n");
243 return ENOMEM;
244 }
245 list_initialize(&instance->devices);
246
247#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
248if (ret != EOK) { \
249 if (instance->hc_fun) { \
250 ddf_fun_destroy(instance->hc_fun); \
251 } \
252 usb_log_error(message); \
253 return ret; \
254} else (void)0
255
256 instance->hc_fun = ddf_fun_create(device, fun_exposed, "hc");
257 int ret = instance->hc_fun ? EOK : ENOMEM;
258 CHECK_RET_DEST_FREE_RETURN(ret,
259 "Failed to create HCD HC function: %s.\n", str_error(ret));
260 ddf_fun_set_ops(instance->hc_fun, &hc_ops);
261 hcd_t *hcd = ddf_fun_data_alloc(instance->hc_fun, sizeof(hcd_t));
262 ret = hcd ? EOK : ENOMEM;
263 CHECK_RET_DEST_FREE_RETURN(ret,
264 "Failed to allocate HCD structure: %s.\n", str_error(ret));
265
266 hcd_init(hcd, max_speed, bw, bw_count);
267
268 ret = ddf_fun_bind(instance->hc_fun);
269 CHECK_RET_DEST_FREE_RETURN(ret,
270 "Failed to bind HCD device function: %s.\n", str_error(ret));
271
272#define CHECK_RET_UNBIND_FREE_RETURN(ret, message...) \
273if (ret != EOK) { \
274 ddf_fun_unbind(instance->hc_fun); \
275 CHECK_RET_DEST_FREE_RETURN(ret, message); \
276} else (void)0
277 ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
278 CHECK_RET_UNBIND_FREE_RETURN(ret,
279 "Failed to add hc to category: %s\n", str_error(ret));
280
281 /* HC should be ok at this point (except it can't do anything) */
282 if (hc_fun)
283 *hc_fun = instance->hc_fun;
284
285 return EOK;
286}
287
288/**
289 * @}
290 */
Note: See TracBrowser for help on using the repository browser.