source: mainline/uspace/lib/drv/generic/remote_usb.c@ 205261f

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

libdrv, usb: Remove redundant NULL check

async_req is NULL safe

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