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

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

USBHC iface: remove default address reservation

This functionality is now handled via endpoint registration.

Also removed references to this function from hub driver. Either they
were unreachable or would break things anyway.

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