source: mainline/uspace/drv/bus/usb/vhc/connhost.c@ bd444e5

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

Virtual USB HC: fix possible null pointer freeing

  • Property mode set to 100644
File size: 16.8 KB
Line 
1/*
2 * Copyright (c) 2011 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 drvusbvhc
30 * @{
31 */
32/** @file
33 * Host controller interface implementation.
34 */
35#include <assert.h>
36#include <errno.h>
37#include <usb/usb.h>
38#include <usb/ddfiface.h>
39#include <usb/debug.h>
40#include <usbhc_iface.h>
41#include "vhcd.h"
42
43#define GET_VHC_DATA(fun) \
44 ((vhc_data_t *)fun->dev->driver_data)
45#define VHC_DATA(vhc, fun) \
46 vhc_data_t *vhc = GET_VHC_DATA(fun); assert(vhc->magic == 0xdeadbeef)
47
48#define UNSUPPORTED(methodname) \
49 usb_log_warning("Unsupported interface method `%s()' in %s:%d.\n", \
50 methodname, __FILE__, __LINE__)
51
52/** Found free USB address.
53 *
54 * @param[in] fun Device function the action was invoked on.
55 * @param[in] speed Speed of the device that will get this address.
56 * @param[out] address Non-null pointer where to store the free address.
57 * @return Error code.
58 */
59static int request_address(ddf_fun_t *fun, usb_speed_t speed,
60 usb_address_t *address)
61{
62 VHC_DATA(vhc, fun);
63
64 usb_address_t addr = usb_device_manager_get_free_address(
65 &vhc->dev_manager, USB_SPEED_HIGH);
66 if (addr < 0) {
67 return addr;
68 }
69
70 if (address != NULL) {
71 *address = addr;
72 }
73
74 return EOK;
75}
76
77/** Bind USB address with device devman handle.
78 *
79 * @param[in] fun Device function the action was invoked on.
80 * @param[in] address USB address of the device.
81 * @param[in] handle Devman handle of the device.
82 * @return Error code.
83 */
84static int bind_address(ddf_fun_t *fun,
85 usb_address_t address, devman_handle_t handle)
86{
87 VHC_DATA(vhc, fun);
88 usb_log_debug("Binding handle %" PRIun " to address %d.\n",
89 handle, address);
90 usb_device_manager_bind(&vhc->dev_manager, address, handle);
91
92 return EOK;
93}
94
95/** Find device handle by address interface function.
96 *
97 * @param[in] fun DDF function that was called.
98 * @param[in] address Address in question.
99 * @param[out] handle Where to store device handle if found.
100 * @return Error code.
101 */
102static int find_by_address(ddf_fun_t *fun, usb_address_t address,
103 devman_handle_t *handle)
104{
105 VHC_DATA(vhc, fun);
106 bool found =
107 usb_device_manager_find_by_address(&vhc->dev_manager, address, handle);
108 return found ? EOK : ENOENT;
109}
110
111/** Release previously requested address.
112 *
113 * @param[in] fun Device function the action was invoked on.
114 * @param[in] address USB address to be released.
115 * @return Error code.
116 */
117static int release_address(ddf_fun_t *fun, usb_address_t address)
118{
119 VHC_DATA(vhc, fun);
120 usb_log_debug("Releasing address %d...\n", address);
121 usb_device_manager_release(&vhc->dev_manager, address);
122
123 return ENOTSUP;
124}
125
126/** Register endpoint for bandwidth reservation.
127 *
128 * @param[in] fun Device function the action was invoked on.
129 * @param[in] address USB address of the device.
130 * @param[in] speed Endpoint speed (invalid means to use device one).
131 * @param[in] endpoint Endpoint number.
132 * @param[in] transfer_type USB transfer type.
133 * @param[in] direction Endpoint data direction.
134 * @param[in] max_packet_size Max packet size of the endpoint.
135 * @param[in] interval Polling interval.
136 * @return Error code.
137 */
138static int register_endpoint(ddf_fun_t *fun,
139 usb_address_t address, usb_speed_t speed, usb_endpoint_t endpoint,
140 usb_transfer_type_t transfer_type, usb_direction_t direction,
141 size_t max_packet_size, unsigned int interval)
142{
143 /* TODO: Use usb_endpoint_manager_add_ep */
144 VHC_DATA(vhc, fun);
145
146 endpoint_t *ep = endpoint_get(
147 address, endpoint, direction, transfer_type, USB_SPEED_FULL, 1);
148 if (ep == NULL) {
149 return ENOMEM;
150 }
151
152 int rc = usb_endpoint_manager_register_ep(&vhc->ep_manager, ep, 1);
153 if (rc != EOK) {
154 endpoint_destroy(ep);
155 return rc;
156 }
157
158 return EOK;
159}
160
161/** Unregister endpoint (free some bandwidth reservation).
162 *
163 * @param[in] fun Device function the action was invoked on.
164 * @param[in] address USB address of the device.
165 * @param[in] endpoint Endpoint number.
166 * @param[in] direction Endpoint data direction.
167 * @return Error code.
168 */
169static int unregister_endpoint(ddf_fun_t *fun, usb_address_t address,
170 usb_endpoint_t endpoint, usb_direction_t direction)
171{
172 VHC_DATA(vhc, fun);
173
174 int rc = usb_endpoint_manager_unregister_ep(&vhc->ep_manager,
175 address, endpoint, direction);
176
177 return rc;
178}
179#if 0
180/** Schedule interrupt out transfer.
181 *
182 * The callback is supposed to be called once the transfer (on the wire) is
183 * complete regardless of the outcome.
184 * However, the callback could be called only when this function returns
185 * with success status (i.e. returns EOK).
186 *
187 * @param[in] fun Device function the action was invoked on.
188 * @param[in] target Target pipe (address and endpoint number) specification.
189 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
190 * by the caller).
191 * @param[in] size Size of the @p data buffer in bytes.
192 * @param[in] callback Callback to be issued once the transfer is complete.
193 * @param[in] arg Pass-through argument to the callback.
194 * @return Error code.
195 */
196static int interrupt_out(ddf_fun_t *fun, usb_target_t target,
197 void *data, size_t size,
198 usbhc_iface_transfer_out_callback_t callback, void *arg)
199{
200 VHC_DATA(vhc, fun);
201
202 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
203 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_INTERRUPT,
204 fun, arg);
205 if (transfer == NULL) {
206 return ENOMEM;
207 }
208
209 transfer->data_buffer = data;
210 transfer->data_buffer_size = size;
211 transfer->callback_out = callback;
212
213 int rc = vhc_virtdev_add_transfer(vhc, transfer);
214 if (rc != EOK) {
215 free(transfer);
216 return rc;
217 }
218
219 return EOK;
220}
221
222/** Schedule interrupt in transfer.
223 *
224 * The callback is supposed to be called once the transfer (on the wire) is
225 * complete regardless of the outcome.
226 * However, the callback could be called only when this function returns
227 * with success status (i.e. returns EOK).
228 *
229 * @param[in] fun Device function the action was invoked on.
230 * @param[in] target Target pipe (address and endpoint number) specification.
231 * @param[in] data Buffer where to store the data (in USB endianess,
232 * allocated and deallocated by the caller).
233 * @param[in] size Size of the @p data buffer in bytes.
234 * @param[in] callback Callback to be issued once the transfer is complete.
235 * @param[in] arg Pass-through argument to the callback.
236 * @return Error code.
237 */
238static int interrupt_in(ddf_fun_t *fun, usb_target_t target,
239 void *data, size_t size,
240 usbhc_iface_transfer_in_callback_t callback, void *arg)
241{
242 VHC_DATA(vhc, fun);
243
244 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
245 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_INTERRUPT,
246 fun, arg);
247 if (transfer == NULL) {
248 return ENOMEM;
249 }
250
251 transfer->data_buffer = data;
252 transfer->data_buffer_size = size;
253 transfer->callback_in = callback;
254
255 int rc = vhc_virtdev_add_transfer(vhc, transfer);
256 if (rc != EOK) {
257 free(transfer);
258 return rc;
259 }
260
261 return EOK;
262}
263
264/** Schedule bulk out transfer.
265 *
266 * The callback is supposed to be called once the transfer (on the wire) is
267 * complete regardless of the outcome.
268 * However, the callback could be called only when this function returns
269 * with success status (i.e. returns EOK).
270 *
271 * @param[in] fun Device function the action was invoked on.
272 * @param[in] target Target pipe (address and endpoint number) specification.
273 * @param[in] data Data to be sent (in USB endianess, allocated and deallocated
274 * by the caller).
275 * @param[in] size Size of the @p data buffer in bytes.
276 * @param[in] callback Callback to be issued once the transfer is complete.
277 * @param[in] arg Pass-through argument to the callback.
278 * @return Error code.
279 */
280static int bulk_out(ddf_fun_t *fun, usb_target_t target,
281 void *data, size_t size,
282 usbhc_iface_transfer_out_callback_t callback, void *arg)
283{
284 UNSUPPORTED("bulk_out");
285
286 return ENOTSUP;
287}
288
289/** Schedule bulk in transfer.
290 *
291 * The callback is supposed to be called once the transfer (on the wire) is
292 * complete regardless of the outcome.
293 * However, the callback could be called only when this function returns
294 * with success status (i.e. returns EOK).
295 *
296 * @param[in] fun Device function the action was invoked on.
297 * @param[in] target Target pipe (address and endpoint number) specification.
298 * @param[in] data Buffer where to store the data (in USB endianess,
299 * allocated and deallocated by the caller).
300 * @param[in] size Size of the @p data buffer in bytes.
301 * @param[in] callback Callback to be issued once the transfer is complete.
302 * @param[in] arg Pass-through argument to the callback.
303 * @return Error code.
304 */
305static int bulk_in(ddf_fun_t *fun, usb_target_t target,
306 void *data, size_t size,
307 usbhc_iface_transfer_in_callback_t callback, void *arg)
308{
309 UNSUPPORTED("bulk_in");
310
311 return ENOTSUP;
312}
313
314/** Schedule control write transfer.
315 *
316 * The callback is supposed to be called once the transfer (on the wire) is
317 * complete regardless of the outcome.
318 * However, the callback could be called only when this function returns
319 * with success status (i.e. returns EOK).
320 *
321 * @param[in] fun Device function the action was invoked on.
322 * @param[in] target Target pipe (address and endpoint number) specification.
323 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
324 * and deallocated by the caller).
325 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
326 * @param[in] data_buffer Data buffer (in USB endianess, allocated and
327 * deallocated by the caller).
328 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
329 * @param[in] callback Callback to be issued once the transfer is complete.
330 * @param[in] arg Pass-through argument to the callback.
331 * @return Error code.
332 */
333static int control_write(ddf_fun_t *fun, usb_target_t target,
334 void *setup_packet, size_t setup_packet_size,
335 void *data_buffer, size_t data_buffer_size,
336 usbhc_iface_transfer_out_callback_t callback, void *arg)
337{
338 VHC_DATA(vhc, fun);
339
340 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
341 target.endpoint, USB_DIRECTION_OUT, USB_TRANSFER_CONTROL,
342 fun, arg);
343 if (transfer == NULL) {
344 return ENOMEM;
345 }
346
347 transfer->setup_buffer = setup_packet;
348 transfer->setup_buffer_size = setup_packet_size;
349 transfer->data_buffer = data_buffer;
350 transfer->data_buffer_size = data_buffer_size;
351 transfer->callback_out = callback;
352
353 int rc = vhc_virtdev_add_transfer(vhc, transfer);
354 if (rc != EOK) {
355 free(transfer);
356 return rc;
357 }
358
359 return EOK;
360}
361
362/** Schedule control read transfer.
363 *
364 * The callback is supposed to be called once the transfer (on the wire) is
365 * complete regardless of the outcome.
366 * However, the callback could be called only when this function returns
367 * with success status (i.e. returns EOK).
368 *
369 * @param[in] fun Device function the action was invoked on.
370 * @param[in] target Target pipe (address and endpoint number) specification.
371 * @param[in] setup_packet Setup packet buffer (in USB endianess, allocated
372 * and deallocated by the caller).
373 * @param[in] setup_packet_size Size of @p setup_packet buffer in bytes.
374 * @param[in] data_buffer Buffer where to store the data (in USB endianess,
375 * allocated and deallocated by the caller).
376 * @param[in] data_buffer_size Size of @p data_buffer buffer in bytes.
377 * @param[in] callback Callback to be issued once the transfer is complete.
378 * @param[in] arg Pass-through argument to the callback.
379 * @return Error code.
380 */
381static int control_read(ddf_fun_t *fun, usb_target_t target,
382 void *setup_packet, size_t setup_packet_size,
383 void *data_buffer, size_t data_buffer_size,
384 usbhc_iface_transfer_in_callback_t callback, void *arg)
385{
386 VHC_DATA(vhc, fun);
387
388 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
389 target.endpoint, USB_DIRECTION_IN, USB_TRANSFER_CONTROL,
390 fun, arg);
391 if (transfer == NULL) {
392 return ENOMEM;
393 }
394
395 transfer->setup_buffer = setup_packet;
396 transfer->setup_buffer_size = setup_packet_size;
397 transfer->data_buffer = data_buffer;
398 transfer->data_buffer_size = data_buffer_size;
399 transfer->callback_in = callback;
400
401 int rc = vhc_virtdev_add_transfer(vhc, transfer);
402 if (rc != EOK) {
403 free(transfer);
404 return rc;
405 }
406
407 return EOK;
408}
409#endif
410static int usb_read(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
411 uint8_t *data_buffer, size_t data_buffer_size,
412 usbhc_iface_transfer_in_callback_t callback, void *arg)
413{
414 VHC_DATA(vhc, fun);
415
416 endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
417 target.address, target.endpoint, USB_DIRECTION_IN, NULL);
418 if (ep == NULL) {
419 return ENOENT;
420 }
421 const usb_transfer_type_t transfer_type = ep->transfer_type;
422
423
424 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
425 target.endpoint, USB_DIRECTION_IN, transfer_type,
426 fun, arg);
427 if (transfer == NULL) {
428 return ENOMEM;
429 }
430 if (transfer_type == USB_TRANSFER_CONTROL) {
431 transfer->setup_buffer = malloc(sizeof(uint64_t));
432 assert(transfer->setup_buffer);
433 memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
434 transfer->setup_buffer_size = sizeof(uint64_t);
435 }
436 transfer->data_buffer = data_buffer;
437 transfer->data_buffer_size = data_buffer_size;
438 transfer->callback_in = callback;
439
440 int rc = vhc_virtdev_add_transfer(vhc, transfer);
441 if (rc != EOK) {
442 if (transfer->setup_buffer != NULL) {
443 free(transfer->setup_buffer);
444 }
445 free(transfer);
446 return rc;
447 }
448
449 return EOK;
450}
451
452static int usb_write(ddf_fun_t *fun, usb_target_t target, uint64_t setup_buffer,
453 const uint8_t *data_buffer, size_t data_buffer_size,
454 usbhc_iface_transfer_out_callback_t callback, void *arg)
455{
456 VHC_DATA(vhc, fun);
457
458 endpoint_t *ep = usb_endpoint_manager_get_ep(&vhc->ep_manager,
459 target.address, target.endpoint, USB_DIRECTION_OUT, NULL);
460 if (ep == NULL) {
461 return ENOENT;
462 }
463 const usb_transfer_type_t transfer_type = ep->transfer_type;
464
465
466 vhc_transfer_t *transfer = vhc_transfer_create(target.address,
467 target.endpoint, USB_DIRECTION_OUT, transfer_type,
468 fun, arg);
469 if (transfer == NULL) {
470 return ENOMEM;
471 }
472 if (transfer_type == USB_TRANSFER_CONTROL) {
473 transfer->setup_buffer = malloc(sizeof(uint64_t));
474 assert(transfer->setup_buffer);
475 memcpy(transfer->setup_buffer, &setup_buffer, sizeof(uint64_t));
476 transfer->setup_buffer_size = sizeof(uint64_t);
477 }
478 transfer->data_buffer = (void*)data_buffer;
479 transfer->data_buffer_size = data_buffer_size;
480 transfer->callback_out = callback;
481
482 int rc = vhc_virtdev_add_transfer(vhc, transfer);
483 if (rc != EOK) {
484 free(transfer->setup_buffer);
485 free(transfer);
486 return rc;
487 }
488
489 return EOK;
490}
491
492static int tell_address(ddf_fun_t *fun, devman_handle_t handle,
493 usb_address_t *address)
494{
495 UNSUPPORTED("tell_address");
496
497 return ENOTSUP;
498}
499
500static int usb_iface_get_hc_handle_rh_impl(ddf_fun_t *root_hub_fun,
501 devman_handle_t *handle)
502{
503 VHC_DATA(vhc, root_hub_fun);
504
505 *handle = vhc->hc_fun->handle;
506
507 return EOK;
508}
509
510static int tell_address_rh(ddf_fun_t *root_hub_fun, devman_handle_t handle,
511 usb_address_t *address)
512{
513 VHC_DATA(vhc, root_hub_fun);
514
515 if (handle == 0) {
516 handle = root_hub_fun->handle;
517 }
518
519 usb_log_debug("tell_address_rh(handle=%" PRIun ")\n", handle);
520 usb_address_t addr = usb_device_manager_find(&vhc->dev_manager, handle);
521 if (addr < 0) {
522 return addr;
523 } else {
524 *address = addr;
525 return EOK;
526 }
527}
528
529usbhc_iface_t vhc_iface = {
530 .request_address = request_address,
531 .bind_address = bind_address,
532 .find_by_address = find_by_address,
533 .release_address = release_address,
534
535 .register_endpoint = register_endpoint,
536 .unregister_endpoint = unregister_endpoint,
537
538 .write = usb_write,
539 .read = usb_read,
540};
541
542usb_iface_t vhc_usb_iface = {
543 .get_hc_handle = usb_iface_get_hc_handle_hc_impl,
544 .get_address = tell_address
545};
546
547usb_iface_t rh_usb_iface = {
548 .get_hc_handle = usb_iface_get_hc_handle_rh_impl,
549 .get_address = tell_address_rh
550};
551
552
553/**
554 * @}
555 */
Note: See TracBrowser for help on using the repository browser.