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

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

Removal of remote parts of old API

The control transfer callbacks for each part of the transfer
(i.e. for setup, data and status) were completely removed.

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