diff options
author | Daniel Drake <dsd@gentoo.org> | 2008-03-09 01:01:57 +0000 |
---|---|---|
committer | Daniel Drake <dsd@gentoo.org> | 2008-03-09 01:06:08 +0000 |
commit | 1ac0a7d88f282b6f293c456fac8edb143cbaca3d (patch) | |
tree | e75ff5bcaf431f71fa6189c5c0ddaa185470ea39 /libusb/sync.c | |
parent | 66348c90ea4570bf999ac301089e006d0cce1926 (diff) | |
download | libusb-1ac0a7d88f282b6f293c456fac8edb143cbaca3d.tar.gz |
Move synchronous I/O implementation to its own file
Diffstat (limited to 'libusb/sync.c')
-rw-r--r-- | libusb/sync.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/libusb/sync.c b/libusb/sync.c new file mode 100644 index 0000000..2bcfc5b --- /dev/null +++ b/libusb/sync.c @@ -0,0 +1,169 @@ +/* + * Synchronous I/O functions for libusb + * Copyright (C) 2007-2008 Daniel Drake <dsd@gentoo.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "libusbi.h" + +static void ctrl_transfer_cb(struct libusb_transfer *transfer) +{ + int *completed = transfer->user_data; + *completed = 1; + usbi_dbg("actual_length=%d", transfer->actual_length); + /* caller interprets result and frees transfer */ +} + +API_EXPORTED int libusb_control_transfer(libusb_dev_handle *dev_handle, + uint8_t bRequestType, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, + unsigned char *data, uint16_t wLength, unsigned int timeout) +{ + struct libusb_transfer *transfer = libusb_alloc_transfer(); + unsigned char *buffer; + int length = wLength + LIBUSB_CONTROL_SETUP_SIZE; + int completed = 0; + int r; + + if (!transfer) + return -ENOMEM; + + buffer = malloc(length); + if (!buffer) { + libusb_free_transfer(transfer); + return -ENOMEM; + } + + libusb_fill_control_setup(buffer, bRequestType, bRequest, wValue, wIndex, + wLength); + if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) + memcpy(buffer + LIBUSB_CONTROL_SETUP_SIZE, data, wLength); + + libusb_fill_control_transfer(transfer, dev_handle, buffer, length, + ctrl_transfer_cb, &completed, timeout); + r = libusb_submit_transfer(transfer); + if (r < 0) { + libusb_free_transfer(transfer); + return r; + } + + while (!completed) { + r = libusb_poll(); + if (r < 0) { + libusb_cancel_transfer_sync(dev_handle, transfer); + libusb_free_transfer(transfer); + return r; + } + } + + if ((bRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) + memcpy(data, libusb_control_transfer_get_data(transfer), + transfer->actual_length); + + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + r = transfer->actual_length; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + r = -ETIMEDOUT; + break; + default: + usbi_warn("unrecognised status code %d", transfer->status); + r = -1; + } + + libusb_free_transfer(transfer); + return r; +} + +static void bulk_transfer_cb(struct libusb_transfer *transfer) +{ + int *completed = transfer->user_data; + *completed = 1; + usbi_dbg("actual_length=%d", transfer->actual_length); + /* caller interprets results and frees transfer */ +} + +static int do_sync_bulk_transfer(struct libusb_dev_handle *dev_handle, + unsigned char endpoint, unsigned char *buffer, int length, + int *transferred, unsigned int timeout, unsigned char endpoint_type) +{ + struct libusb_transfer *transfer = libusb_alloc_transfer(); + int completed = 0; + int r; + + if (!transfer) + return -ENOMEM; + + libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, + bulk_transfer_cb, &completed, timeout); + transfer->endpoint_type = endpoint_type; + + r = libusb_submit_transfer(transfer); + if (r < 0) { + libusb_free_transfer(transfer); + return r; + } + + while (!completed) { + r = libusb_poll(); + if (r < 0) { + libusb_cancel_transfer_sync(dev_handle, transfer); + libusb_free_transfer(transfer); + return r; + } + } + + *transferred = transfer->actual_length; + switch (transfer->status) { + case LIBUSB_TRANSFER_COMPLETED: + r = 0; + break; + case LIBUSB_TRANSFER_TIMED_OUT: + r = -ETIMEDOUT; + break; + default: + usbi_warn("unrecognised status code %d", transfer->status); + r = -1; + } + + libusb_free_transfer(transfer); + return r; +} + +/* FIXME: should transferred be the return value? */ +API_EXPORTED int libusb_bulk_transfer(struct libusb_dev_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, int *transferred, + unsigned int timeout) +{ + return do_sync_bulk_transfer(dev_handle, endpoint, data, length, + transferred, timeout, LIBUSB_ENDPOINT_TYPE_BULK); +} + +/* FIXME: do we need an interval param here? usbfs doesn't expose it? */ +API_EXPORTED int libusb_interrupt_transfer(struct libusb_dev_handle *dev_handle, + unsigned char endpoint, unsigned char *data, int length, int *transferred, + unsigned int timeout) +{ + return do_sync_bulk_transfer(dev_handle, endpoint, data, length, + transferred, timeout, LIBUSB_ENDPOINT_TYPE_INTERRUPT); +} + |