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

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

libusbhost: Move ddf specific functions to separate header.

Switch ehci to using libusbhost proided routines.
Make hcd_iface private.

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