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

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

Merge mainline changes (DDF refactoring)

This merge includes DDF refactoring that brought multifunctional devices
(i.e. ddf_dev_t and ddf_fun_t). Please, see ticket #295 at HelenOS
upstream Trac.

The conflicts themselves were easy to solve (merely several renamings).

Changes to USB subsystem:

  • drivers uses ddf_dev_t and ddf_fun_t
  • different signatures of many library functions
  • several hacks around communication with parent device (now the communication is clearer and somehow what we have now is hack about other hacks)
    • will repair and clean later
  • maybe added some extra debugging messages (the diff has about 240K, and I admit I have no energy to double check that)

WARNING:

  • the diff is VERY long, recommended is viewing partial diffs of the merge (i.e. merges in mainline branch that lead to the parent one)
  • merging with your branches might involve huge renamings, sorry, no other way is possible

BUGS:

  • hub driver will not work (no function created)

GOOD NEWS:

  • QEMU keyboard seems to work with QEMU 0.13 and 0.14
  • we are up-to-date with mainline again
  • 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#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_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
54static void remote_usbhc_request_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
55static void remote_usbhc_bind_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
56static void remote_usbhc_release_address(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_reserve_default_address,
62 remote_usbhc_release_default_address,
63
64 remote_usbhc_request_address,
65 remote_usbhc_bind_address,
66 remote_usbhc_release_address,
67
68 remote_usbhc_interrupt_out,
69 remote_usbhc_interrupt_in,
70
71 remote_usbhc_bulk_out,
72 remote_usbhc_bulk_in,
73
74 remote_usbhc_control_write,
75 remote_usbhc_control_read
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_reserve_default_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->reserve_default_address) {
132 async_answer_0(callid, ENOTSUP);
133 return;
134 }
135
136 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
137
138 int rc = usb_iface->reserve_default_address(fun, speed);
139
140 async_answer_0(callid, rc);
141}
142
143void remote_usbhc_release_default_address(ddf_fun_t *fun, void *iface,
144 ipc_callid_t callid, ipc_call_t *call)
145{
146 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
147
148 if (!usb_iface->release_default_address) {
149 async_answer_0(callid, ENOTSUP);
150 return;
151 }
152
153 int rc = usb_iface->release_default_address(fun);
154
155 async_answer_0(callid, rc);
156}
157
158void remote_usbhc_request_address(ddf_fun_t *fun, void *iface,
159 ipc_callid_t callid, ipc_call_t *call)
160{
161 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
162
163 if (!usb_iface->request_address) {
164 async_answer_0(callid, ENOTSUP);
165 return;
166 }
167
168 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
169
170 usb_address_t address;
171 int rc = usb_iface->request_address(fun, speed, &address);
172 if (rc != EOK) {
173 async_answer_0(callid, rc);
174 } else {
175 async_answer_1(callid, EOK, (sysarg_t) address);
176 }
177}
178
179void remote_usbhc_bind_address(ddf_fun_t *fun, void *iface,
180 ipc_callid_t callid, ipc_call_t *call)
181{
182 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
183
184 if (!usb_iface->bind_address) {
185 async_answer_0(callid, ENOTSUP);
186 return;
187 }
188
189 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
190 devman_handle_t handle = (devman_handle_t) DEV_IPC_GET_ARG2(*call);
191
192 int rc = usb_iface->bind_address(fun, address, handle);
193
194 async_answer_0(callid, rc);
195}
196
197void remote_usbhc_release_address(ddf_fun_t *fun, void *iface,
198 ipc_callid_t callid, ipc_call_t *call)
199{
200 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
201
202 if (!usb_iface->release_address) {
203 async_answer_0(callid, ENOTSUP);
204 return;
205 }
206
207 usb_address_t address = (usb_address_t) DEV_IPC_GET_ARG1(*call);
208
209 int rc = usb_iface->release_address(fun, address);
210
211 async_answer_0(callid, rc);
212}
213
214
215static void callback_out(ddf_fun_t *fun,
216 int outcome, void *arg)
217{
218 async_transaction_t *trans = (async_transaction_t *)arg;
219
220 async_answer_0(trans->caller, outcome);
221
222 async_transaction_destroy(trans);
223}
224
225static void callback_in(ddf_fun_t *fun,
226 int outcome, size_t actual_size, void *arg)
227{
228 async_transaction_t *trans = (async_transaction_t *)arg;
229
230 if (outcome != EOK) {
231 async_answer_0(trans->caller, outcome);
232 if (trans->data_caller) {
233 async_answer_0(trans->data_caller, EINTR);
234 }
235 async_transaction_destroy(trans);
236 return;
237 }
238
239 trans->size = actual_size;
240
241 if (trans->data_caller) {
242 async_data_read_finalize(trans->data_caller,
243 trans->buffer, actual_size);
244 }
245
246 async_answer_0(trans->caller, EOK);
247
248 async_transaction_destroy(trans);
249}
250
251/** Process an outgoing transfer (both OUT and SETUP).
252 *
253 * @param device Target device.
254 * @param callid Initiating caller.
255 * @param call Initiating call.
256 * @param transfer_func Transfer function (might be NULL).
257 */
258static void remote_usbhc_out_transfer(ddf_fun_t *fun,
259 ipc_callid_t callid, ipc_call_t *call,
260 usbhc_iface_transfer_out_t transfer_func)
261{
262 if (!transfer_func) {
263 async_answer_0(callid, ENOTSUP);
264 return;
265 }
266
267 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
268 usb_target_t target = {
269 .address = DEV_IPC_GET_ARG1(*call),
270 .endpoint = DEV_IPC_GET_ARG2(*call)
271 };
272
273 size_t len = 0;
274 void *buffer = NULL;
275
276 int rc = async_data_write_accept(&buffer, false,
277 1, USB_MAX_PAYLOAD_SIZE,
278 0, &len);
279
280 if (rc != EOK) {
281 async_answer_0(callid, rc);
282 return;
283 }
284
285 async_transaction_t *trans = async_transaction_create(callid);
286 if (trans == NULL) {
287 if (buffer != NULL) {
288 free(buffer);
289 }
290 async_answer_0(callid, ENOMEM);
291 return;
292 }
293
294 trans->buffer = buffer;
295 trans->size = len;
296
297 rc = transfer_func(fun, target, max_packet_size,
298 buffer, len,
299 callback_out, trans);
300
301 if (rc != EOK) {
302 async_answer_0(callid, rc);
303 async_transaction_destroy(trans);
304 }
305}
306
307/** Process an incoming transfer.
308 *
309 * @param device Target device.
310 * @param callid Initiating caller.
311 * @param call Initiating call.
312 * @param transfer_func Transfer function (might be NULL).
313 */
314static void remote_usbhc_in_transfer(ddf_fun_t *fun,
315 ipc_callid_t callid, ipc_call_t *call,
316 usbhc_iface_transfer_in_t transfer_func)
317{
318 if (!transfer_func) {
319 async_answer_0(callid, ENOTSUP);
320 return;
321 }
322
323 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
324 usb_target_t target = {
325 .address = DEV_IPC_GET_ARG1(*call),
326 .endpoint = DEV_IPC_GET_ARG2(*call)
327 };
328
329 size_t len;
330 ipc_callid_t data_callid;
331 if (!async_data_read_receive(&data_callid, &len)) {
332 async_answer_0(callid, EPARTY);
333 return;
334 }
335
336 async_transaction_t *trans = async_transaction_create(callid);
337 if (trans == NULL) {
338 async_answer_0(callid, ENOMEM);
339 return;
340 }
341 trans->data_caller = data_callid;
342 trans->buffer = malloc(len);
343 trans->size = len;
344
345 int rc = transfer_func(fun, target, max_packet_size,
346 trans->buffer, len,
347 callback_in, trans);
348
349 if (rc != EOK) {
350 async_answer_0(callid, rc);
351 async_transaction_destroy(trans);
352 }
353}
354
355void remote_usbhc_interrupt_out(ddf_fun_t *fun, void *iface,
356 ipc_callid_t callid, ipc_call_t *call)
357{
358 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
359 assert(usb_iface != NULL);
360
361 return remote_usbhc_out_transfer(fun, callid, call,
362 usb_iface->interrupt_out);
363}
364
365void remote_usbhc_interrupt_in(ddf_fun_t *fun, void *iface,
366 ipc_callid_t callid, ipc_call_t *call)
367{
368 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
369 assert(usb_iface != NULL);
370
371 return remote_usbhc_in_transfer(fun, callid, call,
372 usb_iface->interrupt_in);
373}
374
375void remote_usbhc_bulk_out(ddf_fun_t *fun, void *iface,
376 ipc_callid_t callid, ipc_call_t *call)
377{
378 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
379 assert(usb_iface != NULL);
380
381 return remote_usbhc_out_transfer(fun, callid, call,
382 usb_iface->bulk_out);
383}
384
385void remote_usbhc_bulk_in(ddf_fun_t *fun, void *iface,
386 ipc_callid_t callid, ipc_call_t *call)
387{
388 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
389 assert(usb_iface != NULL);
390
391 return remote_usbhc_in_transfer(fun, callid, call,
392 usb_iface->bulk_in);
393}
394
395void remote_usbhc_control_write(ddf_fun_t *fun, void *iface,
396ipc_callid_t callid, ipc_call_t *call)
397{
398 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
399 assert(usb_iface != NULL);
400
401 if (!usb_iface->control_write) {
402 async_answer_0(callid, ENOTSUP);
403 return;
404 }
405
406 usb_target_t target = {
407 .address = DEV_IPC_GET_ARG1(*call),
408 .endpoint = DEV_IPC_GET_ARG2(*call)
409 };
410 size_t data_buffer_len = DEV_IPC_GET_ARG3(*call);
411 size_t max_packet_size = DEV_IPC_GET_ARG4(*call);
412
413 int rc;
414
415 void *setup_packet = NULL;
416 void *data_buffer = NULL;
417 size_t setup_packet_len = 0;
418
419 rc = async_data_write_accept(&setup_packet, false,
420 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
421 if (rc != EOK) {
422 async_answer_0(callid, rc);
423 return;
424 }
425
426 if (data_buffer_len > 0) {
427 rc = async_data_write_accept(&data_buffer, false,
428 1, USB_MAX_PAYLOAD_SIZE, 0, &data_buffer_len);
429 if (rc != EOK) {
430 async_answer_0(callid, rc);
431 free(setup_packet);
432 return;
433 }
434 }
435
436 async_transaction_t *trans = async_transaction_create(callid);
437 if (trans == NULL) {
438 async_answer_0(callid, ENOMEM);
439 free(setup_packet);
440 free(data_buffer);
441 return;
442 }
443 trans->setup_packet = setup_packet;
444 trans->buffer = data_buffer;
445 trans->size = data_buffer_len;
446
447 rc = usb_iface->control_write(fun, target, max_packet_size,
448 setup_packet, setup_packet_len,
449 data_buffer, data_buffer_len,
450 callback_out, trans);
451
452 if (rc != EOK) {
453 async_answer_0(callid, rc);
454 async_transaction_destroy(trans);
455 }
456}
457
458
459void remote_usbhc_control_read(ddf_fun_t *fun, void *iface,
460ipc_callid_t callid, ipc_call_t *call)
461{
462 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
463 assert(usb_iface != NULL);
464
465 if (!usb_iface->control_read) {
466 async_answer_0(callid, ENOTSUP);
467 return;
468 }
469
470 usb_target_t target = {
471 .address = DEV_IPC_GET_ARG1(*call),
472 .endpoint = DEV_IPC_GET_ARG2(*call)
473 };
474 size_t max_packet_size = DEV_IPC_GET_ARG3(*call);
475
476 int rc;
477
478 void *setup_packet = NULL;
479 size_t setup_packet_len = 0;
480 size_t data_len = 0;
481
482 rc = async_data_write_accept(&setup_packet, false,
483 1, USB_MAX_PAYLOAD_SIZE, 0, &setup_packet_len);
484 if (rc != EOK) {
485 async_answer_0(callid, rc);
486 return;
487 }
488
489 ipc_callid_t data_callid;
490 if (!async_data_read_receive(&data_callid, &data_len)) {
491 async_answer_0(callid, EPARTY);
492 free(setup_packet);
493 return;
494 }
495
496 async_transaction_t *trans = async_transaction_create(callid);
497 if (trans == NULL) {
498 async_answer_0(callid, ENOMEM);
499 free(setup_packet);
500 return;
501 }
502 trans->data_caller = data_callid;
503 trans->setup_packet = setup_packet;
504 trans->size = data_len;
505 trans->buffer = malloc(data_len);
506 if (trans->buffer == NULL) {
507 async_answer_0(callid, ENOMEM);
508 async_transaction_destroy(trans);
509 return;
510 }
511
512 rc = usb_iface->control_read(fun, target, max_packet_size,
513 setup_packet, setup_packet_len,
514 trans->buffer, trans->size,
515 callback_in, trans);
516
517 if (rc != EOK) {
518 async_answer_0(callid, rc);
519 async_transaction_destroy(trans);
520 }
521}
522
523
524
525/**
526 * @}
527 */
Note: See TracBrowser for help on using the repository browser.