source: mainline/uspace/drv/ohci/iface.c@ d8b275d

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

Add proper locking to prevent use/remove race

  • Property mode set to 100644
File size: 15.1 KB
Line 
1/*
2 * Copyright (c) 2011 Vojtech Horky, 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 drvusbohci
29 * @{
30 */
31/** @file
32 * @brief OHCI driver hc 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
40#include "iface.h"
41#include "hc.h"
42
43static inline int setup_batch(
44 ddf_fun_t *fun, usb_target_t target, usb_direction_t direction,
45 void *data, size_t size, void * setup_data, size_t setup_size,
46 usbhc_iface_transfer_in_callback_t in,
47 usbhc_iface_transfer_out_callback_t out, void *arg, const char* name,
48 hc_t **hc, usb_transfer_batch_t **batch)
49{
50 assert(hc);
51 assert(batch);
52 assert(fun);
53 *hc = fun_to_hc(fun);
54 assert(*hc);
55
56 size_t res_bw;
57 endpoint_t *ep = hc_get_endpoint(*hc,
58 target.address, target.endpoint, direction, &res_bw);
59 if (ep == NULL) {
60 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
61 target.address, target.endpoint, name);
62 return ENOENT;
63 }
64
65 usb_log_debug("%s %d:%d %zu(%zu).\n",
66 name, target.address, target.endpoint, size, ep->max_packet_size);
67
68 const size_t bw = bandwidth_count_usb11(
69 ep->speed, ep->transfer_type, size, ep->max_packet_size);
70 if (res_bw < bw) {
71 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
72 "but only %zu is reserved.\n",
73 target.address, target.endpoint, name, bw, res_bw);
74 return ENOSPC;
75 }
76
77 *batch = batch_get(
78 fun, ep, data, size, setup_data, setup_size, in, out, arg);
79 if (!*batch)
80 return ENOMEM;
81 return EOK;
82}
83/*----------------------------------------------------------------------------*/
84/** Request address interface function
85 *
86 * @param[in] fun DDF function that was called.
87 * @param[in] speed Speed to associate with the new default address.
88 * @param[out] address Place to write a new address.
89 * @return Error code.
90 */
91static int request_address(
92 ddf_fun_t *fun, usb_speed_t speed, usb_address_t *address)
93{
94 assert(fun);
95 hc_t *hc = fun_to_hc(fun);
96 assert(hc);
97 assert(address);
98
99 usb_log_debug("Address request with speed %d.\n", speed);
100 *address = device_keeper_get_free_address(&hc->manager, speed);
101 usb_log_debug("Address request with result: %d.\n", *address);
102 if (*address <= 0)
103 return *address;
104 return EOK;
105}
106/*----------------------------------------------------------------------------*/
107/** Bind address interface function
108 *
109 * @param[in] fun DDF function that was called.
110 * @param[in] address Address of the device
111 * @param[in] handle Devman handle of the device driver.
112 * @return Error code.
113 */
114static int bind_address(
115 ddf_fun_t *fun, usb_address_t address, devman_handle_t handle)
116{
117 assert(fun);
118 hc_t *hc = fun_to_hc(fun);
119 assert(hc);
120 usb_log_debug("Address bind %d-%d.\n", address, handle);
121 usb_device_keeper_bind(&hc->manager, address, handle);
122 return EOK;
123}
124/*----------------------------------------------------------------------------*/
125/** Release address interface function
126 *
127 * @param[in] fun DDF function that was called.
128 * @param[in] address USB address to be released.
129 * @return Error code.
130 */
131static int release_address(ddf_fun_t *fun, usb_address_t address)
132{
133 assert(fun);
134 hc_t *hc = fun_to_hc(fun);
135 assert(hc);
136 usb_log_debug("Address release %d.\n", address);
137 usb_device_keeper_release(&hc->manager, address);
138 return EOK;
139}
140/*----------------------------------------------------------------------------*/
141/** Register endpoint for bandwidth reservation.
142 *
143 * @param[in] fun Device function the action was invoked on.
144 * @param[in] address USB address of the device.
145 * @param[in] ep_speed Endpoint speed (invalid means to use device one).
146 * @param[in] endpoint Endpoint number.
147 * @param[in] transfer_type USB transfer type.
148 * @param[in] direction Endpoint data direction.
149 * @param[in] max_packet_size Max packet size of the endpoint.
150 * @param[in] interval Polling interval.
151 * @return Error code.
152 */
153static int register_endpoint(ddf_fun_t *fun,
154 usb_address_t address, usb_speed_t ep_speed, usb_endpoint_t endpoint,
155 usb_transfer_type_t transfer_type, usb_direction_t direction,
156 size_t max_packet_size, unsigned int interval)
157{
158 hc_t *hc = fun_to_hc(fun);
159 assert(hc);
160
161 usb_speed_t speed = usb_device_keeper_get_speed(&hc->manager, address);
162 if (speed >= USB_SPEED_MAX) {
163 speed = ep_speed;
164 }
165 const size_t size = max_packet_size;
166
167 usb_log_debug("Register endpoint %d:%d %s %s(%d) %zu(%zu) %u.\n",
168 address, endpoint, usb_str_transfer_type(transfer_type),
169 usb_str_speed(speed), direction, size, max_packet_size, interval);
170
171 return hc_add_endpoint(hc, address, endpoint, speed, transfer_type,
172 direction, max_packet_size, size, interval);
173}
174/*----------------------------------------------------------------------------*/
175static int unregister_endpoint(
176 ddf_fun_t *fun, usb_address_t address,
177 usb_endpoint_t endpoint, usb_direction_t direction)
178{
179 hc_t *hc = fun_to_hc(fun);
180 assert(hc);
181 usb_log_debug("Unregister endpoint %d:%d %d.\n",
182 address, endpoint, direction);
183 return hc_remove_endpoint(hc, address, endpoint, direction);
184}
185/*----------------------------------------------------------------------------*/
186/** Schedule interrupt out transfer.
187 *
188 * The callback is supposed to be called once the transfer (on the wire) is
189 * complete regardless of the outcome.
190 * However, the callback could be called only when this function returns
191 * with success status (i.e. returns EOK).
192 *
193 * @param[in] fun Device function the action was invoked on.
194 * @param[in] target Target pipe (address and endpoint number) specification.
195 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
196 * by the caller).
197 * @param[in] size Size of the @p data buffer in bytes.
198 * @param[in] callback Callback to be issued once the transfer is complete.
199 * @param[in] arg Pass-through argument to the callback.
200 * @return Error code.
201 */
202static int interrupt_out(
203 ddf_fun_t *fun, usb_target_t target, void *data,
204 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
205{
206 usb_transfer_batch_t *batch = NULL;
207 hc_t *hc = NULL;
208 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
209 NULL, 0, NULL, callback, arg, "Interrupt OUT", &hc, &batch);
210 if (ret != EOK)
211 return ret;
212 batch_interrupt_out(batch);
213 ret = hc_schedule(hc, batch);
214 if (ret != EOK) {
215 usb_transfer_batch_dispose(batch);
216 }
217 return ret;
218}
219/*----------------------------------------------------------------------------*/
220/** Schedule interrupt in transfer.
221 *
222 * The callback is supposed to be called once the transfer (on the wire) is
223 * complete regardless of the outcome.
224 * However, the callback could be called only when this function returns
225 * with success status (i.e. returns EOK).
226 *
227 * @param[in] fun Device function the action was invoked on.
228 * @param[in] target Target pipe (address and endpoint number) specification.
229 * @param[in] data Buffer where to store the data (in USB endianess,
230 * allocated and deallocated by the caller).
231 * @param[in] size Size of the @p data buffer in bytes.
232 * @param[in] callback Callback to be issued once the transfer is complete.
233 * @param[in] arg Pass-through argument to the callback.
234 * @return Error code.
235 */
236static int interrupt_in(
237 ddf_fun_t *fun, usb_target_t target, void *data,
238 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
239{
240 usb_transfer_batch_t *batch = NULL;
241 hc_t *hc = NULL;
242 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
243 NULL, 0, callback, NULL, arg, "Interrupt IN", &hc, &batch);
244 if (ret != EOK)
245 return ret;
246 batch_interrupt_in(batch);
247 ret = hc_schedule(hc, batch);
248 if (ret != EOK) {
249 usb_transfer_batch_dispose(batch);
250 }
251 return ret;
252}
253/*----------------------------------------------------------------------------*/
254/** Schedule bulk out transfer.
255 *
256 * The callback is supposed to be called once the transfer (on the wire) is
257 * complete regardless of the outcome.
258 * However, the callback could be called only when this function returns
259 * with success status (i.e. returns EOK).
260 *
261 * @param[in] fun Device function the action was invoked on.
262 * @param[in] target Target pipe (address and endpoint number) specification.
263 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
264 * by the caller).
265 * @param[in] size Size of the @p data buffer in bytes.
266 * @param[in] callback Callback to be issued once the transfer is complete.
267 * @param[in] arg Pass-through argument to the callback.
268 * @return Error code.
269 */
270static int bulk_out(
271 ddf_fun_t *fun, usb_target_t target, void *data,
272 size_t size, usbhc_iface_transfer_out_callback_t callback, void *arg)
273{
274 usb_transfer_batch_t *batch = NULL;
275 hc_t *hc = NULL;
276 int ret = setup_batch(fun, target, USB_DIRECTION_OUT, data, size,
277 NULL, 0, NULL, callback, arg, "Bulk OUT", &hc, &batch);
278 if (ret != EOK)
279 return ret;
280 batch_bulk_out(batch);
281 ret = hc_schedule(hc, batch);
282 if (ret != EOK) {
283 usb_transfer_batch_dispose(batch);
284 }
285 return ret;
286}
287/*----------------------------------------------------------------------------*/
288/** Schedule bulk in transfer.
289 *
290 * The callback is supposed to be called once the transfer (on the wire) is
291 * complete regardless of the outcome.
292 * However, the callback could be called only when this function returns
293 * with success status (i.e. returns EOK).
294 *
295 * @param[in] fun Device function the action was invoked on.
296 * @param[in] target Target pipe (address and endpoint number) specification.
297 * @param[in] data Buffer where to store the data (in USB endianess,
298 * allocated and deallocated by the caller).
299 * @param[in] size Size of the @p data buffer in bytes.
300 * @param[in] callback Callback to be issued once the transfer is complete.
301 * @param[in] arg Pass-through argument to the callback.
302 * @return Error code.
303 */
304static int bulk_in(
305 ddf_fun_t *fun, usb_target_t target, void *data,
306 size_t size, usbhc_iface_transfer_in_callback_t callback, void *arg)
307{
308 usb_transfer_batch_t *batch = NULL;
309 hc_t *hc = NULL;
310 int ret = setup_batch(fun, target, USB_DIRECTION_IN, data, size,
311 NULL, 0, callback, NULL, arg, "Bulk IN", &hc, &batch);
312 if (ret != EOK)
313 return ret;
314 batch_bulk_in(batch);
315 ret = hc_schedule(hc, batch);
316 if (ret != EOK) {
317 usb_transfer_batch_dispose(batch);
318 }
319 return ret;
320}
321/*----------------------------------------------------------------------------*/
322/** Schedule control write transfer.
323 *
324 * The callback is supposed to be called once the transfer (on the wire) is
325 * complete regardless of the outcome.
326 * However, the callback could be called only when this function returns
327 * with success status (i.e. returns EOK).
328 *
329 * @param[in] fun Device function the action was invoked on.
330 * @param[in] target Target pipe (address and endpoint number) specification.
331 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
332 * and deallocated by the caller).
333 * @param[in] setup_size Size of @p setup_packet buffer in bytes.
334 * @param[in] data_buffer Data buffer (in USB endianess, allocated and
335 * deallocated by the caller).
336 * @param[in] size Size of @p data_buffer buffer in bytes.
337 * @param[in] callback Callback to be issued once the transfer is complete.
338 * @param[in] arg Pass-through argument to the callback.
339 * @return Error code.
340 */
341static int control_write(
342 ddf_fun_t *fun, usb_target_t target,
343 void *setup_data, size_t setup_size, void *data, size_t size,
344 usbhc_iface_transfer_out_callback_t callback, void *arg)
345{
346 usb_transfer_batch_t *batch = NULL;
347 hc_t *hc = NULL;
348 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
349 setup_data, setup_size, NULL, callback, arg, "Control WRITE",
350 &hc, &batch);
351 if (ret != EOK)
352 return ret;
353 usb_endpoint_manager_reset_if_need(&hc->ep_manager, target, setup_data);
354 batch_control_write(batch);
355 ret = hc_schedule(hc, batch);
356 if (ret != EOK) {
357 usb_transfer_batch_dispose(batch);
358 }
359 return ret;
360}
361/*----------------------------------------------------------------------------*/
362/** Schedule control read transfer.
363 *
364 * The callback is supposed to be called once the transfer (on the wire) is
365 * complete regardless of the outcome.
366 * However, the callback could be called only when this function returns
367 * with success status (i.e. returns EOK).
368 *
369 * @param[in] fun Device function the action was invoked on.
370 * @param[in] target Target pipe (address and endpoint number) specification.
371 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
372 * and deallocated by the caller).
373 * @param[in] setup_size Size of @p setup_packet buffer in bytes.
374 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
375 * allocated and deallocated by the caller).
376 * @param[in] size Size of @p data_buffer buffer in bytes.
377 * @param[in] callback Callback to be issued once the transfer is complete.
378 * @param[in] arg Pass-through argument to the callback.
379 * @return Error code.
380 */
381static int control_read(
382 ddf_fun_t *fun, usb_target_t target,
383 void *setup_data, size_t setup_size, void *data, size_t size,
384 usbhc_iface_transfer_in_callback_t callback, void *arg)
385{
386 usb_transfer_batch_t *batch = NULL;
387 hc_t *hc = NULL;
388 int ret = setup_batch(fun, target, USB_DIRECTION_BOTH, data, size,
389 setup_data, setup_size, callback, NULL, arg, "Control READ",
390 &hc, &batch);
391 if (ret != EOK)
392 return ret;
393 batch_control_read(batch);
394 ret = hc_schedule(hc, batch);
395 if (ret != EOK) {
396 usb_transfer_batch_dispose(batch);
397 }
398 return ret;
399}
400/*----------------------------------------------------------------------------*/
401usbhc_iface_t hc_iface = {
402 .request_address = request_address,
403 .bind_address = bind_address,
404 .release_address = release_address,
405
406 .register_endpoint = register_endpoint,
407 .unregister_endpoint = unregister_endpoint,
408
409 .interrupt_out = interrupt_out,
410 .interrupt_in = interrupt_in,
411
412 .bulk_out = bulk_out,
413 .bulk_in = bulk_in,
414
415 .control_write = control_write,
416 .control_read = control_read,
417};
418/**
419 * @}
420 */
Note: See TracBrowser for help on using the repository browser.