source: mainline/uspace/lib/usb/src/localdrv.c@ 4d31d58

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4d31d58 was 4d31d58, checked in by Vojtech Horky <vojtechhorky@…>, 15 years ago

Control transfers ready for local drivers

  • Property mode set to 100644
File size: 10.6 KB
RevLine 
[be2ad7cf]1/*
2 * Copyright (c) 2010 Vojtech Horky
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 libusb usb
30 * @{
31 */
32/** @file
33 * @brief Driver communication for local drivers (hubs).
34 */
35#include <usb/hcdhubd.h>
36#include <usbhc_iface.h>
37#include <driver.h>
38#include <bool.h>
39#include <errno.h>
40
41/** Information about pending transaction on HC. */
42typedef struct {
43 /** Storage for actual number of bytes transferred. */
44 size_t *size_transferred;
45
46 /** Target device. */
47 usb_hcd_attached_device_info_t *device;
48 /** Target endpoint. */
49 usb_hc_endpoint_info_t *endpoint;
50
51 /** Guard for the condition variable. */
52 fibril_mutex_t condvar_guard;
53 /** Condition variable for waiting for done. */
54 fibril_condvar_t condvar;
55
56 /** Flag whether the transfer is done. */
57 bool done;
58} transfer_info_t;
59
60/** Create new transfer info.
61 *
62 * @param device Attached device.
63 * @param endpoint Endpoint.
64 * @return Transfer info with pre-filled values.
65 */
66static transfer_info_t *transfer_info_create(
67 usb_hcd_attached_device_info_t *device, usb_hc_endpoint_info_t *endpoint)
68{
69 transfer_info_t *transfer = malloc(sizeof(transfer_info_t));
70
71 transfer->size_transferred = NULL;
72 fibril_condvar_initialize(&transfer->condvar);
73 fibril_mutex_initialize(&transfer->condvar_guard);
74 transfer->done = false;
75
76 transfer->device = device;
77 transfer->endpoint = endpoint;
78
79 return transfer;
80}
81
82/** Destroy transfer info.
83 *
84 * @param transfer Transfer to be destroyed.
85 */
86static void transfer_info_destroy(transfer_info_t *transfer)
87{
88 free(transfer->device);
89 free(transfer->endpoint);
90 free(transfer);
91}
92
93/** Create info about attached device.
94 *
95 * @param address Device address.
96 * @return Device info structure.
97 */
98static usb_hcd_attached_device_info_t *create_attached_device_info(
99 usb_address_t address)
100{
101 usb_hcd_attached_device_info_t *dev
102 = malloc(sizeof(usb_hcd_attached_device_info_t));
103
104 dev->address = address;
105 dev->endpoint_count = 0;
106 dev->endpoints = NULL;
107 list_initialize(&dev->link);
108
109 return dev;
110}
111
112/** Create info about device endpoint.
113 *
114 * @param endpoint Endpoint number.
115 * @param direction Endpoint data direction.
116 * @param transfer_type Transfer type of the endpoint.
117 * @return Endpoint info structure.
118 */
119static usb_hc_endpoint_info_t *create_endpoint_info(usb_endpoint_t endpoint,
120 usb_direction_t direction, usb_transfer_type_t transfer_type)
121{
122 usb_hc_endpoint_info_t *ep = malloc(sizeof(usb_hc_endpoint_info_t));
123 ep->data_toggle = 0;
124 ep->direction = direction;
125 ep->transfer_type = transfer_type;
126 ep->endpoint = endpoint;
127
128 return ep;
129}
130
131/** Marks given transfer as done.
132 *
133 * @param transfer Transfer to be completed.
134 */
135static void transfer_mark_complete(transfer_info_t *transfer)
136{
137 fibril_mutex_lock(&transfer->condvar_guard);
138 transfer->done = true;
139 fibril_condvar_signal(&transfer->condvar);
140 fibril_mutex_unlock(&transfer->condvar_guard);
141}
142
143/** Callback for OUT transfers.
144 *
145 * @param hc Host controller that processed the transfer.
146 * @param outcome Transfer outcome.
147 * @param arg Custom argument.
148 */
149static void callback_out(usb_hc_device_t *hc,
150 usb_transaction_outcome_t outcome, void *arg)
151{
152 transfer_info_t *transfer = (transfer_info_t *) arg;
153
154 /*
155 * For out transfers, marking them complete is enough.
156 * No other processing is necessary.
157 */
158 transfer_mark_complete(transfer);
159}
160
161/** Callback for IN transfers.
162 *
163 * @param hc Host controller that processed the transfer.
164 * @param actual_size Number of actually transferred bytes.
165 * @param outcome Transfer outcome.
166 * @param arg Custom argument.
167 */
168static void callback_in(usb_hc_device_t *hc,
169 size_t actual_size, usb_transaction_outcome_t outcome, void *arg)
170{
171 transfer_info_t *transfer = (transfer_info_t *) arg;
172
173 /*
174 * Set the number of actually transferred bytes and
175 * mark the transfer as complete.
176 */
177 if (transfer->size_transferred != NULL) {
178 *transfer->size_transferred = actual_size;
179 }
180
181 transfer_mark_complete(transfer);
182}
183
[4d31d58]184static int async_transfer_out(usb_hc_device_t *hc,
185 usb_target_t target, usb_transfer_type_t transfer_type,
186 void *data, size_t size,
[be2ad7cf]187 usb_handle_t *handle)
188{
189 if ((hc->transfer_ops == NULL)
190 || (hc->transfer_ops->transfer_out == NULL)) {
191 return ENOTSUP;
192 }
193
194 /* This creation of the device on the fly is just a workaround. */
195
196 transfer_info_t *transfer = transfer_info_create(
197 create_attached_device_info(target.address),
198 create_endpoint_info(target.endpoint,
[4d31d58]199 USB_DIRECTION_OUT, transfer_type));
[be2ad7cf]200
201 int rc = hc->transfer_ops->transfer_out(hc,
202 transfer->device, transfer->endpoint,
[4d31d58]203 data, size,
[be2ad7cf]204 callback_out, transfer);
205
206 if (rc != EOK) {
207 transfer_info_destroy(transfer);
208 return rc;
209 }
210
211 *handle = (usb_handle_t)transfer;
212
213 return EOK;
214}
215
[4d31d58]216static int async_transfer_setup(usb_hc_device_t *hc,
217 usb_target_t target, usb_transfer_type_t transfer_type,
218 void *data, size_t size,
219 usb_handle_t *handle)
220{
221 if ((hc->transfer_ops == NULL)
222 || (hc->transfer_ops->transfer_setup == NULL)) {
223 return ENOTSUP;
224 }
[be2ad7cf]225
[4d31d58]226 /* This creation of the device on the fly is just a workaround. */
227
228 transfer_info_t *transfer = transfer_info_create(
229 create_attached_device_info(target.address),
230 create_endpoint_info(target.endpoint,
231 USB_DIRECTION_OUT, transfer_type));
232
233 int rc = hc->transfer_ops->transfer_setup(hc,
234 transfer->device, transfer->endpoint,
235 data, size,
236 callback_out, transfer);
237
238 if (rc != EOK) {
239 transfer_info_destroy(transfer);
240 return rc;
241 }
242
243 *handle = (usb_handle_t)transfer;
244
245 return EOK;
246}
247
248static int async_transfer_in(usb_hc_device_t *hc, usb_target_t target,
249 usb_transfer_type_t transfer_type,
[be2ad7cf]250 void *buffer, size_t size, size_t *actual_size,
251 usb_handle_t *handle)
252{
253 if ((hc->transfer_ops == NULL)
254 || (hc->transfer_ops->transfer_in == NULL)) {
255 return ENOTSUP;
256 }
257
258 /* This creation of the device on the fly is just a workaround. */
259
260 transfer_info_t *transfer = transfer_info_create(
261 create_attached_device_info(target.address),
262 create_endpoint_info(target.endpoint,
[4d31d58]263 USB_DIRECTION_IN, transfer_type));
[be2ad7cf]264 transfer->size_transferred = actual_size;
265
266 int rc = hc->transfer_ops->transfer_in(hc,
267 transfer->device, transfer->endpoint,
268 buffer, size,
269 callback_in, transfer);
270
271 if (rc != EOK) {
272 transfer_info_destroy(transfer);
273 return rc;
274 }
275
276 *handle = (usb_handle_t)transfer;
277
278 return EOK;
279}
280
[4d31d58]281
282/** Issue interrupt OUT transfer to HC driven by current task.
283 *
284 * @param hc Host controller to handle the transfer.
285 * @param target Target device address.
286 * @param buffer Data buffer.
287 * @param size Buffer size.
288 * @param handle Transfer handle.
289 * @return Error code.
290 */
291int usb_hc_async_interrupt_out(usb_hc_device_t *hc, usb_target_t target,
292 void *buffer, size_t size,
293 usb_handle_t *handle)
294{
295 return async_transfer_out(hc, target,
296 USB_TRANSFER_INTERRUPT, buffer, size, handle);
297}
298
299
300/** Issue interrupt IN transfer to HC driven by current task.
301 *
302 * @warning The @p buffer and @p actual_size parameters shall not be
303 * touched until this transfer is waited for by usb_hc_async_wait_for().
304 *
305 * @param hc Host controller to handle the transfer.
306 * @param target Target device address.
307 * @param buffer Data buffer.
308 * @param size Buffer size.
309 * @param actual_size Size of actually transferred data.
310 * @param handle Transfer handle.
311 * @return Error code.
312 */
313int usb_hc_async_interrupt_in(usb_hc_device_t *hc, usb_target_t target,
314 void *buffer, size_t size, size_t *actual_size,
315 usb_handle_t *handle)
316{
317 return async_transfer_in(hc, target,
318 USB_TRANSFER_INTERRUPT, buffer, size, actual_size, handle);
319}
320
321int usb_hc_async_control_write_setup(usb_hc_device_t *hc, usb_target_t target,
322 void *data, size_t size, usb_handle_t *handle)
323{
324 return async_transfer_setup(hc, target,
325 USB_TRANSFER_CONTROL, data, size, handle);
326}
327
328int usb_hc_async_control_write_data(usb_hc_device_t *hc, usb_target_t target,
329 void *data, size_t size, usb_handle_t *handle)
330{
331 return async_transfer_out(hc, target,
332 USB_TRANSFER_CONTROL, data, size, handle);
333}
334
335int usb_hc_async_control_write_status(usb_hc_device_t *hc, usb_target_t target,
336 usb_handle_t *handle)
337{
338 return async_transfer_in(hc, target,
339 USB_TRANSFER_CONTROL, NULL, 0, NULL, handle);
340}
341
342int usb_hc_async_control_read_setup(usb_hc_device_t *hc, usb_target_t target,
343 void *data, size_t size, usb_handle_t *handle)
344{
345 return async_transfer_setup(hc, target,
346 USB_TRANSFER_CONTROL, data, size, handle);
347}
348
349int usb_hc_async_control_read_data(usb_hc_device_t *hc, usb_target_t target,
350 void *buffer, size_t size, size_t *actual_size,
351 usb_handle_t *handle)
352{
353 return async_transfer_in(hc, target,
354 USB_TRANSFER_CONTROL, buffer, size, actual_size, handle);
355}
356
357int usb_hc_async_control_read_status(usb_hc_device_t *hc, usb_target_t target,
358 usb_handle_t *handle)
359{
360 return async_transfer_out(hc, target,
361 USB_TRANSFER_CONTROL, NULL, 0, handle);
362}
363
[be2ad7cf]364/** Wait for transfer to complete.
365 *
366 * @param handle Transfer handle.
367 * @return Error code.
368 */
369int usb_hc_async_wait_for(usb_handle_t handle)
370{
371 transfer_info_t *transfer = (transfer_info_t *) handle;
372 if (transfer == NULL) {
373 return ENOENT;
374 }
375
376 fibril_mutex_lock(&transfer->condvar_guard);
377 while (!transfer->done) {
378 fibril_condvar_wait(&transfer->condvar, &transfer->condvar_guard);
379 }
380 fibril_mutex_unlock(&transfer->condvar_guard);
381
382 transfer_info_destroy(transfer);
383
384 return EOK;
385}
386
387/**
388 * @}
389 */
Note: See TracBrowser for help on using the repository browser.