source: mainline/uspace/lib/usb/src/remotedrv.c@ 710f518

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

Add remote implementation of USBHC interface

  • Property mode set to 100644
File size: 13.1 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 remote drivers (interface implementation).
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#include "hcdhubd_private.h"
42
43static int remote_get_address(device_t *, devman_handle_t, usb_address_t *);
44
45static int remote_interrupt_out(device_t *, usb_target_t, void *, size_t,
46 usbhc_iface_transfer_out_callback_t, void *);
47static int remote_interrupt_in(device_t *, usb_target_t, void *, size_t,
48 usbhc_iface_transfer_in_callback_t, void *);
49
50static int remote_control_write_setup(device_t *, usb_target_t,
51 void *, size_t,
52 usbhc_iface_transfer_out_callback_t, void *);
53static int remote_control_write_data(device_t *, usb_target_t,
54 void *, size_t,
55 usbhc_iface_transfer_out_callback_t, void *);
56static int remote_control_write_status(device_t *, usb_target_t,
57 usbhc_iface_transfer_in_callback_t, void *);
58
59static int remote_control_read_setup(device_t *, usb_target_t,
60 void *, size_t,
61 usbhc_iface_transfer_out_callback_t, void *);
62static int remote_control_read_data(device_t *, usb_target_t,
63 void *, size_t,
64 usbhc_iface_transfer_in_callback_t, void *);
65static int remote_control_read_status(device_t *, usb_target_t,
66 usbhc_iface_transfer_out_callback_t, void *);
67
68/** Implementation of USB HC interface. */
69usbhc_iface_t usbhc_interface = {
70 .tell_address = remote_get_address,
71 .interrupt_out = remote_interrupt_out,
72 .interrupt_in = remote_interrupt_in,
73 .control_write_setup = remote_control_write_setup,
74 .control_write_data = remote_control_write_data,
75 .control_write_status = remote_control_write_status,
76 .control_read_setup = remote_control_read_setup,
77 .control_read_data = remote_control_read_data,
78 .control_read_status = remote_control_read_status
79};
80
81/** Get USB address for remote USBHC interface.
82 *
83 * @param dev Device asked for the information.
84 * @param handle Devman handle of the USB device.
85 * @param address Storage for obtained address.
86 * @return Error code.
87 */
88int remote_get_address(device_t *dev, devman_handle_t handle,
89 usb_address_t *address)
90{
91 usb_address_t addr = usb_get_address_by_handle(handle);
92 if (addr < 0) {
93 return addr;
94 }
95
96 *address = addr;
97
98 return EOK;
99}
100
101/** Information about pending transaction on HC. */
102typedef struct {
103 /** Target device. */
104 usb_hcd_attached_device_info_t *device;
105 /** Target endpoint. */
106 usb_hc_endpoint_info_t *endpoint;
107
108 /** Callbacks. */
109 union {
110 /** Callback for outgoing transfers. */
111 usbhc_iface_transfer_out_callback_t out_callback;
112 /** Callback for incoming transfers. */
113 usbhc_iface_transfer_in_callback_t in_callback;
114 };
115
116 /** Custom argument for the callback. */
117 void *arg;
118} transfer_info_t;
119
120/** Create new transfer info.
121 *
122 * @param device Attached device.
123 * @param endpoint Endpoint.
124 * @param custom_arg Custom argument.
125 * @return Transfer info with pre-filled values.
126 */
127static transfer_info_t *transfer_info_create(
128 usb_hcd_attached_device_info_t *device, usb_hc_endpoint_info_t *endpoint,
129 void *custom_arg)
130{
131 transfer_info_t *transfer = malloc(sizeof(transfer_info_t));
132
133 transfer->device = device;
134 transfer->endpoint = endpoint;
135 transfer->arg = custom_arg;
136 transfer->out_callback = NULL;
137 transfer->in_callback = NULL;
138
139 return transfer;
140}
141
142/** Destroy transfer info.
143 *
144 * @param transfer Transfer to be destroyed.
145 */
146static void transfer_info_destroy(transfer_info_t *transfer)
147{
148 free(transfer->device);
149 free(transfer->endpoint);
150 free(transfer);
151}
152
153/** Create info about attached device.
154 *
155 * @param address Device address.
156 * @return Device info structure.
157 */
158static usb_hcd_attached_device_info_t *create_attached_device_info(
159 usb_address_t address)
160{
161 usb_hcd_attached_device_info_t *dev
162 = malloc(sizeof(usb_hcd_attached_device_info_t));
163
164 dev->address = address;
165 dev->endpoint_count = 0;
166 dev->endpoints = NULL;
167 list_initialize(&dev->link);
168
169 return dev;
170}
171
172/** Create info about device endpoint.
173 *
174 * @param endpoint Endpoint number.
175 * @param direction Endpoint data direction.
176 * @param transfer_type Transfer type of the endpoint.
177 * @return Endpoint info structure.
178 */
179static usb_hc_endpoint_info_t *create_endpoint_info(usb_endpoint_t endpoint,
180 usb_direction_t direction, usb_transfer_type_t transfer_type)
181{
182 usb_hc_endpoint_info_t *ep = malloc(sizeof(usb_hc_endpoint_info_t));
183 ep->data_toggle = 0;
184 ep->direction = direction;
185 ep->transfer_type = transfer_type;
186 ep->endpoint = endpoint;
187
188 return ep;
189}
190
191
192
193/** Callback for OUT transfers.
194 * This callback is called by implementation of HC operations.
195 *
196 * @param hc Host controller that processed the transfer.
197 * @param outcome Transfer outcome.
198 * @param arg Custom argument.
199 */
200static void remote_out_callback(usb_hc_device_t *hc,
201 usb_transaction_outcome_t outcome, void *arg)
202{
203 transfer_info_t *transfer = (transfer_info_t *) arg;
204 transfer->out_callback(hc->generic, outcome, transfer->arg);
205
206 transfer_info_destroy(transfer);
207}
208
209/** Start an OUT transfer.
210 *
211 * @param dev Device that shall process the transfer.
212 * @param target Target device for the data.
213 * @param transfer_type Transfer type.
214 * @param data Data buffer.
215 * @param size Size of data buffer.
216 * @param callback Callback after transfer is complete.
217 * @param arg Custom argument to the callback.
218 * @return Error code.
219 */
220static int remote_out_transfer(device_t *dev, usb_target_t target,
221 usb_transfer_type_t transfer_type, void *data, size_t size,
222 usbhc_iface_transfer_out_callback_t callback, void *arg)
223{
224 usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
225
226 if ((hc->transfer_ops == NULL)
227 || (hc->transfer_ops->transfer_out == NULL)) {
228 return ENOTSUP;
229 }
230
231 transfer_info_t *transfer = transfer_info_create(
232 create_attached_device_info(target.address),
233 create_endpoint_info(target.endpoint,
234 USB_DIRECTION_OUT, transfer_type),
235 arg);
236 transfer->out_callback = callback;
237
238 int rc = hc->transfer_ops->transfer_out(hc,
239 transfer->device, transfer->endpoint,
240 data, size,
241 remote_out_callback, transfer);
242
243 if (rc != EOK) {
244 transfer_info_destroy(transfer);
245 return rc;
246 }
247
248 return EOK;
249}
250
251/** Start a SETUP transfer.
252 *
253 * @param dev Device that shall process the transfer.
254 * @param target Target device for the data.
255 * @param transfer_type Transfer type.
256 * @param data Data buffer.
257 * @param size Size of data buffer.
258 * @param callback Callback after transfer is complete.
259 * @param arg Custom argument to the callback.
260 * @return Error code.
261 */
262static int remote_setup_transfer(device_t *dev, usb_target_t target,
263 usb_transfer_type_t transfer_type, void *data, size_t size,
264 usbhc_iface_transfer_out_callback_t callback, void *arg)
265{
266 usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
267
268 if ((hc->transfer_ops == NULL)
269 || (hc->transfer_ops->transfer_setup == NULL)) {
270 return ENOTSUP;
271 }
272
273 transfer_info_t *transfer = transfer_info_create(
274 create_attached_device_info(target.address),
275 create_endpoint_info(target.endpoint,
276 USB_DIRECTION_OUT, transfer_type),
277 arg);
278 transfer->out_callback = callback;
279
280 int rc = hc->transfer_ops->transfer_setup(hc,
281 transfer->device, transfer->endpoint,
282 data, size,
283 remote_out_callback, transfer);
284
285 if (rc != EOK) {
286 transfer_info_destroy(transfer);
287 return rc;
288 }
289
290 return EOK;
291}
292
293/** Callback for IN transfers.
294 * This callback is called by implementation of HC operations.
295 *
296 * @param hc Host controller that processed the transfer.
297 * @param outcome Transfer outcome.
298 * @param actual_size Size of actually received data.
299 * @param arg Custom argument.
300 */
301static void remote_in_callback(usb_hc_device_t *hc,
302 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
303{
304 transfer_info_t *transfer = (transfer_info_t *) arg;
305 transfer->in_callback(hc->generic, outcome, actual_size, transfer->arg);
306
307 transfer_info_destroy(transfer);
308}
309
310/** Start an IN transfer.
311 *
312 * @param dev Device that shall process the transfer.
313 * @param target Target device for the data.
314 * @param transfer_type Transfer type.
315 * @param data Data buffer.
316 * @param size Size of data buffer.
317 * @param callback Callback after transfer is complete.
318 * @param arg Custom argument to the callback.
319 * @return Error code.
320 */
321static int remote_in_transfer(device_t *dev, usb_target_t target,
322 usb_transfer_type_t transfer_type, void *data, size_t size,
323 usbhc_iface_transfer_in_callback_t callback, void *arg)
324{
325 usb_hc_device_t *hc = (usb_hc_device_t *) dev->driver_data;
326
327 if ((hc->transfer_ops == NULL)
328 || (hc->transfer_ops->transfer_in == NULL)) {
329 return ENOTSUP;
330 }
331
332 transfer_info_t *transfer = transfer_info_create(
333 create_attached_device_info(target.address),
334 create_endpoint_info(target.endpoint,
335 USB_DIRECTION_OUT, transfer_type),
336 arg);
337 transfer->in_callback = callback;
338
339 int rc = hc->transfer_ops->transfer_in(hc,
340 transfer->device, transfer->endpoint,
341 data, size,
342 remote_in_callback, transfer);
343
344 if (rc != EOK) {
345 transfer_info_destroy(transfer);
346 return rc;
347 }
348
349 return EOK;
350}
351
352/** Start outgoing interrupt transfer (USBHC remote interface).
353 *
354 * @param dev Host controller device processing the transfer.
355 * @param target Target USB device.
356 * @param buffer Data buffer.
357 * @param size Data buffer size.
358 * @param callback Callback after the transfer is completed.
359 * @param arg Custom argument to the callback.
360 * @return Error code.
361 */
362int remote_interrupt_out(device_t *dev, usb_target_t target,
363 void *buffer, size_t size,
364 usbhc_iface_transfer_out_callback_t callback, void *arg)
365{
366 return remote_out_transfer(dev, target, USB_TRANSFER_INTERRUPT,
367 buffer, size, callback, arg);
368}
369
370/** Start incoming interrupt transfer (USBHC remote interface).
371 *
372 * @param dev Host controller device processing the transfer.
373 * @param target Target USB device.
374 * @param buffer Data buffer.
375 * @param size Data buffer size.
376 * @param callback Callback after the transfer is completed.
377 * @param arg Custom argument to the callback.
378 * @return Error code.
379 */
380int remote_interrupt_in(device_t *dev, usb_target_t target,
381 void *buffer, size_t size,
382 usbhc_iface_transfer_in_callback_t callback, void *arg)
383{
384 return remote_in_transfer(dev, target, USB_TRANSFER_INTERRUPT,
385 buffer, size, callback, arg);
386}
387
388
389int remote_control_write_setup(device_t *device, usb_target_t target,
390 void *buffer, size_t size,
391 usbhc_iface_transfer_out_callback_t callback, void *arg)
392{
393 return remote_setup_transfer(device, target, USB_TRANSFER_CONTROL,
394 buffer, size, callback, arg);
395}
396
397int remote_control_write_data(device_t *device, usb_target_t target,
398 void *buffer, size_t size,
399 usbhc_iface_transfer_out_callback_t callback, void *arg)
400{
401 return remote_out_transfer(device, target, USB_TRANSFER_CONTROL,
402 buffer, size, callback, arg);
403}
404
405int remote_control_write_status(device_t *device, usb_target_t target,
406 usbhc_iface_transfer_in_callback_t callback, void *arg)
407{
408 return remote_in_transfer(device, target, USB_TRANSFER_CONTROL,
409 NULL, 0, callback, arg);
410}
411
412int remote_control_read_setup(device_t *device, usb_target_t target,
413 void *buffer, size_t size,
414 usbhc_iface_transfer_out_callback_t callback, void *arg)
415{
416 return remote_setup_transfer(device, target, USB_TRANSFER_CONTROL,
417 buffer, size, callback, arg);
418}
419
420int remote_control_read_data(device_t *dev, usb_target_t target,
421 void *buffer, size_t size,
422 usbhc_iface_transfer_in_callback_t callback, void *arg)
423{
424 return remote_in_transfer(dev, target, USB_TRANSFER_CONTROL,
425 buffer, size, callback, arg);
426}
427
428int remote_control_read_status(device_t *device, usb_target_t target,
429 usbhc_iface_transfer_out_callback_t callback, void *arg)
430{
431 return remote_out_transfer(device, target, USB_TRANSFER_CONTROL,
432 NULL, 0, callback, arg);
433}
434
435/**
436 * @}
437 */
Note: See TracBrowser for help on using the repository browser.