source: mainline/uspace/lib/usb/src/usbdrv.c@ aae339e9

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

Add method for getting device address to USBHC interface

  • Property mode set to 100644
File size: 8.2 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 libusb usb
30 * @{
31 */
32/** @file
33 * @brief USB driver (implementation).
34 */
35#include <usb/usbdrv.h>
36#include <usbhc_iface.h>
37#include <errno.h>
38
39/** Information about pending transaction on HC. */
40typedef struct {
41 /** Phone to host controller driver. */
42 int phone;
43 /** Data buffer. */
44 void *buffer;
45 /** Buffer size. */
46 size_t size;
47 /** Storage for actual number of bytes transferred. */
48 size_t *size_transferred;
49 /** Initial call replay data. */
50 ipc_call_t reply;
51 /** Initial call identifier. */
52 aid_t request;
53} transfer_info_t;
54
55/** Connect to host controller the device is physically attached to.
56 *
57 * @param handle Device handle.
58 * @param flags Connection flags (blocking connection).
59 * @return Phone to corresponding HC or error code.
60 */
61int usb_drv_hc_connect(device_t *dev, unsigned int flags)
62{
63 /*
64 * Call parent hub to obtain device handle of respective HC.
65 */
66 return ENOTSUP;
67}
68
69/** Tell USB address assigned to given device.
70 *
71 * @param phone Phone to my HC.
72 * @param dev Device in question.
73 * @return USB address or error code.
74 */
75usb_address_t usb_drv_get_my_address(int phone, device_t *dev)
76{
77 ipcarg_t address;
78 int rc = async_req_1_1(phone, IPC_M_USBHC_GET_ADDRESS,
79 dev->handle, &address);
80
81 if (rc != EOK) {
82 return rc;
83 }
84
85 return (usb_address_t) address;
86}
87
88/** Send data to HCD.
89 *
90 * @param phone Phone to HC.
91 * @param method Method used for calling.
92 * @param target Targeted device.
93 * @param buffer Data buffer (NULL to skip data transfer phase).
94 * @param size Buffer size (must be zero when @p buffer is NULL).
95 * @param handle Storage for transaction handle (cannot be NULL).
96 * @return Error status.
97 * @retval EINVAL Invalid parameter.
98 * @retval ENOMEM Not enough memory to complete the operation.
99 */
100static int async_send_buffer(int phone, int method,
101 usb_target_t target,
102 void *buffer, size_t size,
103 usb_handle_t *handle)
104{
105 if (phone < 0) {
106 return EINVAL;
107 }
108
109 if ((buffer == NULL) && (size > 0)) {
110 return EINVAL;
111 }
112
113 if (handle == NULL) {
114 return EINVAL;
115 }
116
117 transfer_info_t *transfer
118 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
119 if (transfer == NULL) {
120 return ENOMEM;
121 }
122
123 transfer->size_transferred = NULL;
124 transfer->buffer = NULL;
125 transfer->size = 0;
126 transfer->phone = phone;
127
128 int rc;
129
130 transfer->request = async_send_4(phone,
131 DEV_IFACE_ID(USBHC_DEV_IFACE),
132 method,
133 target.address, target.endpoint,
134 size,
135 &transfer->reply);
136
137 if (size > 0) {
138 rc = async_data_write_start(phone, buffer, size);
139 if (rc != EOK) {
140 async_wait_for(transfer->request, NULL);
141 return rc;
142 }
143 }
144
145 *handle = (usb_handle_t) transfer;
146
147 return EOK;
148}
149
150/** Prepare data retrieval.
151 *
152 * @param phone Opened phone to HCD.
153 * @param method Method used for calling.
154 * @param target Targeted device.
155 * @param buffer Buffer where to store retrieved data
156 * (NULL to skip data transfer phase).
157 * @param size Buffer size (must be zero when @p buffer is NULL).
158 * @param actual_size Storage where actual number of bytes transferred will
159 * be stored.
160 * @param handle Storage for transaction handle (cannot be NULL).
161 * @return Error status.
162 * @retval EINVAL Invalid parameter.
163 * @retval ENOMEM Not enough memory to complete the operation.
164 */
165static int async_recv_buffer(int phone, int method,
166 usb_target_t target,
167 void *buffer, size_t size, size_t *actual_size,
168 usb_handle_t *handle)
169{
170 if (phone < 0) {
171 return EINVAL;
172 }
173
174 if ((buffer == NULL) && (size > 0)) {
175 return EINVAL;
176 }
177
178 if (handle == NULL) {
179 return EINVAL;
180 }
181
182 transfer_info_t *transfer
183 = (transfer_info_t *) malloc(sizeof(transfer_info_t));
184 if (transfer == NULL) {
185 return ENOMEM;
186 }
187
188 transfer->size_transferred = actual_size;
189 transfer->buffer = buffer;
190 transfer->size = size;
191 transfer->phone = phone;
192
193 transfer->request = async_send_4(phone,
194 DEV_IFACE_ID(USBHC_DEV_IFACE),
195 method,
196 target.address, target.endpoint,
197 size,
198 &transfer->reply);
199
200 *handle = (usb_handle_t) transfer;
201
202 return EOK;
203}
204
205/** Read buffer from HCD.
206 *
207 * @param phone Opened phone to HCD.
208 * @param hash Buffer hash (obtained after completing IN transaction).
209 * @param buffer Buffer where to store data data.
210 * @param size Buffer size.
211 * @param actual_size Storage where actual number of bytes transferred will
212 * be stored.
213 * @return Error status.
214 */
215static int read_buffer_in(int phone, ipcarg_t hash,
216 void *buffer, size_t size, size_t *actual_size)
217{
218 ipc_call_t answer_data;
219 ipcarg_t answer_rc;
220 aid_t req;
221 int rc;
222
223 req = async_send_2(phone,
224 DEV_IFACE_ID(USBHC_DEV_IFACE),
225 IPC_M_USBHC_GET_BUFFER,
226 hash,
227 &answer_data);
228
229 rc = async_data_read_start(phone, buffer, size);
230 if (rc != EOK) {
231 async_wait_for(req, NULL);
232 return EINVAL;
233 }
234
235 async_wait_for(req, &answer_rc);
236 rc = (int)answer_rc;
237
238 if (rc != EOK) {
239 return rc;
240 }
241
242 *actual_size = IPC_GET_ARG1(answer_data);
243
244 return EOK;
245}
246
247/** Blocks caller until given USB transaction is finished.
248 * After the transaction is finished, the user can access all output data
249 * given to initial call function.
250 *
251 * @param handle Transaction handle.
252 * @return Error status.
253 * @retval EOK No error.
254 * @retval EBADMEM Invalid handle.
255 * @retval ENOENT Data buffer associated with transaction does not exist.
256 */
257int usb_drv_async_wait_for(usb_handle_t handle)
258{
259 if (handle == 0) {
260 return EBADMEM;
261 }
262
263 int rc = EOK;
264
265 transfer_info_t *transfer = (transfer_info_t *) handle;
266
267 ipcarg_t answer_rc;
268 async_wait_for(transfer->request, &answer_rc);
269
270 if (answer_rc != EOK) {
271 rc = (int) answer_rc;
272 goto leave;
273 }
274
275 /*
276 * If the buffer is not NULL, we must accept some data.
277 */
278 if ((transfer->buffer != NULL) && (transfer->size > 0)) {
279 /*
280 * The buffer hash identifies the data on the server
281 * side.
282 * We will use it when actually reading-in the data.
283 */
284 ipcarg_t buffer_hash = IPC_GET_ARG1(transfer->reply);
285 if (buffer_hash == 0) {
286 rc = ENOENT;
287 goto leave;
288 }
289
290 size_t actual_size;
291 rc = read_buffer_in(transfer->phone, buffer_hash,
292 transfer->buffer, transfer->size, &actual_size);
293
294 if (rc != EOK) {
295 goto leave;
296 }
297
298 if (transfer->size_transferred) {
299 *(transfer->size_transferred) = actual_size;
300 }
301 }
302
303leave:
304 free(transfer);
305
306 return rc;
307}
308
309/** Send interrupt data to device. */
310int usb_drv_async_interrupt_out(int phone, usb_target_t target,
311 void *buffer, size_t size,
312 usb_handle_t *handle)
313{
314 return async_send_buffer(phone,
315 IPC_M_USBHC_INTERRUPT_OUT,
316 target,
317 buffer, size,
318 handle);
319}
320
321/** Request interrupt data from device. */
322int usb_drv_async_interrupt_in(int phone, usb_target_t target,
323 void *buffer, size_t size, size_t *actual_size,
324 usb_handle_t *handle)
325{
326 return async_recv_buffer(phone,
327 IPC_M_USBHC_INTERRUPT_IN,
328 target,
329 buffer, size, actual_size,
330 handle);
331}
332
333/**
334 * @}
335 */
Note: See TracBrowser for help on using the repository browser.