source: mainline/uspace/lib/drv/generic/remote_usbhc.c@ 7f56fb7

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

USB interfaces reorganization

The most important change is that getting USB address of a device
is an operation of generic USB interface, not USB-HC interface.
That is needed for proper functionality of a MID driver.

Also added sample implementation of USB interface operations as is
needed by most drivers (sample does not mean unfunctional or partially
implemented here).
They are stored in libusb/ddfiface.h

Updated UHCI, UHCI-RH, hub, VHC drivers to use these sample
implementations.

Updated libusb device recognition routines to route get_address requests
through USB interface.

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * Copyright (c) 2010-2011 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 libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <async.h>
36#include <errno.h>
37
38#include "usbhc_iface.h"
39#include "driver.h"
40
41#define USB_MAX_PAYLOAD_SIZE 1020
42#define HACK_MAX_PACKET_SIZE 8
43#define HACK_MAX_PACKET_SIZE_INTERRUPT_IN 4
44
45static void remote_usbhc_interrupt_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
46static void remote_usbhc_interrupt_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
47static void remote_usbhc_bulk_out(device_t *, void *, ipc_callid_t, ipc_call_t *);
48static void remote_usbhc_bulk_in(device_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_control_write(device_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_read(device_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_reserve_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_release_default_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_request_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
54static void remote_usbhc_bind_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_release_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
56//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
57
58/** Remote USB host controller interface operations. */
59static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
60 remote_usbhc_reserve_default_address,
61 remote_usbhc_release_default_address,
62
63 remote_usbhc_request_address,
64 remote_usbhc_bind_address,
65 remote_usbhc_release_address,
66
67 remote_usbhc_interrupt_out,
68 remote_usbhc_interrupt_in,
69
70 remote_usbhc_bulk_out,
71 remote_usbhc_bulk_in,
72
73 remote_usbhc_control_write,
74 remote_usbhc_control_read
75};
76
77/** Remote USB host controller interface structure.
78 */
79remote_iface_t remote_usbhc_iface = {
80 .method_count = sizeof(remote_usbhc_iface_ops) /
81 sizeof(remote_usbhc_iface_ops[0]),
82 .methods = remote_usbhc_iface_ops
83};
84
85typedef struct {
86 ipc_callid_t caller;
87 ipc_callid_t data_caller;
88 void *buffer;
89 void *setup_packet;
90 size_t size;
91} async_transaction_t;
92
93static void async_transaction_destroy(async_transaction_t *trans)
94{
95 if (trans == NULL) {
96 return;
97 }
98
99 if (trans->setup_packet != NULL) {
100 free(trans->setup_packet);
101 }
102 if (trans->buffer != NULL) {
103 free(trans->buffer);
104 }
105
106 free(trans);
107}
108
109static async_transaction_t *async_transaction_create(ipc_callid_t caller)
110{
111 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
112 if (trans == NULL) {
113 return NULL;
114 }
115
116 trans->caller = caller;
117 trans->data_caller = 0;
118 trans->buffer = NULL;
119 trans->setup_packet = NULL;
120 trans->size = 0;
121
122 return trans;
123}
124
125void remote_usbhc_reserve_default_address(device_t *device, void *iface,
126 ipc_callid_t callid, ipc_call_t *call)
127{
128 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
129
130 if (!usb_iface->reserve_default_address) {
131 async_answer_0(callid, ENOTSUP);
132 return;
133 }
134
135 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
136
137 int rc = usb_iface->reserve_default_address(device, speed);
138
139 async_answer_0(callid, rc);
140}
141
142void remote_usbhc_release_default_address(device_t *device, void *iface,
143 ipc_callid_t callid, ipc_call_t *call)
144{
145 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
146
147 if (!usb_iface->release_default_address) {
148 async_answer_0(callid, ENOTSUP);
149 return;
150 }
151
152 int rc = usb_iface->release_default_address(device);
153
154 async_answer_0(callid, rc);
155}
156
157void remote_usbhc_request_address(device_t *device, void *iface,
158 ipc_callid_t callid, ipc_call_t *call)
159{
160 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
161
162 if (!usb_iface->request_address) {
163 async_answer_0(callid, ENOTSUP);
164 return;
165 }
166
167 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
168
169 usb_address_t address;
170 int rc = usb_iface->request_address(device, speed, &address);
171 if (rc != EOK) {
172 async_answer_0(callid, rc);
173 } else {
174 async_answer_1(callid, EOK, (sysarg_t) address);
175 }
176}
177
178void remote_usbhc_bind_address(device_t *device, void *iface,
179 ipc_callid_t callid, ipc_call_t *call)
180{
181 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
182
183 if (!usb_iface->bind_address) {
184 async_answer_0(callid, ENOTSUP);
185 return;
186 }
187
188 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
189 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
190
191 int rc = usb_iface->bind_address(device, address, handle);
192
193 async_answer_0(callid, rc);
194}
195
196void remote_usbhc_release_address(device_t *device, void *iface,
197 ipc_callid_t callid, ipc_call_t *call)
198{
199 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
200
201 if (!usb_iface->release_address) {
202 async_answer_0(callid, ENOTSUP);
203 return;
204 }
205
206 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
207
208 int rc = usb_iface->release_address(device, address);
209
210 async_answer_0(callid, rc);
211}
212
213
214static void callback_out(device_t *device,
215 int outcome, void *arg)
216{
217 async_transaction_t *trans = (async_transaction_t *)arg;
218
219 async_answer_0(trans->caller, outcome);
220
221 async_transaction_destroy(trans);
222}
223
224static void callback_in(device_t *device,
225 int outcome, size_t actual_size, void *arg)
226{
227 async_transaction_t *trans = (async_transaction_t *)arg;
228
229 if (outcome != EOK) {
230 async_answer_0(trans->caller, outcome);
231 if (trans->data_caller) {
232 async_answer_0(trans->data_caller, EINTR);
233 }
234 async_transaction_destroy(trans);
235 return;
236 }
237
238 trans->size = actual_size;
239
240 if (trans->data_caller) {
241 async_data_read_finalize(trans->data_caller,
242 trans->buffer, actual_size);
243 }
244
245 async_answer_0(trans->caller, EOK);
246
247 async_transaction_destroy(trans);
248}
249
250/** Process an outgoing transfer (both OUT and SETUP).
251 *
252 * @param device Target device.
253 * @param callid Initiating caller.
254 * @param call Initiating call.
255 * @param transfer_func Transfer function (might be NULL).
256 */
257static void remote_usbhc_out_transfer(device_t *device,
258 ipc_callid_t callid, ipc_call_t *call,
259 usbhc_iface_transfer_out_t transfer_func)
260{
261 if (!transfer_func) {
262 async_answer_0(callid, ENOTSUP);
263 return;
264 }
265
266 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
267 usb_target_t target = {
268 .address = DEV_IPC_GET_ARG1(*call),
269 .endpoint = DEV_IPC_GET_ARG2(*call)
270 };
271
272 size_t len = 0;
273 void *buffer = NULL;
274
275 int rc = async_data_write_accept(&buffer, false,
276 1, USB_MAX_PAYLOAD_SIZE,
277 0, &len);
278
279 if (rc != EOK) {
280 async_answer_0(callid, rc);
281 return;
282 }
283
284 async_transaction_t *trans = async_transaction_create(callid);
285 if (trans == NULL) {
286 if (buffer != NULL) {
287 free(buffer);
288 }
289 async_answer_0(callid, ENOMEM);
290 return;
291 }
292
293 trans->buffer = buffer;
294 trans->size = len;
295
296 rc = transfer_func(device, target, max_packet_size,
297 buffer, len,
298 callback_out, trans);
299
300 if (rc != EOK) {
301 async_answer_0(callid, rc);
302 async_transaction_destroy(trans);
303 }
304}
305
306/** Process an incoming transfer.
307 *
308 * @param device Target device.
309 * @param callid Initiating caller.
310 * @param call Initiating call.
311 * @param transfer_func Transfer function (might be NULL).
312 */
313static void remote_usbhc_in_transfer(device_t *device,
314 ipc_callid_t callid, ipc_call_t *call,
315 usbhc_iface_transfer_in_t transfer_func)
316{
317 if (!transfer_func) {
318 async_answer_0(callid, ENOTSUP);
319 return;
320 }
321
322 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
323 usb_target_t target = {
324 .address = DEV_IPC_GET_ARG1(*call),
325 .endpoint = DEV_IPC_GET_ARG2(*call)
326 };
327
328 size_t len;
329 ipc_callid_t data_callid;
330 if (!async_data_read_receive(&data_callid, &len)) {
331 async_answer_0(callid, EPARTY);
332 return;
333 }
334
335 async_transaction_t *trans = async_transaction_create(callid);
336 if (trans == NULL) {
337 async_answer_0(callid, ENOMEM);
338 return;
339 }
340 trans->data_caller = data_callid;
341 trans->buffer = malloc(len);
342 trans->size = len;
343
344 int rc = transfer_func(device, target, max_packet_size,
345 trans->buffer, len,
346 callback_in, trans);
347
348 if (rc != EOK) {
349 async_answer_0(callid, rc);
350 async_transaction_destroy(trans);
351 }
352}
353
354void remote_usbhc_interrupt_out(device_t *device, void *iface,
355 ipc_callid_t callid, ipc_call_t *call)
356{
357 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
358 assert(usb_iface != NULL);
359
360 return remote_usbhc_out_transfer(device, callid, call,
361 usb_iface->interrupt_out);
362}
363
364void remote_usbhc_interrupt_in(device_t *device, void *iface,
365 ipc_callid_t callid, ipc_call_t *call)
366{
367 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
368 assert(usb_iface != NULL);
369
370 return remote_usbhc_in_transfer(device, callid, call,
371 usb_iface->interrupt_in);
372}
373
374void remote_usbhc_bulk_out(device_t *device, void *iface,
375 ipc_callid_t callid, ipc_call_t *call)
376{
377 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
378 assert(usb_iface != NULL);
379
380 return remote_usbhc_out_transfer(device, callid, call,
381 usb_iface->bulk_out);
382}
383
384void remote_usbhc_bulk_in(device_t *device, void *iface,
385 ipc_callid_t callid, ipc_call_t *call)
386{
387 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
388 assert(usb_iface != NULL);
389
390 return remote_usbhc_in_transfer(device, callid, call,
391 usb_iface->bulk_in);
392}
393
394void remote_usbhc_control_write(device_t *device, void *iface,
395ipc_callid_t callid, ipc_call_t *call)
396{
397 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
398 assert(usb_iface != NULL);
399
400 if (!usb_iface->control_write) {
401 async_answer_0(callid, ENOTSUP);
402 return;
403 }
404
405 usb_target_t target = {
406 .address = DEV_IPC_GET_ARG1(*call),
407 .endpoint = DEV_IPC_GET_ARG2(*call)
408 };
409 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
410 size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
411
412 int rc;
413
414 void *setup_packet = NULL;
415 void *data_buffer = NULL;
416 size_t setup_packet_len = 0;
417
418 rc = async_data_write_accept(&setup_packet, false,
419 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
420 if (rc != EOK) {
421 async_answer_0(callid, rc);
422 return;
423 }
424
425 if (data_buffer_len > 0) {
426 rc = async_data_write_accept(&data_buffer, false,
427 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
428 if (rc != EOK) {
429 async_answer_0(callid, rc);
430 free(setup_packet);
431 return;
432 }
433 }
434
435 async_transaction_t *trans = async_transaction_create(callid);
436 if (trans == NULL) {
437 async_answer_0(callid, ENOMEM);
438 free(setup_packet);
439 free(data_buffer);
440 return;
441 }
442 trans->setup_packet = setup_packet;
443 trans->buffer = data_buffer;
444 trans->size = data_buffer_len;
445
446 rc = usb_iface->control_write(device, target, max_packet_size,
447 setup_packet, setup_packet_len,
448 data_buffer, data_buffer_len,
449 callback_out, trans);
450
451 if (rc != EOK) {
452 async_answer_0(callid, rc);
453 async_transaction_destroy(trans);
454 }
455}
456
457
458void remote_usbhc_control_read(device_t *device, void *iface,
459ipc_callid_t callid, ipc_call_t *call)
460{
461 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
462 assert(usb_iface != NULL);
463
464 if (!usb_iface->control_read) {
465 async_answer_0(callid, ENOTSUP);
466 return;
467 }
468
469 usb_target_t target = {
470 .address = DEV_IPC_GET_ARG1(*call),
471 .endpoint = DEV_IPC_GET_ARG2(*call)
472 };
473 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
474
475 int rc;
476
477 void *setup_packet = NULL;
478 size_t setup_packet_len = 0;
479 size_t data_len = 0;
480
481 rc = async_data_write_accept(&setup_packet, false,
482 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
483 if (rc != EOK) {
484 async_answer_0(callid, rc);
485 return;
486 }
487
488 ipc_callid_t data_callid;
489 if (!async_data_read_receive(&data_callid, &data_len)) {
490 async_answer_0(callid, EPARTY);
491 free(setup_packet);
492 return;
493 }
494
495 async_transaction_t *trans = async_transaction_create(callid);
496 if (trans == NULL) {
497 async_answer_0(callid, ENOMEM);
498 free(setup_packet);
499 return;
500 }
501 trans->data_caller = data_callid;
502 trans->setup_packet = setup_packet;
503 trans->size = data_len;
504 trans->buffer = malloc(data_len);
505 if (trans->buffer == NULL) {
506 async_answer_0(callid, ENOMEM);
507 async_transaction_destroy(trans);
508 return;
509 }
510
511 rc = usb_iface->control_read(device, target, max_packet_size,
512 setup_packet, setup_packet_len,
513 trans->buffer, trans->size,
514 callback_in, trans);
515
516 if (rc != EOK) {
517 async_answer_0(callid, rc);
518 async_transaction_destroy(trans);
519 }
520}
521
522
523
524/**
525 * @}
526 */
Note: See TracBrowser for help on using the repository browser.