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

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

Add control transfer to USBHC interface

The USBHC interface (of DDF) knows how to handle control transfers
(both read and write).

  • Property mode set to 100644
File size: 11.3 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 libdrv
30 * @{
31 */
32/** @file
33 */
34
35#include <ipc/ipc.h>
36#include <async.h>
37#include <errno.h>
38
39#include "usbhc_iface.h"
40#include "driver.h"
41
42#define USB_MAX_PAYLOAD_SIZE 1020
43
44static void remote_usbhc_get_address(device_t *, void *, ipc_callid_t, ipc_call_t *);
45static void remote_usbhc_get_buffer(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_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
49static void remote_usbhc_control_write_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
50static void remote_usbhc_control_write_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
51static void remote_usbhc_control_read_setup(device_t *, void *, ipc_callid_t, ipc_call_t *);
52static void remote_usbhc_control_read_data(device_t *, void *, ipc_callid_t, ipc_call_t *);
53static void remote_usbhc_control_read_status(device_t *, void *, ipc_callid_t, ipc_call_t *);
54//static void remote_usbhc(device_t *, void *, ipc_callid_t, ipc_call_t *);
55
56/** Remote USB interface operations. */
57static remote_iface_func_ptr_t remote_usbhc_iface_ops [] = {
58 remote_usbhc_get_address,
59 remote_usbhc_get_buffer,
60 remote_usbhc_interrupt_out,
61 remote_usbhc_interrupt_in,
62 remote_usbhc_control_write_setup,
63 remote_usbhc_control_write_data,
64 remote_usbhc_control_write_status,
65 remote_usbhc_control_read_setup,
66 remote_usbhc_control_read_data,
67 remote_usbhc_control_read_status
68};
69
70/** Remote USB interface structure.
71 */
72remote_iface_t remote_usbhc_iface = {
73 .method_count = sizeof(remote_usbhc_iface_ops) /
74 sizeof(remote_usbhc_iface_ops[0]),
75 .methods = remote_usbhc_iface_ops
76};
77
78typedef struct {
79 ipc_callid_t caller;
80 void *buffer;
81 size_t size;
82} async_transaction_t;
83
84void remote_usbhc_get_address(device_t *device, void *iface,
85 ipc_callid_t callid, ipc_call_t *call)
86{
87 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
88
89 if (!usb_iface->tell_address) {
90 ipc_answer_0(callid, ENOTSUP);
91 return;
92 }
93
94 devman_handle_t handle = IPC_GET_ARG1(*call);
95
96 usb_address_t address;
97 int rc = usb_iface->tell_address(device, handle, &address);
98 if (rc != EOK) {
99 ipc_answer_0(callid, rc);
100 } else {
101 ipc_answer_1(callid, EOK, address);
102 }
103}
104
105void remote_usbhc_get_buffer(device_t *device, void *iface,
106 ipc_callid_t callid, ipc_call_t *call)
107{
108 ipcarg_t buffer_hash = IPC_GET_ARG1(*call);
109 async_transaction_t * trans = (async_transaction_t *)buffer_hash;
110 if (trans == NULL) {
111 ipc_answer_0(callid, ENOENT);
112 return;
113 }
114 if (trans->buffer == NULL) {
115 ipc_answer_0(callid, EINVAL);
116 free(trans);
117 return;
118 }
119
120 ipc_callid_t cid;
121 size_t accepted_size;
122 if (!async_data_read_receive(&cid, &accepted_size)) {
123 ipc_answer_0(callid, EINVAL);
124 return;
125 }
126
127 if (accepted_size > trans->size) {
128 accepted_size = trans->size;
129 }
130 async_data_read_finalize(callid, trans->buffer, accepted_size);
131
132 ipc_answer_1(callid, EOK, accepted_size);
133
134 free(trans->buffer);
135 free(trans);
136}
137
138
139static void callback_out(device_t *device,
140 usb_transaction_outcome_t outcome, void *arg)
141{
142 async_transaction_t *trans = (async_transaction_t *)arg;
143
144 // FIXME - answer according to outcome
145 ipc_answer_0(trans->caller, EOK);
146
147 free(trans);
148}
149
150static void callback_in(device_t *device,
151 usb_transaction_outcome_t outcome, size_t actual_size, void *arg)
152{
153 async_transaction_t *trans = (async_transaction_t *)arg;
154
155 // FIXME - answer according to outcome
156 ipc_answer_1(trans->caller, EOK, (ipcarg_t)trans);
157
158 trans->size = actual_size;
159}
160
161void remote_usbhc_interrupt_out(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 size_t expected_len = IPC_GET_ARG3(*call);
167 usb_target_t target = {
168 .address = IPC_GET_ARG1(*call),
169 .endpoint = IPC_GET_ARG2(*call)
170 };
171
172 size_t len = 0;
173 void *buffer = NULL;
174 if (expected_len > 0) {
175 int rc = async_data_write_accept(&buffer, false,
176 1, USB_MAX_PAYLOAD_SIZE,
177 0, &len);
178
179 if (rc != EOK) {
180 ipc_answer_0(callid, rc);
181 return;
182 }
183 }
184
185 if (!usb_iface->interrupt_out) {
186 ipc_answer_0(callid, ENOTSUP);
187 return;
188 }
189
190 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
191 trans->caller = callid;
192 trans->buffer = NULL;
193 trans->size = 0;
194
195 int rc = usb_iface->interrupt_out(device, target, buffer, len,
196 callback_out, trans);
197
198 if (rc != EOK) {
199 ipc_answer_0(callid, rc);
200 free(trans);
201 }
202}
203
204void remote_usbhc_interrupt_in(device_t *device, void *iface,
205 ipc_callid_t callid, ipc_call_t *call)
206{
207 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
208
209 size_t len = IPC_GET_ARG3(*call);
210 usb_target_t target = {
211 .address = IPC_GET_ARG1(*call),
212 .endpoint = IPC_GET_ARG2(*call)
213 };
214
215 if (!usb_iface->interrupt_in) {
216 ipc_answer_0(callid, ENOTSUP);
217 return;
218 }
219
220 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
221 trans->caller = callid;
222 trans->buffer = malloc(len);
223 trans->size = len;
224
225 int rc = usb_iface->interrupt_in(device, target, trans->buffer, len,
226 callback_in, trans);
227
228 if (rc != EOK) {
229 ipc_answer_0(callid, rc);
230 free(trans->buffer);
231 free(trans);
232 }
233}
234
235void remote_usbhc_control_write_setup(device_t *device, void *iface,
236 ipc_callid_t callid, ipc_call_t *call)
237{
238 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
239
240 size_t expected_len = IPC_GET_ARG3(*call);
241 usb_target_t target = {
242 .address = IPC_GET_ARG1(*call),
243 .endpoint = IPC_GET_ARG2(*call)
244 };
245
246 size_t len = 0;
247 void *buffer = NULL;
248 if (expected_len > 0) {
249 int rc = async_data_write_accept(&buffer, false,
250 1, USB_MAX_PAYLOAD_SIZE,
251 0, &len);
252
253 if (rc != EOK) {
254 ipc_answer_0(callid, rc);
255 return;
256 }
257 }
258
259 if (!usb_iface->control_write_setup) {
260 ipc_answer_0(callid, ENOTSUP);
261 return;
262 }
263
264 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
265 trans->caller = callid;
266 trans->buffer = NULL;
267 trans->size = 0;
268
269 int rc = usb_iface->control_write_setup(device, target, buffer, len,
270 callback_out, trans);
271
272 if (rc != EOK) {
273 ipc_answer_0(callid, rc);
274 free(trans);
275 }
276}
277
278void remote_usbhc_control_write_data(device_t *device, void *iface,
279 ipc_callid_t callid, ipc_call_t *call)
280{
281 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
282
283 size_t expected_len = IPC_GET_ARG3(*call);
284 usb_target_t target = {
285 .address = IPC_GET_ARG1(*call),
286 .endpoint = IPC_GET_ARG2(*call)
287 };
288
289 size_t len = 0;
290 void *buffer = NULL;
291 if (expected_len > 0) {
292 int rc = async_data_write_accept(&buffer, false,
293 1, USB_MAX_PAYLOAD_SIZE,
294 0, &len);
295
296 if (rc != EOK) {
297 ipc_answer_0(callid, rc);
298 return;
299 }
300 }
301
302 if (!usb_iface->control_write_data) {
303 ipc_answer_0(callid, ENOTSUP);
304 return;
305 }
306
307 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
308 trans->caller = callid;
309 trans->buffer = NULL;
310 trans->size = 0;
311
312 int rc = usb_iface->control_write_data(device, target, buffer, len,
313 callback_out, trans);
314
315 if (rc != EOK) {
316 ipc_answer_0(callid, rc);
317 free(trans);
318 }
319}
320
321void remote_usbhc_control_write_status(device_t *device, void *iface,
322 ipc_callid_t callid, ipc_call_t *call)
323{
324 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
325
326 usb_target_t target = {
327 .address = IPC_GET_ARG1(*call),
328 .endpoint = IPC_GET_ARG2(*call)
329 };
330
331 if (!usb_iface->control_write_status) {
332 ipc_answer_0(callid, ENOTSUP);
333 return;
334 }
335
336 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
337 trans->caller = callid;
338 trans->buffer = NULL;
339 trans->size = 0;
340
341 int rc = usb_iface->control_write_status(device, target,
342 callback_in, trans);
343
344 if (rc != EOK) {
345 ipc_answer_0(callid, rc);
346 free(trans);
347 }
348}
349
350void remote_usbhc_control_read_setup(device_t *device, void *iface,
351 ipc_callid_t callid, ipc_call_t *call)
352{
353 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
354
355 size_t expected_len = IPC_GET_ARG3(*call);
356 usb_target_t target = {
357 .address = IPC_GET_ARG1(*call),
358 .endpoint = IPC_GET_ARG2(*call)
359 };
360
361 size_t len = 0;
362 void *buffer = NULL;
363 if (expected_len > 0) {
364 int rc = async_data_write_accept(&buffer, false,
365 1, USB_MAX_PAYLOAD_SIZE,
366 0, &len);
367
368 if (rc != EOK) {
369 ipc_answer_0(callid, rc);
370 return;
371 }
372 }
373
374 if (!usb_iface->control_read_setup) {
375 ipc_answer_0(callid, ENOTSUP);
376 return;
377 }
378
379 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
380 trans->caller = callid;
381 trans->buffer = NULL;
382 trans->size = 0;
383
384 int rc = usb_iface->control_read_setup(device, target, buffer, len,
385 callback_out, trans);
386
387 if (rc != EOK) {
388 ipc_answer_0(callid, rc);
389 free(trans);
390 }
391}
392
393void remote_usbhc_control_read_data(device_t *device, void *iface,
394 ipc_callid_t callid, ipc_call_t *call)
395{
396 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
397
398 size_t len = IPC_GET_ARG3(*call);
399 usb_target_t target = {
400 .address = IPC_GET_ARG1(*call),
401 .endpoint = IPC_GET_ARG2(*call)
402 };
403
404 if (!usb_iface->control_read_data) {
405 ipc_answer_0(callid, ENOTSUP);
406 return;
407 }
408
409 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
410 trans->caller = callid;
411 trans->buffer = malloc(len);
412 trans->size = len;
413
414 int rc = usb_iface->control_read_data(device, target, trans->buffer, len,
415 callback_in, trans);
416
417 if (rc != EOK) {
418 ipc_answer_0(callid, rc);
419 free(trans->buffer);
420 free(trans);
421 }
422}
423
424void remote_usbhc_control_read_status(device_t *device, void *iface,
425 ipc_callid_t callid, ipc_call_t *call)
426{
427 usbhc_iface_t *usb_iface = (usbhc_iface_t *) iface;
428
429 usb_target_t target = {
430 .address = IPC_GET_ARG1(*call),
431 .endpoint = IPC_GET_ARG2(*call)
432 };
433
434 if (!usb_iface->control_read_status) {
435 ipc_answer_0(callid, ENOTSUP);
436 return;
437 }
438
439 async_transaction_t *trans = malloc(sizeof(async_transaction_t));
440 trans->caller = callid;
441 trans->buffer = NULL;
442 trans->size = 0;
443
444 int rc = usb_iface->control_read_status(device, target,
445 callback_out, trans);
446
447 if (rc != EOK) {
448 ipc_answer_0(callid, rc);
449 free(trans);
450 }
451}
452
453
454
455/**
456 * @}
457 */
Note: See TracBrowser for help on using the repository browser.