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

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

libusbhost: Move lsit of usb device to ddf helper structure.

  • 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 OHCI 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 //TODO more checks
130 ddf_fun_t *fun = ddf_fun_create(parent, fun_inner, name);
131 if (!fun)
132 return ENOMEM;
133 usb_dev_t *info = ddf_fun_data_alloc(fun, sizeof(usb_dev_t));
134 if (!info) {
135 ddf_fun_destroy(fun);
136 return ENOMEM;
137 }
138 info->address = address;
139 info->speed = speed;
140 info->handle = hc_handle;
141 info->fun = fun;
142 link_initialize(&info->link);
143
144 ddf_fun_set_ops(fun, &usb_ops);
145 list_foreach(mids->ids, iter) {
146 match_id_t *mid = list_get_instance(iter, match_id_t, link);
147 ddf_fun_add_match_id(fun, mid->id, mid->score);
148 }
149
150 int ret = ddf_fun_bind(fun);
151 if (ret != EOK) {
152 ddf_fun_destroy(fun);
153 return ret;
154 }
155
156 ret = usb_device_manager_bind_address(&dev_to_hcd(parent)->dev_manager,
157 address, ddf_fun_get_handle(fun));
158 if (ret != EOK)
159 usb_log_warning("Failed to bind address: %s.\n",
160 str_error(ret));
161
162 list_append(&info->link, &hc_dev->devices);
163 return EOK;
164}
165
166/** Announce root hub to the DDF
167 *
168 * @param[in] instance OHCI driver instance
169 * @param[in] hub_fun DDF function representing OHCI root hub
170 * @return Error code
171 */
172int hcd_ddf_setup_hub(hcd_t *instance, usb_address_t *address, ddf_dev_t *device)
173{
174 assert(instance);
175 assert(address);
176 assert(device);
177
178 const usb_speed_t speed = instance->dev_manager.max_speed;
179
180 int ret = usb_device_manager_request_address(&instance->dev_manager,
181 address, false, speed);
182 if (ret != EOK) {
183 usb_log_error("Failed to get root hub address: %s\n",
184 str_error(ret));
185 return ret;
186 }
187
188#define CHECK_RET_UNREG_RETURN(ret, message...) \
189if (ret != EOK) { \
190 usb_log_error(message); \
191 usb_endpoint_manager_remove_ep( \
192 &instance->ep_manager, *address, 0, \
193 USB_DIRECTION_BOTH, NULL, NULL); \
194 usb_device_manager_release_address( \
195 &instance->dev_manager, *address); \
196 return ret; \
197} else (void)0
198
199 ret = usb_endpoint_manager_add_ep(
200 &instance->ep_manager, *address, 0,
201 USB_DIRECTION_BOTH, USB_TRANSFER_CONTROL, speed, 64,
202 0, NULL, NULL);
203 CHECK_RET_UNREG_RETURN(ret,
204 "Failed to add root hub control endpoint: %s.\n", str_error(ret));
205
206 match_id_t mid = { .id = "usb&class=hub", .score = 100 };
207 link_initialize(&mid.link);
208 match_id_list_t mid_list;
209 init_match_ids(&mid_list);
210 add_match_id(&mid_list, &mid);
211
212 ret = hcd_ddf_add_usb_device(device, *address, speed, "rh", &mid_list);
213 CHECK_RET_UNREG_RETURN(ret,
214 "Failed to add hcd device: %s.\n", str_error(ret));
215
216 return EOK;
217#undef CHECK_RET_UNREG_RETURN
218}
219
220/** Initialize hc structures.
221 *
222 * @param[in] device DDF instance of the device to use.
223 *
224 * This function does all the preparatory work for hc driver implementation.
225 * - gets device hw resources
226 * - disables OHCI legacy support
227 * - asks for interrupt
228 * - registers interrupt handler
229 */
230int hcd_ddf_setup_device(ddf_dev_t *device, ddf_fun_t **hc_fun,
231 usb_speed_t max_speed, size_t bw, bw_count_func_t bw_count)
232{
233 if (device == NULL)
234 return EBADMEM;
235
236 hc_dev_t *instance = ddf_dev_data_alloc(device, sizeof(hc_dev_t));
237 if (instance == NULL) {
238 usb_log_error("Failed to allocate OHCI driver.\n");
239 return ENOMEM;
240 }
241 list_initialize(&instance->devices);
242
243#define CHECK_RET_DEST_FREE_RETURN(ret, message...) \
244if (ret != EOK) { \
245 if (instance->hc_fun) { \
246 ddf_fun_destroy(instance->hc_fun); \
247 } \
248 usb_log_error(message); \
249 return ret; \
250} else (void)0
251
252 instance->hc_fun = ddf_fun_create(device, fun_exposed, "hc");
253 int ret = instance->hc_fun ? EOK : ENOMEM;
254 CHECK_RET_DEST_FREE_RETURN(ret,
255 "Failed to create OHCI HC function: %s.\n", str_error(ret));
256 ddf_fun_set_ops(instance->hc_fun, &hc_ops);
257 hcd_t *hcd = ddf_fun_data_alloc(instance->hc_fun, sizeof(hcd_t));
258 ret = hcd ? EOK : ENOMEM;
259 CHECK_RET_DEST_FREE_RETURN(ret,
260 "Failed to allocate HCD structure: %s.\n", str_error(ret));
261
262 hcd_init(hcd, max_speed, bw, bw_count);
263
264 ret = ddf_fun_bind(instance->hc_fun);
265 CHECK_RET_DEST_FREE_RETURN(ret,
266 "Failed to bind OHCI device function: %s.\n", str_error(ret));
267
268#define CHECK_RET_UNBIND_FREE_RETURN(ret, message...) \
269if (ret != EOK) { \
270 ddf_fun_unbind(instance->hc_fun); \
271 CHECK_RET_DEST_FREE_RETURN(ret, \
272 "Failed to add OHCI to HC class: %s.\n", str_error(ret)); \
273} else (void)0
274 ret = ddf_fun_add_to_category(instance->hc_fun, USB_HC_CATEGORY);
275 CHECK_RET_UNBIND_FREE_RETURN(ret,
276 "Failed to add hc to category: %s\n", str_error(ret));
277
278 /* HC should be ok at this point (except it can't do anything) */
279 if (hc_fun)
280 *hc_fun = instance->hc_fun;
281
282 return EOK;
283}
284
285/**
286 * @}
287 */
Note: See TracBrowser for help on using the repository browser.