source: mainline/uspace/lib/drv/generic/remote_usb.c@ 70a422b

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

libdrv: Add endpoint management to usb iface.

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