source: mainline/uspace/lib/drv/generic/remote_usb.c@ 1298a8fa

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1298a8fa was 1298a8fa, checked in by Jan Vesely <jano.vesely@…>, 12 years ago

libdrv: Allow parallel session when connecting directly to devman handle.

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * Copyright (c) 2011 Jan Vesely
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libdrv
31 * @{
32 */
33/** @file
34 */
35
36#include <async.h>
37#include <macros.h>
38#include <errno.h>
39#include <devman.h>
40
41#include "usb_iface.h"
42#include "ddf/driver.h"
43
44
45usb_dev_session_t *usb_dev_connect(devman_handle_t handle)
46{
47 return devman_device_connect(EXCHANGE_PARALLEL, handle, IPC_FLAG_BLOCKING);
48}
49
50usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
51{
52 // TODO All usb requests are atomic so this is safe,
53 // it will need to change once USING EXCHANGE PARALLEL is safe with
54 // devman_parent_device_connect
55 return devman_parent_device_connect(EXCHANGE_ATOMIC,
56 ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
57}
58
59void usb_dev_disconnect(usb_dev_session_t *sess)
60{
61 if (sess)
62 async_hangup(sess);
63}
64
65typedef enum {
66 IPC_M_USB_GET_MY_ADDRESS,
67 IPC_M_USB_GET_MY_INTERFACE,
68 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
69 IPC_M_USB_GET_DEVICE_HANDLE,
70 IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
71 IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
72 IPC_M_USB_DEVICE_ENUMERATE,
73 IPC_M_USB_DEVICE_REMOVE,
74 IPC_M_USB_REGISTER_ENDPOINT,
75 IPC_M_USB_UNREGISTER_ENDPOINT,
76} usb_iface_funcs_t;
77
78/** Tell USB address assigned to device.
79 * @param exch Vaid IPC exchange
80 * @param address Pointer to address storage place.
81 * @return Error code.
82 *
83 * Exch param is an open communication to device implementing usb_iface.
84 */
85int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
86{
87 sysarg_t addr;
88 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
89 IPC_M_USB_GET_MY_ADDRESS, &addr);
90
91 if (ret == EOK && address != NULL)
92 *address = (usb_address_t) addr;
93 return ret;
94}
95
96/** Tell interface number given device can use.
97 * @param[in] exch IPC communication exchange
98 * @param[in] handle Id of the device
99 * @param[out] usb_iface Assigned USB interface
100 * @return Error code.
101 */
102int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
103{
104 if (!exch)
105 return EBADMEM;
106 sysarg_t iface_no;
107 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
108 IPC_M_USB_GET_MY_INTERFACE, &iface_no);
109 if (ret == EOK && usb_iface)
110 *usb_iface = (int)iface_no;
111 return ret;
112}
113
114/** Tell devman handle of device host controller.
115 * @param[in] exch IPC communication exchange
116 * @param[out] hc_handle devman handle of the HC used by the target device.
117 * @return Error code.
118 */
119int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
120{
121 if (!exch)
122 return EBADMEM;
123 devman_handle_t h;
124 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
125 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
126 if (ret == EOK && hc_handle)
127 *hc_handle = (devman_handle_t)h;
128 return ret;
129}
130
131/** Tell devman handle of the usb device function.
132 * @param[in] exch IPC communication exchange
133 * @param[out] handle devman handle of the HC used by the target device.
134 * @return Error code.
135 */
136int usb_get_device_handle(async_exch_t *exch, devman_handle_t *handle)
137{
138 devman_handle_t h = 0;
139 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
140 IPC_M_USB_GET_DEVICE_HANDLE, &h);
141 if (ret == EOK && handle)
142 *handle = (devman_handle_t)h;
143 return ret;
144}
145
146/** Reserve default USB address.
147 * @param[in] exch IPC communication exchange
148 * @param[in] speed Communication speed of the newly attached device
149 * @return Error code.
150 */
151int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
152{
153 if (!exch)
154 return EBADMEM;
155 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
156 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
157}
158
159/** Release default USB address.
160 * @param[in] exch IPC communication exchange
161 * @return Error code.
162 */
163int usb_release_default_address(async_exch_t *exch)
164{
165 if (!exch)
166 return EBADMEM;
167 return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
168 IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
169}
170
171/** Trigger USB device enumeration
172 * @param[in] exch IPC communication exchange
173 * @param[out] handle Identifier of the newly added device (if successful)
174 * @return Error code.
175 */
176int usb_device_enumerate(async_exch_t *exch, usb_device_handle_t *handle)
177{
178 if (!exch || !handle)
179 return EBADMEM;
180 sysarg_t h;
181 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
182 IPC_M_USB_DEVICE_ENUMERATE, &h);
183 if (ret == EOK)
184 *handle = (usb_device_handle_t)h;
185 return ret;
186}
187
188/** Trigger USB device enumeration
189 * @param[in] exch IPC communication exchange
190 * @param[in] handle Identifier of the device
191 * @return Error code.
192 */
193int usb_device_remove(async_exch_t *exch, usb_device_handle_t handle)
194{
195 if (!exch)
196 return EBADMEM;
197 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
198 IPC_M_USB_DEVICE_REMOVE, handle);
199}
200
201int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
202 usb_transfer_type_t type, usb_direction_t direction,
203 size_t mps, unsigned interval)
204{
205 if (!exch)
206 return EBADMEM;
207#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
208
209 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
210 IPC_M_USB_REGISTER_ENDPOINT, endpoint,
211 _PACK2(type, direction), _PACK2(mps, interval));
212
213#undef _PACK2
214}
215
216int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
217 usb_direction_t direction)
218{
219 if (!exch)
220 return EBADMEM;
221 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
222 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
223}
224
225static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
226static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
227static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
228static void remote_usb_get_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
229
230static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
231static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
232static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
233static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
234static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
235static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
236
237/** Remote USB interface operations. */
238static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
239 [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
240 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
241 [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
242 [IPC_M_USB_GET_DEVICE_HANDLE] = remote_usb_get_device_handle,
243 [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
244 [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
245 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
246 [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
247 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
248 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
249};
250
251/** Remote USB interface structure.
252 */
253remote_iface_t remote_usb_iface = {
254 .method_count = ARRAY_SIZE(remote_usb_iface_ops),
255 .methods = remote_usb_iface_ops,
256};
257
258
259void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
260 ipc_callid_t callid, ipc_call_t *call)
261{
262 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
263
264 if (usb_iface->get_my_address == NULL) {
265 async_answer_0(callid, ENOTSUP);
266 return;
267 }
268
269 usb_address_t address;
270 const int ret = usb_iface->get_my_address(fun, &address);
271 if (ret != EOK) {
272 async_answer_0(callid, ret);
273 } else {
274 async_answer_1(callid, EOK, address);
275 }
276}
277
278void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
279 ipc_callid_t callid, ipc_call_t *call)
280{
281 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
282
283 if (usb_iface->get_my_interface == NULL) {
284 async_answer_0(callid, ENOTSUP);
285 return;
286 }
287
288 int iface_no;
289 const int ret = usb_iface->get_my_interface(fun, &iface_no);
290 if (ret != EOK) {
291 async_answer_0(callid, ret);
292 } else {
293 async_answer_1(callid, EOK, iface_no);
294 }
295}
296
297void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
298 ipc_callid_t callid, ipc_call_t *call)
299{
300 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
301
302 if (usb_iface->get_hc_handle == NULL) {
303 async_answer_0(callid, ENOTSUP);
304 return;
305 }
306
307 devman_handle_t handle;
308 const int ret = usb_iface->get_hc_handle(fun, &handle);
309 if (ret != EOK) {
310 async_answer_0(callid, ret);
311 }
312
313 async_answer_1(callid, EOK, (sysarg_t) handle);
314}
315
316void remote_usb_get_device_handle(ddf_fun_t *fun, void *iface,
317 ipc_callid_t callid, ipc_call_t *call)
318{
319 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
320
321 if (usb_iface->get_device_handle == NULL) {
322 async_answer_0(callid, ENOTSUP);
323 return;
324 }
325
326 devman_handle_t handle;
327 const int ret = usb_iface->get_device_handle(fun, &handle);
328 if (ret != EOK) {
329 async_answer_0(callid, ret);
330 }
331
332 async_answer_1(callid, EOK, (sysarg_t) handle);
333}
334
335void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
336 ipc_callid_t callid, ipc_call_t *call)
337{
338 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
339
340 if (usb_iface->reserve_default_address == NULL) {
341 async_answer_0(callid, ENOTSUP);
342 return;
343 }
344
345 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
346 const int ret = usb_iface->reserve_default_address(fun, speed);
347 async_answer_0(callid, ret);
348}
349
350void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
351 ipc_callid_t callid, ipc_call_t *call)
352{
353 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
354
355 if (usb_iface->release_default_address == NULL) {
356 async_answer_0(callid, ENOTSUP);
357 return;
358 }
359
360 const int ret = usb_iface->release_default_address(fun);
361 async_answer_0(callid, ret);
362}
363
364static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
365 ipc_callid_t callid, ipc_call_t *call)
366{
367 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
368
369 if (usb_iface->device_enumerate == NULL) {
370 async_answer_0(callid, ENOTSUP);
371 return;
372 }
373
374 usb_device_handle_t handle = 0;
375 const int ret = usb_iface->device_enumerate(fun, &handle);
376 if (ret != EOK) {
377 async_answer_0(callid, ret);
378 }
379
380 async_answer_1(callid, EOK, (sysarg_t) handle);
381}
382
383static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
384 ipc_callid_t callid, ipc_call_t *call)
385{
386 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
387
388 if (usb_iface->device_remove == NULL) {
389 async_answer_0(callid, ENOTSUP);
390 return;
391 }
392
393 usb_device_handle_t handle = DEV_IPC_GET_ARG1(*call);
394 const int ret = usb_iface->device_remove(fun, handle);
395 async_answer_0(callid, ret);
396}
397
398static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
399 ipc_callid_t callid, ipc_call_t *call)
400{
401 usb_iface_t *usb_iface = (usb_iface_t *) iface;
402
403 if (!usb_iface->register_endpoint) {
404 async_answer_0(callid, ENOTSUP);
405 return;
406 }
407
408#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
409 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
410#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
411 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
412
413 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
414
415 _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
416 _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
417
418 _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
419 _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
420
421#undef _INIT_FROM_HIGH_DATA2
422#undef _INIT_FROM_LOW_DATA2
423
424 const int ret = usb_iface->register_endpoint(fun, endpoint,
425 transfer_type, direction, max_packet_size, interval);
426
427 async_answer_0(callid, ret);
428}
429
430static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
431 ipc_callid_t callid, ipc_call_t *call)
432{
433 usb_iface_t *usb_iface = (usb_iface_t *) iface;
434
435 if (!usb_iface->unregister_endpoint) {
436 async_answer_0(callid, ENOTSUP);
437 return;
438 }
439
440 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
441 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
442
443 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
444
445 async_answer_0(callid, rc);
446}
447/**
448 * @}
449 */
Note: See TracBrowser for help on using the repository browser.