source: mainline/uspace/lib/usbhost/src/iface.c@ cbd568b

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

libsusbhost: Doxygen.

  • Property mode set to 100644
File size: 11.4 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/** @addtogroup libusbhost
29 * @{
30 */
31/** @file
32 * @brief HCD DDF interface implementation
33 */
34#include <ddf/driver.h>
35#include <errno.h>
36
37#include <usb/debug.h>
38#include <usb/host/endpoint.h>
39#include <usb/host/hcd.h>
40
41/** Prepare generic usb_transfer_batch and schedule it.
42 * @param fun DDF fun
43 * @param target address and endpoint number.
44 * @param setup_data Data to use in setup stage (Control communication type)
45 * @param in Callback for device to host communication.
46 * @param out Callback for host to device communication.
47 * @param arg Callback parameter.
48 * @param name Communication identifier (for nicer output).
49 * @return Error code.
50 */
51static inline int send_batch(
52 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
53 void *data, size_t size, uint64_t setup_data,
54 usbhc_iface_transfer_in_callback_t in,
55 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name)
56{
57 assert(fun);
58 hcd_t *hcd = fun_to_hcd(fun);
59 assert(hcd);
60
61 endpoint_t *ep = usb_endpoint_manager_find_ep(&hcd->ep_manager,
62 target.address, target.endpoint, direction);
63 if (ep == NULL) {
64 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
65 target.address, target.endpoint, name);
66 return ENOENT;
67 }
68
69 usb_log_debug2("%s %d:%d %zu(%zu).\n",
70 name, target.address, target.endpoint, size, ep->max_packet_size);
71
72 const size_t bw = bandwidth_count_usb11(
73 ep->speed, ep->transfer_type, size, ep->max_packet_size);
74 /* Check if we have enough bandwidth reserved */
75 if (ep->bandwidth < bw) {
76 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
77 "but only %zu is reserved.\n",
78 ep->address, ep->endpoint, name, bw, ep->bandwidth);
79 return ENOSPC;
80 }
81 if (!hcd->schedule) {
82 usb_log_error("HCD does not implement scheduler.\n");
83 return ENOTSUP;
84 }
85
86 /* No private data and no private data dtor */
87 usb_transfer_batch_t *batch =
88 usb_transfer_batch_create(ep, data, size, setup_data,
89 in, out, arg, fun, NULL, NULL);
90 if (!batch) {
91 return ENOMEM;
92 }
93
94 const int ret = hcd->schedule(hcd, batch);
95 if (ret != EOK)
96 usb_transfer_batch_destroy(batch);
97
98 return ret;
99}
100/*----------------------------------------------------------------------------*/
101/** Calls ep_add_hook upon endpoint registration.
102 * @param ep Endpoint to be registered.
103 * @param arg hcd_t in disguise.
104 * @return Error code.
105 */
106static int register_helper(endpoint_t *ep, void *arg)
107{
108 hcd_t *hcd = arg;
109 assert(ep);
110 assert(hcd);
111 if (hcd->ep_add_hook)
112 return hcd->ep_add_hook(hcd, ep);
113 return EOK;
114}
115/*----------------------------------------------------------------------------*/
116/** Calls ep_remove_hook upon endpoint removal.
117 * @param ep Endpoint to be unregistered.
118 * @param arg hcd_t in disguise.
119 */
120static void unregister_helper(endpoint_t *ep, void *arg)
121{
122 hcd_t *hcd = arg;
123 assert(ep);
124 assert(hcd);
125 if (hcd->ep_remove_hook)
126 hcd->ep_remove_hook(hcd, ep);
127}
128/*----------------------------------------------------------------------------*/
129/** Calls ep_remove_hook upon endpoint removal. Prints warning.
130 * @param ep Endpoint to be unregistered.
131 * @param arg hcd_t in disguise.
132 */
133static void unregister_helper_warn(endpoint_t *ep, void *arg)
134{
135 hcd_t *hcd = arg;
136 assert(ep);
137 assert(hcd);
138 usb_log_warning("Endpoint %d:%d %s was left behind, removing.\n",
139 ep->address, ep->endpoint, usb_str_direction(ep->direction));
140 if (hcd->ep_remove_hook)
141 hcd->ep_remove_hook(hcd, ep);
142}
143/*----------------------------------------------------------------------------*/
144/** Request address interface function.
145 *
146 * @param[in] fun DDF function that was called.
147 * @param[in] address Pointer to preferred USB address.
148 * @param[out] address Place to write a new address.
149 * @param[in] strict Fail if the preferred address is not available.
150 * @param[in] speed Speed to associate with the new default address.
151 * @return Error code.
152 */
153static int request_address(
154 ddf_fun_t *fun, usb_address_t *address, bool strict, usb_speed_t speed)
155{
156 assert(fun);
157 hcd_t *hcd = fun_to_hcd(fun);
158 assert(hcd);
159 assert(address);
160
161 usb_log_debug("Address request: speed: %s, address: %d, strict: %s.\n",
162 usb_str_speed(speed), *address, strict ? "YES" : "NO");
163 return usb_device_manager_request_address(
164 &hcd->dev_manager, address, strict, speed);
165}
166/*----------------------------------------------------------------------------*/
167/** Bind address interface function.
168 *
169 * @param[in] fun DDF function that was called.
170 * @param[in] address Address of the device
171 * @param[in] handle Devman handle of the device driver.
172 * @return Error code.
173 */
174static int bind_address(
175 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
176{
177 assert(fun);
178 hcd_t *hcd = fun_to_hcd(fun);
179 assert(hcd);
180
181 usb_log_debug("Address bind %d-%" PRIun ".\n", address, handle);
182 return usb_device_manager_bind_address(
183 &hcd->dev_manager, address, handle);
184}
185/*----------------------------------------------------------------------------*/
186/** Find device handle by address interface function.
187 *
188 * @param[in] fun DDF function that was called.
189 * @param[in] address Address in question.
190 * @param[out] handle Where to store device handle if found.
191 * @return Error code.
192 */
193static int find_by_address(ddf_fun_t *fun, usb_address_t address,
194 devman_handle_t *handle)
195{
196 assert(fun);
197 hcd_t *hcd = fun_to_hcd(fun);
198 assert(hcd);
199 return usb_device_manager_get_info_by_address(
200 &hcd->dev_manager, address, handle, NULL);
201}
202/*----------------------------------------------------------------------------*/
203/** Release address interface function.
204 *
205 * @param[in] fun DDF function that was called.
206 * @param[in] address USB address to be released.
207 * @return Error code.
208 */
209static int release_address(ddf_fun_t *fun, usb_address_t address)
210{
211 assert(fun);
212 hcd_t *hcd = fun_to_hcd(fun);
213 assert(hcd);
214 usb_log_debug("Address release %d.\n", address);
215 usb_device_manager_release_address(&hcd->dev_manager, address);
216 usb_endpoint_manager_remove_address(&hcd->ep_manager, address,
217 unregister_helper_warn, hcd);
218 return EOK;
219}
220/*----------------------------------------------------------------------------*/
221/** Register endpoint interface function.
222 * @param fun DDF function.
223 * @param address USB address of the device.
224 * @param endpoint USB endpoint number to be registered.
225 * @param transfer_type Endpoint's transfer type.
226 * @param direction USB communication direction the endpoint is capable of.
227 * @param max_packet_size Maximu size of packets the endpoint accepts.
228 * @param interval Preferred timeout between communication.
229 * @return Error code.
230 */
231static int register_endpoint(
232 ddf_fun_t *fun, usb_address_t address, usb_endpoint_t endpoint,
233 usb_transfer_type_t transfer_type, usb_direction_t direction,
234 size_t max_packet_size, unsigned interval)
235{
236 assert(fun);
237 hcd_t *hcd = fun_to_hcd(fun);
238 assert(hcd);
239 const size_t size = max_packet_size;
240 usb_speed_t speed = USB_SPEED_MAX;
241 const int ret = usb_device_manager_get_info_by_address(
242 &hcd->dev_manager, address, NULL, &speed);
243 if (ret != EOK) {
244 return ret;
245 }
246
247 usb_log_debug("Register endpoint %d:%d %s-%s %s %zuB %ums.\n",
248 address, endpoint, usb_str_transfer_type(transfer_type),
249 usb_str_direction(direction), usb_str_speed(speed),
250 max_packet_size, interval);
251
252 return usb_endpoint_manager_add_ep(&hcd->ep_manager, address, endpoint,
253 direction, transfer_type, speed, max_packet_size, size,
254 register_helper, hcd);
255}
256/*----------------------------------------------------------------------------*/
257/** Unregister endpoint interface function.
258 * @param fun DDF function.
259 * @param address USB address of the endpoint.
260 * @param endpoint USB endpoint number.
261 * @param direction Communication direction of the enpdoint to unregister.
262 * @return Error code.
263 */
264static int unregister_endpoint(
265 ddf_fun_t *fun, usb_address_t address,
266 usb_endpoint_t endpoint, usb_direction_t direction)
267{
268 assert(fun);
269 hcd_t *hcd = fun_to_hcd(fun);
270 assert(hcd);
271 usb_log_debug("Unregister endpoint %d:%d %s.\n",
272 address, endpoint, usb_str_direction(direction));
273 return usb_endpoint_manager_remove_ep(&hcd->ep_manager, address,
274 endpoint, direction, unregister_helper, hcd);
275}
276/*----------------------------------------------------------------------------*/
277/** Inbound communication interface function.
278 * @param fun DDF function.
279 * @param target Communication target.
280 * @param setup_data Data to use in setup stage (control transfers).
281 * @param data Pointer to data buffer.
282 * @param size Size of the data buffer.
283 * @param callback Function to call on communication end.
284 * @param arg Argument passed to the callback function.
285 * @return Error code.
286 */
287static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
288 uint8_t *data, size_t size, usbhc_iface_transfer_in_callback_t callback,
289 void *arg)
290{
291 return send_batch(fun, target, USB_DIRECTION_IN, data, size,
292 setup_data, callback, NULL, arg, "READ");
293}
294/*----------------------------------------------------------------------------*/
295/** Outbound communication interface function.
296 * @param fun DDF function.
297 * @param target Communication target.
298 * @param setup_data Data to use in setup stage (control transfers).
299 * @param data Pointer to data buffer.
300 * @param size Size of the data buffer.
301 * @param callback Function to call on communication end.
302 * @param arg Argument passed to the callback function.
303 * @return Error code.
304 */
305static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_data,
306 const uint8_t *data, size_t size,
307 usbhc_iface_transfer_out_callback_t callback, void *arg)
308{
309 return send_batch(fun, target, USB_DIRECTION_OUT, (uint8_t*)data, size,
310 setup_data, NULL, callback, arg, "WRITE");
311}
312/*----------------------------------------------------------------------------*/
313/** usbhc Interface implementation using hcd_t from libusbhost library. */
314usbhc_iface_t hcd_iface = {
315 .request_address = request_address,
316 .bind_address = bind_address,
317 .get_handle = find_by_address,
318 .release_address = release_address,
319
320 .register_endpoint = register_endpoint,
321 .unregister_endpoint = unregister_endpoint,
322
323 .read = usb_read,
324 .write = usb_write,
325};
326/**
327 * @}
328 */
Note: See TracBrowser for help on using the repository browser.