source: mainline/uspace/lib/drv/generic/remote_usb.c@ 9d15d1b

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

libdrv: add device handle query

  • Property mode set to 100644
File size: 13.3 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 // TODO All usb requests are atomic so this is safe,
48 // it will need to change once USING EXCHANGE PARALLEL is safe with
49 // devman_device_connect
50 return devman_device_connect(EXCHANGE_ATOMIC, handle, IPC_FLAG_BLOCKING);
51}
52
53usb_dev_session_t *usb_dev_connect_to_self(ddf_dev_t *dev)
54{
55 // TODO All usb requests are atomic so this is safe,
56 // it will need to change once USING EXCHANGE PARALLEL is safe with
57 // devman_parent_device_connect
58 return devman_parent_device_connect(EXCHANGE_ATOMIC,
59 ddf_dev_get_handle(dev), IPC_FLAG_BLOCKING);
60}
61
62void usb_dev_disconnect(usb_dev_session_t *sess)
63{
64 if (sess)
65 async_hangup(sess);
66}
67
68typedef enum {
69 IPC_M_USB_GET_MY_ADDRESS,
70 IPC_M_USB_GET_MY_INTERFACE,
71 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE,
72 IPC_M_USB_GET_DEVICE_HANDLE,
73 IPC_M_USB_RESERVE_DEFAULT_ADDRESS,
74 IPC_M_USB_RELEASE_DEFAULT_ADDRESS,
75 IPC_M_USB_DEVICE_ENUMERATE,
76 IPC_M_USB_DEVICE_REMOVE,
77 IPC_M_USB_REGISTER_ENDPOINT,
78 IPC_M_USB_UNREGISTER_ENDPOINT,
79} usb_iface_funcs_t;
80
81/** Tell USB address assigned to device.
82 * @param exch Vaid IPC exchange
83 * @param address Pointer to address storage place.
84 * @return Error code.
85 *
86 * Exch param is an open communication to device implementing usb_iface.
87 */
88int usb_get_my_address(async_exch_t *exch, usb_address_t *address)
89{
90 sysarg_t addr;
91 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
92 IPC_M_USB_GET_MY_ADDRESS, &addr);
93
94 if (ret == EOK && address != NULL)
95 *address = (usb_address_t) addr;
96 return ret;
97}
98
99/** Tell interface number given device can use.
100 * @param[in] exch IPC communication exchange
101 * @param[in] handle Id of the device
102 * @param[out] usb_iface Assigned USB interface
103 * @return Error code.
104 */
105int usb_get_my_interface(async_exch_t *exch, int *usb_iface)
106{
107 if (!exch)
108 return EBADMEM;
109 sysarg_t iface_no;
110 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
111 IPC_M_USB_GET_MY_INTERFACE, &iface_no);
112 if (ret == EOK && usb_iface)
113 *usb_iface = (int)iface_no;
114 return ret;
115}
116
117/** Tell devman handle of device host controller.
118 * @param[in] exch IPC communication exchange
119 * @param[out] hc_handle devman handle of the HC used by the target device.
120 * @return Error code.
121 */
122int usb_get_hc_handle(async_exch_t *exch, devman_handle_t *hc_handle)
123{
124 if (!exch)
125 return EBADMEM;
126 devman_handle_t h;
127 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
128 IPC_M_USB_GET_HOST_CONTROLLER_HANDLE, &h);
129 if (ret == EOK && hc_handle)
130 *hc_handle = (devman_handle_t)h;
131 return ret;
132}
133
134/** Tell devman handle of the usb device function.
135 * @param[in] exch IPC communication exchange
136 * @param[out] handle devman handle of the HC used by the target device.
137 * @return Error code.
138 */
139int usb_get_device_handle(async_exch_t *exch, devman_handle_t *handle)
140{
141 devman_handle_t h = 0;
142 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
143 IPC_M_USB_GET_DEVICE_HANDLE, &h);
144 if (ret == EOK && handle)
145 *handle = (devman_handle_t)h;
146 return ret;
147}
148
149/** Reserve default USB address.
150 * @param[in] exch IPC communication exchange
151 * @param[in] speed Communication speed of the newly attached device
152 * @return Error code.
153 */
154int usb_reserve_default_address(async_exch_t *exch, usb_speed_t speed)
155{
156 if (!exch)
157 return EBADMEM;
158 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
159 IPC_M_USB_RESERVE_DEFAULT_ADDRESS, speed);
160}
161
162/** Release default USB address.
163 * @param[in] exch IPC communication exchange
164 * @return Error code.
165 */
166int usb_release_default_address(async_exch_t *exch)
167{
168 if (!exch)
169 return EBADMEM;
170 return async_req_1_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
171 IPC_M_USB_RELEASE_DEFAULT_ADDRESS);
172}
173
174/** Trigger USB device enumeration
175 * @param[in] exch IPC communication exchange
176 * @param[out] handle Identifier of the newly added device (if successful)
177 * @return Error code.
178 */
179int usb_device_enumerate(async_exch_t *exch, usb_device_handle_t *handle)
180{
181 if (!exch || !handle)
182 return EBADMEM;
183 sysarg_t h;
184 const int ret = async_req_1_1(exch, DEV_IFACE_ID(USB_DEV_IFACE),
185 IPC_M_USB_DEVICE_ENUMERATE, &h);
186 if (ret == EOK)
187 *handle = (usb_device_handle_t)h;
188 return ret;
189}
190
191/** Trigger USB device enumeration
192 * @param[in] exch IPC communication exchange
193 * @param[in] handle Identifier of the device
194 * @return Error code.
195 */
196int usb_device_remove(async_exch_t *exch, usb_device_handle_t handle)
197{
198 if (!exch)
199 return EBADMEM;
200 return async_req_2_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
201 IPC_M_USB_DEVICE_REMOVE, handle);
202}
203
204int usb_register_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
205 usb_transfer_type_t type, usb_direction_t direction,
206 size_t mps, unsigned interval)
207{
208 if (!exch)
209 return EBADMEM;
210#define _PACK2(high, low) (((high & 0xffff) << 16) | (low & 0xffff))
211
212 return async_req_4_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
213 IPC_M_USB_REGISTER_ENDPOINT, endpoint,
214 _PACK2(type, direction), _PACK2(mps, interval));
215
216#undef _PACK2
217}
218
219int usb_unregister_endpoint(async_exch_t *exch, usb_endpoint_t endpoint,
220 usb_direction_t direction)
221{
222 if (!exch)
223 return EBADMEM;
224 return async_req_3_0(exch, DEV_IFACE_ID(USB_DEV_IFACE),
225 IPC_M_USB_UNREGISTER_ENDPOINT, endpoint, direction);
226}
227
228static void remote_usb_get_my_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
229static void remote_usb_get_my_interface(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
230static void remote_usb_get_hc_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
231static void remote_usb_get_device_handle(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
232
233static void remote_usb_reserve_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
234static void remote_usb_release_default_address(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
235static void remote_usb_device_enumerate(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
236static void remote_usb_device_remove(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
237static void remote_usb_register_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
238static void remote_usb_unregister_endpoint(ddf_fun_t *, void *, ipc_callid_t, ipc_call_t *);
239
240/** Remote USB interface operations. */
241static remote_iface_func_ptr_t remote_usb_iface_ops [] = {
242 [IPC_M_USB_GET_MY_ADDRESS] = remote_usb_get_my_address,
243 [IPC_M_USB_GET_MY_INTERFACE] = remote_usb_get_my_interface,
244 [IPC_M_USB_GET_HOST_CONTROLLER_HANDLE] = remote_usb_get_hc_handle,
245 [IPC_M_USB_GET_DEVICE_HANDLE] = remote_usb_get_device_handle,
246 [IPC_M_USB_RESERVE_DEFAULT_ADDRESS] = remote_usb_reserve_default_address,
247 [IPC_M_USB_RELEASE_DEFAULT_ADDRESS] = remote_usb_release_default_address,
248 [IPC_M_USB_DEVICE_ENUMERATE] = remote_usb_device_enumerate,
249 [IPC_M_USB_DEVICE_REMOVE] = remote_usb_device_remove,
250 [IPC_M_USB_REGISTER_ENDPOINT] = remote_usb_register_endpoint,
251 [IPC_M_USB_UNREGISTER_ENDPOINT] = remote_usb_unregister_endpoint,
252};
253
254/** Remote USB interface structure.
255 */
256remote_iface_t remote_usb_iface = {
257 .method_count = ARRAY_SIZE(remote_usb_iface_ops),
258 .methods = remote_usb_iface_ops,
259};
260
261
262void remote_usb_get_my_address(ddf_fun_t *fun, void *iface,
263 ipc_callid_t callid, ipc_call_t *call)
264{
265 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
266
267 if (usb_iface->get_my_address == NULL) {
268 async_answer_0(callid, ENOTSUP);
269 return;
270 }
271
272 usb_address_t address;
273 const int ret = usb_iface->get_my_address(fun, &address);
274 if (ret != EOK) {
275 async_answer_0(callid, ret);
276 } else {
277 async_answer_1(callid, EOK, address);
278 }
279}
280
281void remote_usb_get_my_interface(ddf_fun_t *fun, void *iface,
282 ipc_callid_t callid, ipc_call_t *call)
283{
284 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
285
286 if (usb_iface->get_my_interface == NULL) {
287 async_answer_0(callid, ENOTSUP);
288 return;
289 }
290
291 int iface_no;
292 const int ret = usb_iface->get_my_interface(fun, &iface_no);
293 if (ret != EOK) {
294 async_answer_0(callid, ret);
295 } else {
296 async_answer_1(callid, EOK, iface_no);
297 }
298}
299
300void remote_usb_get_hc_handle(ddf_fun_t *fun, void *iface,
301 ipc_callid_t callid, ipc_call_t *call)
302{
303 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
304
305 if (usb_iface->get_hc_handle == NULL) {
306 async_answer_0(callid, ENOTSUP);
307 return;
308 }
309
310 devman_handle_t handle;
311 const int ret = usb_iface->get_hc_handle(fun, &handle);
312 if (ret != EOK) {
313 async_answer_0(callid, ret);
314 }
315
316 async_answer_1(callid, EOK, (sysarg_t) handle);
317}
318
319void remote_usb_get_device_handle(ddf_fun_t *fun, void *iface,
320 ipc_callid_t callid, ipc_call_t *call)
321{
322 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
323
324 if (usb_iface->get_device_handle == NULL) {
325 async_answer_0(callid, ENOTSUP);
326 return;
327 }
328
329 devman_handle_t handle;
330 const int ret = usb_iface->get_device_handle(fun, &handle);
331 if (ret != EOK) {
332 async_answer_0(callid, ret);
333 }
334
335 async_answer_1(callid, EOK, (sysarg_t) handle);
336}
337
338void remote_usb_reserve_default_address(ddf_fun_t *fun, void *iface,
339 ipc_callid_t callid, ipc_call_t *call)
340{
341 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
342
343 if (usb_iface->reserve_default_address == NULL) {
344 async_answer_0(callid, ENOTSUP);
345 return;
346 }
347
348 usb_speed_t speed = DEV_IPC_GET_ARG1(*call);
349 const int ret = usb_iface->reserve_default_address(fun, speed);
350 async_answer_0(callid, ret);
351}
352
353void remote_usb_release_default_address(ddf_fun_t *fun, void *iface,
354 ipc_callid_t callid, ipc_call_t *call)
355{
356 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
357
358 if (usb_iface->release_default_address == NULL) {
359 async_answer_0(callid, ENOTSUP);
360 return;
361 }
362
363 const int ret = usb_iface->release_default_address(fun);
364 async_answer_0(callid, ret);
365}
366
367static void remote_usb_device_enumerate(ddf_fun_t *fun, void *iface,
368 ipc_callid_t callid, ipc_call_t *call)
369{
370 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
371
372 if (usb_iface->device_enumerate == NULL) {
373 async_answer_0(callid, ENOTSUP);
374 return;
375 }
376
377 usb_device_handle_t handle = 0;
378 const int ret = usb_iface->device_enumerate(fun, &handle);
379 if (ret != EOK) {
380 async_answer_0(callid, ret);
381 }
382
383 async_answer_1(callid, EOK, (sysarg_t) handle);
384}
385
386static void remote_usb_device_remove(ddf_fun_t *fun, void *iface,
387 ipc_callid_t callid, ipc_call_t *call)
388{
389 const usb_iface_t *usb_iface = (usb_iface_t *) iface;
390
391 if (usb_iface->device_remove == NULL) {
392 async_answer_0(callid, ENOTSUP);
393 return;
394 }
395
396 usb_device_handle_t handle = DEV_IPC_GET_ARG1(*call);
397 const int ret = usb_iface->device_remove(fun, handle);
398 async_answer_0(callid, ret);
399}
400
401static void remote_usb_register_endpoint(ddf_fun_t *fun, void *iface,
402 ipc_callid_t callid, ipc_call_t *call)
403{
404 usb_iface_t *usb_iface = (usb_iface_t *) iface;
405
406 if (!usb_iface->register_endpoint) {
407 async_answer_0(callid, ENOTSUP);
408 return;
409 }
410
411#define _INIT_FROM_HIGH_DATA2(type, var, arg_no) \
412 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) >> 16)
413#define _INIT_FROM_LOW_DATA2(type, var, arg_no) \
414 type var = (type) (DEV_IPC_GET_ARG##arg_no(*call) & 0xffff)
415
416 const usb_endpoint_t endpoint = DEV_IPC_GET_ARG1(*call);
417
418 _INIT_FROM_HIGH_DATA2(usb_transfer_type_t, transfer_type, 2);
419 _INIT_FROM_LOW_DATA2(usb_direction_t, direction, 2);
420
421 _INIT_FROM_HIGH_DATA2(size_t, max_packet_size, 3);
422 _INIT_FROM_LOW_DATA2(unsigned int, interval, 3);
423
424#undef _INIT_FROM_HIGH_DATA2
425#undef _INIT_FROM_LOW_DATA2
426
427 const int ret = usb_iface->register_endpoint(fun, endpoint,
428 transfer_type, direction, max_packet_size, interval);
429
430 async_answer_0(callid, ret);
431}
432
433static void remote_usb_unregister_endpoint(ddf_fun_t *fun, void *iface,
434 ipc_callid_t callid, ipc_call_t *call)
435{
436 usb_iface_t *usb_iface = (usb_iface_t *) iface;
437
438 if (!usb_iface->unregister_endpoint) {
439 async_answer_0(callid, ENOTSUP);
440 return;
441 }
442
443 usb_endpoint_t endpoint = (usb_endpoint_t) DEV_IPC_GET_ARG1(*call);
444 usb_direction_t direction = (usb_direction_t) DEV_IPC_GET_ARG2(*call);
445
446 int rc = usb_iface->unregister_endpoint(fun, endpoint, direction);
447
448 async_answer_0(callid, rc);
449}
450/**
451 * @}
452 */
Note: See TracBrowser for help on using the repository browser.