source: mainline/uspace/lib/usb/src/localdrv.c@ 62c9661

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

Connecting in HCD in same task in separate function

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