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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f9d0a86 was f9d0a86, checked in by Aearsis <Hlavaty.Ondrej@…>, 8 years ago

Merge tag '0.7.1'

The merge wasn't clean, because of changes in build system. The most
significant change was partial revert of usbhc callback refactoring,
which now does not take usb transfer batch, but few named fields again.

  • Property mode set to 100644
File size: 5.8 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 <usb/debug.h>
37#include <usb/request.h>
38
39#include <assert.h>
40#include <async.h>
41#include <errno.h>
42#include <usb_iface.h>
43#include <str_error.h>
44
45#include "hcd.h"
46
47
48/** Initialize hcd_t structure.
49 * Initializes device and endpoint managers. Sets data and hook pointer to NULL.
50 *
51 * @param hcd hcd_t structure to initialize, non-null.
52 * @param max_speed Maximum supported USB speed (full, high).
53 * @param bandwidth Available bandwidth, passed to endpoint manager.
54 * @param bw_count Bandwidth compute function, passed to endpoint manager.
55 */
56void hcd_init(hcd_t *hcd) {
57 assert(hcd);
58
59 hcd_set_implementation(hcd, NULL, NULL, NULL);
60}
61
62usb_address_t hcd_request_address(hcd_t *hcd, usb_speed_t speed)
63{
64 assert(hcd);
65 usb_address_t address = 0;
66 const int ret = bus_request_address(hcd->bus, &address, false, speed);
67 if (ret != EOK)
68 return ret;
69 return address;
70}
71
72/** Prepare generic usb_transfer_batch and schedule it.
73 * @param hcd Host controller driver.
74 * @param target address and endpoint number.
75 * @param setup_data Data to use in setup stage (Control communication type)
76 * @param in Callback for device to host communication.
77 * @param out Callback for host to device communication.
78 * @param arg Callback parameter.
79 * @param name Communication identifier (for nicer output).
80 * @return Error code.
81 */
82int hcd_send_batch(hcd_t *hcd, device_t *device, usb_target_t target,
83 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
84 usbhc_iface_transfer_callback_t on_complete, void *arg, const char *name)
85{
86 assert(hcd);
87 assert(device->address == target.address);
88
89 if (!hcd->ops.schedule) {
90 usb_log_error("HCD does not implement scheduler.\n");
91 return ENOTSUP;
92 }
93
94 endpoint_t *ep = bus_find_endpoint(hcd->bus, device, target, direction);
95 if (ep == NULL) {
96 usb_log_error("Endpoint(%d:%d) not registered for %s.\n",
97 device->address, target.endpoint, name);
98 return ENOENT;
99 }
100
101 // TODO cut here aka provide helper to call with instance of endpoint_t in hand
102
103 usb_log_debug2("%s %d:%d %zu(%zu).\n",
104 name, target.address, target.endpoint, size, ep->max_packet_size);
105
106 const size_t bw = bus_count_bw(ep, size);
107 /* Check if we have enough bandwidth reserved */
108 if (ep->bandwidth < bw) {
109 usb_log_error("Endpoint(%d:%d) %s needs %zu bw "
110 "but only %zu is reserved.\n",
111 device->address, ep->endpoint, name, bw, ep->bandwidth);
112 return ENOSPC;
113 }
114
115 usb_transfer_batch_t *batch = usb_transfer_batch_create(ep);
116 if (!batch) {
117 usb_log_error("Failed to create transfer batch.\n");
118 return ENOMEM;
119 }
120
121 batch->target = target;
122 batch->buffer = data;
123 batch->buffer_size = size;
124 batch->setup.packed = setup_data;
125 batch->dir = direction;
126 batch->on_complete = on_complete;
127 batch->on_complete_data = arg;
128
129 /* Check for commands that reset toggle bit */
130 if (ep->transfer_type == USB_TRANSFER_CONTROL)
131 batch->toggle_reset_mode
132 = usb_request_get_toggle_reset_mode(&batch->setup.packet);
133
134 const int ret = hcd->ops.schedule(hcd, batch);
135 if (ret != EOK) {
136 usb_log_warning("Batch %p failed to schedule: %s", batch, str_error(ret));
137 usb_transfer_batch_destroy(batch);
138 }
139
140 /* Drop our own reference to ep. */
141 endpoint_del_ref(ep);
142
143 return ret;
144}
145
146typedef struct {
147 fibril_mutex_t done_mtx;
148 fibril_condvar_t done_cv;
149 unsigned done;
150
151 size_t transfered_size;
152 int error;
153} sync_data_t;
154
155static int sync_transfer_complete(void *arg, int error, size_t transfered_size)
156{
157 sync_data_t *d = arg;
158 assert(d);
159 d->transfered_size = transfered_size;
160 d->error = error;
161 fibril_mutex_lock(&d->done_mtx);
162 d->done = 1;
163 fibril_condvar_broadcast(&d->done_cv);
164 fibril_mutex_unlock(&d->done_mtx);
165 return EOK;
166}
167
168ssize_t hcd_send_batch_sync(hcd_t *hcd, device_t *device, usb_target_t target,
169 usb_direction_t direction, char *data, size_t size, uint64_t setup_data,
170 const char *name)
171{
172 assert(hcd);
173 sync_data_t sd = { .done = 0 };
174 fibril_mutex_initialize(&sd.done_mtx);
175 fibril_condvar_initialize(&sd.done_cv);
176
177 const int ret = hcd_send_batch(hcd, device, target, direction,
178 data, size, setup_data,
179 sync_transfer_complete, &sd, name);
180 if (ret != EOK)
181 return ret;
182
183 fibril_mutex_lock(&sd.done_mtx);
184 while (!sd.done)
185 fibril_condvar_wait(&sd.done_cv, &sd.done_mtx);
186 fibril_mutex_unlock(&sd.done_mtx);
187
188 return (sd.error == EOK)
189 ? (ssize_t) sd.transfered_size
190 : (ssize_t) sd.error;
191}
192
193
194/**
195 * @}
196 */
Note: See TracBrowser for help on using the repository browser.