source: mainline/uspace/lib/usbhost/src/hcd.c@ 9c7ed9c

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

libusbhost,hcd: Add generic device_add function.

This will be useful later.
Switch rh initialization to use this function.

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