/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* This library can either be used stand-alone or as plugin
* to the libusb wrapper library.
* The libusb API 0.1.0.10 has been implemented using all original code
* which was not derived from opensource.
*
* XXX issues:
* - timeout thru signal
* - usb_interrupt/bulk_write/read should have common code
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdarg.h>
#include <strings.h>
#include <regex.h>
#include "usb.h"
#include "libusbugen_impl.h"
/* global variables */
/* error handling */
static int usb_error_errno;
/* debugging */
/* api binding */
/* internal function prototypes */
static void usb_error_str(int x, char *format, ...);
static int usb_error(int x);
static int usb_get_status(int fd);
/*
* libusb_init:
*
* Returns: 0 or ENOSUP if we cannot support any bus
*/
int
libusb_init(void)
{
return (0);
}
/*
* libusb_fini:
*
* Returns: always returns 0
*/
int
libusb_fini(void)
{
return (0);
}
/*
* Entry points:
*
* usb_set_debug:
* sets debug level for tracing
*/
void
{
if (getenv("SUN_LIBUSBUGEN_DEBUG")) {
} else if (getenv("SUN_LIBUSB_DEBUG")) {
}
if (level < 0)
return;
"Setting debugging level to %d (%s)\n",
}
/*
* usb_init:
* not much to initialize. just set debug level
*/
void
usb_init(void)
{
if (getenv("LIBUSB_API_STRICT")) {
}
"libusb version=%s\n", libusb_version);
}
/*
* usb_get_busses:
* Returns: usb_busses pointer
*/
usb_get_busses(void)
{
return (usb_busses);
}
/*
* usb_find_busses:
* finds all busses in the system. On solaris we have
*
* Returns: change in number of busses or negative errno
*/
int
usb_find_busses(void)
{
/* we only have one name space for all USB busses */
if (usb_busses == NULL) {
/* never freed */
}
usb_busses = bus;
return (1);
}
return (0);
}
/*
* usb_find_devices:
* finds all devices that have appeared and removes devices
* from the list that are no longer there
*
* Returns: change in number of devices or a negative errno
*/
int
usb_find_devices(void)
{
int changes = 0;
new_devices = NULL;
if (rval != 0) {
}
/* is any of devices on the new list also on the old list? */
found = 0;
found++;
break;
}
}
/* the device must have been hot removed */
if (!found) {
}
}
/* add all new_devices to the old_devices list */
changes++;
}
}
return (changes);
}
/*
* usb_device:
* included because sane uses this
* Returns: usb_device structure associated with handle
*/
struct usb_device *
{
}
/*
* usb_open:
* opens the device for access
*
* Returns: a usb device handle or NULL
*/
{
int i, rval;
dev) == 0) {
"illegal usb_device pointer\n");
return (NULL);
}
/* create a handle and info structure */
return (NULL);
}
return (NULL);
}
/* set all file descriptors to "closed" */
for (i = 0; i < USB_MAXENDPOINTS; i++) {
if (i > 0) {
}
}
/* open default control ep and keep it open */
return (NULL);
}
/*
* setup config info: trees of configs, interfaces, alternates
* and endpoints structures
*/
if (usb_setup_all_configs(hdl) != 0) {
return (NULL);
}
/* set when the app claims an interface */
return ((usb_dev_handle *)hdl);
}
/*
* usb_close:
* closes the device and free resources
*
* Returns: 0
*/
int
{
if (hdl) {
"usb_close(): claimed %d\n",
(void) usb_release_interface(dev,
}
return (0);
}
}
/*
* usb_control_msg:
* sends a control message
*
* Returns: actual number of data bytes transferred or
* a negative errno
*/
/*ARGSUSED*/
int
{
int additional;
int rval;
}
/*
* no need to do validation since ep0 is always open and
* we do not need to claim an interface first
*
* usb_send_msg returns #bytes xferred or negative errno
*/
/* less than setup bytes transferred? */
if (rval < 8) {
"error sending control message: %d", rval);
return ((rval >= 0) ?
}
/* for IN requests, now transfer the remaining bytes */
} else {
additional = rval;
}
"usb_control_msg(): additional 0x%x bytes\n", additional);
return (additional);
}
/*
* usb_bulk_write:
* writes to a bulk endpoint
*
* Returns: actual number of data bytes transferred or negative errno
*/
/* ARGSUSED */
int
int timeout)
{
"usb_bulk_write(): NULL handle or data\n");
}
/* do some validation first */
USB_ENDPOINT_TYPE_BULK, O_WRONLY)) != 0) {
"usb_check_device_and_status_open() failed\n");
}
/* now write out the bytes */
return (sent);
}
/*
* usb_bulk_read:
* reads from a bulk endpoint
*
* Returns: actual number of data bytes transferred or negative errno
*/
/* ARGSUSED */
int
int timeout)
{
ep |= USB_ENDPOINT_IN;
"usb_bulk_read(): NULL handle or data\n");
}
/* do some validation first */
USB_ENDPOINT_TYPE_BULK, O_RDONLY)) != 0) {
"usb_check_device_and_status_open() failed\n");
}
/* now read in the bytes */
return (received);
}
/*
* usb_interrupt_write:
* writes data to an interrupt endpoint
*
* Returns: actual number of data bytes transferred or negative errno
*/
/* ARGSUSED */
int
int timeout)
{
"usb_interrupt_write(): NULL handle or data\n");
}
/* do some validation first */
USB_ENDPOINT_TYPE_INTERRUPT, O_WRONLY)) != 0) {
"usb_check_device_and_status_open() failed\n");
}
/* now transfer the bytes */
return (sent);
}
/*
* usb_interrupt_read:
* reads data from an interrupt endpoint
*
* Returns: actual number of data bytes transferred or negative errno
*/
/* ARGSUSED */
int
int timeout)
{
ep |= USB_ENDPOINT_IN;
"usb_interrupt_read(): NULL handle or data\n");
}
/* do some validation first */
USB_ENDPOINT_TYPE_INTERRUPT, O_RDONLY)) != 0) {
"usb_check_device_and_status_open() failed\n");
}
/* now transfer the bytes */
/* close the endpoint so we stop polling the endpoint now */
return (received);
}
/*
* usb_get_string:
* gets a raw unicode string
*
* Returns: number of bytes transferred or negative errno
*/
int
{
/*
* We can't use usb_get_descriptor() because it's lacking the index
* parameter. This will be fixed in libusb 1.0
*/
"usb_get_string(): index=%d langid=0x%x len=%d\n",
"usb_get_string(): NULL handle or data\n");
}
}
/*
* usb_get_string_simple:
* gets a cooked ascii string
*
* Returns: number of bytes transferred or negative errno
*/
int
{
index);
"usb_get_string_simple(): NULL handle or data\n");
}
/*
* Asking for the zero'th index is special - it returns a string
* descriptor that contains all the language IDs supported by the
* device. Typically there aren't many - often only one. The
* language IDs are 16 bit numbers, and they start at the third byte
* in the descriptor. See USB 2.0 specification, section 9.6.7, for
* more information on this.
*/
if (ret < 4) {
langid = 0x409;
} else {
}
if (ret < 0) {
return (ret);
}
return (-EIO);
}
return (-EFBIG);
}
break;
}
} else {
}
}
return (di);
}
/*
* usb_get_descriptor_by_endpoint:
* usb_get_descriptor:
* get a descriptor. by_endpoint does not appear to make
* much sense.
*
* Returns: number of bytes transferred or negative errno
*/
int
{
"usb_get_descriptor_by_endpoint(): "
"NULL handle or data\n");
}
return (usb_control_msg(udev,
}
int
{
"usb_get_string_simple(): NULL handle or data\n");
}
return (usb_control_msg(udev,
}
/*
* usb_set_altinterface:
* switches to the alternate interface for the device
* Note that ugen does not really need this. It does implicit
* cfg and alt switches when the endpoint is opened.
*
* Returns: 0 or negative errno
*/
/* ARGSUSED */
int
{
"usb_set_altinterface(): NULL handle\n");
}
if (libusb_api == API_RELAXED) {
/*
* usb_claim_interface() should always be called
* prior usb_set_altinterface(), but some apps
* do not do this, hence we call it here assuming
* the default interface.
*/
return (err);
}
}
}
}
/* find the conf index */
index++) {
if (info->configuration_value ==
break;
}
}
"cfg value=%d index=%d, iface=%d, alt=%d #alts=%d\n",
}
return (0);
}
/*
* usb_set_configuration:
* sets the configuration for the device.
* ugen implicitly switches configuration and rejects
* set configuration requests
*
* Returns: 0
*/
/* ARGSUSED */
int
{
int index, i;
"usb_set_configuration(): config = %d\n", configuration);
"usb_set_configuration(): NULL handle\n");
}
/* find the conf index */
index++) {
if (configuration ==
break;
}
}
"usb_set_configuration(): invalid\n");
}
/* reset ep arrays */
for (i = 0; i < USB_MAXENDPOINTS; i++) {
}
}
return (0);
}
/*
* usb_clear_halt:
* clears a halted endpoint
* ugen has auto clearing but we send the request anyways
*
* Returns: 0 or negative errno
*/
/* ARGSUSED */
int
{
int rval;
"usb_clear_halt(): NULL handle\n");
}
}
/* only check for ep > 0 */
}
if (rval < 0) {
}
return (rval);
}
/*
* usb_claim_interface:
* ugen does not have a claim interface concept but all endpoints
* are opened exclusively. This provides some exclusion. However,
* the interrupt IN endpoint is closed after the read
*
* Returns: 0 or negative errno
*/
int
{
int index;
"usb_claim_interface(): NULL handle\n");
}
index = 0;
} else {
/* find the conf index */
for (index = 0;
index++) {
if (info->configuration_value ==
break;
}
}
}
/* is this a valid interface? */
}
/* already claimed? */
return (0);
}
}
}
"interface = %d, claimed by this udev=%d, by hdl=0x%x\n",
return (0);
}
/*
* usb_release_interface:
* releases the acquired interface
*
* Returns: 0 or negative errno
*/
/* ARGSUSED */
int
{
"usb_release_interface(): NULL handle\n");
}
}
"interface = %d, claimed by this udev=%d, by hdl=0x%x\n",
return (0);
}
/*
* usb_resetep
* resets the endpoint
*
* Returns: 0 or negative errno
*/
int
{
}
/*
* usb_reset:
* resets the device
* Returns: -ENOTSUP
*/
/* ARGSUSED */
int
{
int rval;
"usb_reset(): NULL handle\n");
}
}
}
/*
* Helper functions
*
* usb_send_msg:
* creates setup data and send it
*
* Returns: number of bytes transferred or negative errno
*/
static int
{
int rval;
"\trequesttype 0x%x\n"
"\trequest 0x%x\n"
"\tvalue 0x%x\n"
"\tindex 0x%x\n"
"\tsize 0x%x\n",
if (requesttype & USB_DEV_REQ_DEV_TO_HOST) {
} else {
/* append the write data */
char *buffer;
}
}
return (rval);
}
/*
* usb_do_io:
* status of the device if error or short xfer.
*
* Returns: bytes transferred or negative errno
*/
static int
{
int error;
if (size == 0) {
return (0);
}
switch (flag) {
case READ:
break;
case WRITE:
break;
}
if (ret < 0) {
/* usb_get_status will do a read and overwrite errno */
error, save_errno);
return (-save_errno);
}
return ((int)ret);
}
/*
* usb_check_access:
* basically checks if the interface has been claimed
*
*/
static int
{
return (EINVAL);
}
"hdl=0x%x conf=%d claimed=%d alternate=%d\n",
return (EACCES);
}
return (0);
}
/*
* usb_set_ep_iface_alts:
* initialize ep_interface arrays
*/
static void
{
int i;
/* reinitialize endpoint arrays */
for (i = 0; i < USB_MAXENDPOINTS; i++) {
}
/*
* for the current config, this interface and alt,
* which endpoints are available
*/
for (i = 0; i < if_descr->bNumEndpoints; i++) {
}
for (i = 0; i < USB_MAXENDPOINTS; i++) {
info->ep_interface[i]);
}
}
/*
* usb_check_device_and_status_open:
* Make sure that the endpoint and status device for the endpoint
* can be opened, or have already been opened.
*
* Returns: errno
*/
static int
int mode)
{
"usb_check_device_and_status_open(): "
return (rval);
}
return (EINVAL);
}
return (EINVAL);
}
return (0);
}
if (ep == 0) {
/* should already be open */
return (0);
}
return (ENOMEM);
}
return (ENOMEM);
}
/* create filename */
if (info->configuration_index > 0) {
} else {
}
} else {
}
"usb_check_device_and_status_open: %s\n", filename);
/*
* for interrupt IN endpoints, we need to enable one xfer
* mode before opening the endpoint
*/
if ((ep_type == USB_ENDPOINT_TYPE_INTERRUPT) &&
(ep & USB_ENDPOINT_IN)) {
/* open the status device node for the ep first RDWR */
/* might be an older ugen version, try RDONLY */
O_RDONLY)) == -1) {
"can't open %s RDONLY: %d",
return (errno);
}
} else {
if (count != 1) {
/* this should have worked */
return (errno);
}
}
} else {
return (errno);
}
}
/* open the ep */
return (errno);
}
return (0);
}
/*
* usb_ep_index:
* creates an index from endpoint address that can
* be used to index into endpoint lists
*
* Returns: ep index (a number between 0 and 31)
*/
static uchar_t
{
return ((ep_addr & USB_EP_NUM_MASK) +
}
/*
* usb_open_ep0:
* opens default pipe
*
* Returns: errno
*/
static int
{
char *filename;
if (dev_specific->ep0_fd) {
"usb_open_ep0(): already open, ref=%d\n",
return (0);
}
return (ENOMEM);
}
return (errno);
}
return (errno);
}
/* allow sharing between multiple opens */
return (0);
}
/*
* usb_close_ep0:
* closes default ep0
*/
static void
{
if (dev_specific->ep0_fd) {
if (--(dev_specific->ref_count) > 0) {
"usb_close_ep0(): ref_count=%d\n",
return;
}
}
}
}
dev_specific->ep0_fd = 0;
dev_specific->ep0_fd_stat = 0;
}
/*
* usb_close_all_eps:
* closes all open endpoints except 0
*/
static void
{
int i;
for (i = 1; i < USB_MAXENDPOINTS; i++) {
}
}
}
}
/*
* usb_setup_all_configs:
* parses config cloud for each config
*
* Returns: errno
*/
static int
{
return (0);
}
/* get device descriptor */
0, buffer, USB_DEV_DESCR_SIZE, 0);
if (rval != USB_DEV_DESCR_SIZE) {
return (EIO);
}
/* parse device descriptor */
sizeof (struct usb_device_descriptor));
if (rval != (int)sizeof (struct usb_device_descriptor)) {
return (EIO);
}
/* allocate config array */
len = (int) sizeof (struct usb_config_descriptor) *
return (ENOMEM);
}
/* parse each config cloud */
index++) {
return (rval);
}
}
return (0);
}
/*
* usb_free_all_configs:
* frees all allocated resources
*/
static void
{
"dev=0x%x config=0x%x #conf=%d\n",
index++) {
}
}
}
/*
* usb_parse_config:
* parse config descriptor and get cloud
*
* Returns: errno
*/
static int
{
int rval;
char *cloud;
unsigned char *extra;
int extralen;
index);
0, buffer, USB_CFG_DESCR_SIZE, 0);
if (rval < USB_CFG_DESCR_SIZE) {
return (EIO);
}
rval, sizeof (usb_cfg_descr_t));
if (rval < USB_CFG_DESCR_SIZE) {
return (EIO);
}
"cfg%d: len=%d type=%d total=%d #if=%d cf=%d\n", index,
NULL) {
return (ENOMEM);
}
/* get complete cloud */
0, (char *)cloud,
return (EIO);
}
/* parse descriptor again to get extra descriptors */
if (extralen) {
"cfg%d: extra descriptors length=%d:\n",
return (ENOMEM);
}
extralen);
}
/* allocate interface array */
(int)sizeof (struct usb_interface);
NULL) {
return (ENOMEM);
}
iface++) {
if (rval != 0) {
return (rval);
}
}
return (0);
}
/*
* usb_free_config:
* frees all allocated config resources
*/
static void
{
index);
iface++) {
}
}
}
}
/*
* usb_parse_interface:
* parse an interface descriptor
*
* Returns: errno
*/
static int
char *cloud)
{
int rval;
unsigned char *extra;
int extralen;
/* count the number of alternates for this interface */
"alt %d: rval=%d expecting %d\n",
break;
}
}
"usb_parse_interface: max_alt=%d\n", max_alt);
/* allocate alt interface setting array */
return (ENOMEM);
}
if (rval != 0) {
return (rval);
}
}
return (0);
}
/*
* usb_free_interface:
* frees interface resources
*
* Returns: errno
*/
static void
{
}
}
}
/*
* usb_parse_alternate:
* parses each alternate descriptor
*
* Returns: errno
*/
static int
{
int rval;
unsigned char *extra;
int extralen;
rval);
return (EIO);
}
"cfg%d.if%d.%d: len=%d type=%d num=%d alt=%d #ep=%d c=%d"
(void) memcpy(
if (extralen) {
extralen);
return (ENOMEM);
}
(void) memcpy(
}
if (if_descr.bNumEndpoints == 0) {
return (0);
}
/* allocate endpoint array for this alternate */
(int)sizeof (struct usb_endpoint_descriptor);
return (ENOMEM);
}
if (rval != 0) {
return (rval);
}
}
return (0);
}
/*
* usb_free_alternate:
* frees all alternate resources
*/
static void
{
endpoint) {
}
}
extralen) {
}
endpoint);
}
}
/*
* usb_parse_endpoint:
* parses an endpoint descriptor
*
* Returns: errno
*/
static int
{
int rval;
unsigned char *extra;
int extralen;
"index=%d, iface=%d, alt=%d, ep=0x%x\n",
if (rval < USB_EP_DESCR_SIZE) {
return (rval);
}
"\tl=%d t=%d a=0x%x attr=0x%x max=%d int=%d\n",
if (extralen) {
"cfg%d.if%d.%d.ep%d: extralen=%d:\n",
return (ENOMEM);
}
}
return (0);
}
/*
* usb_add_device:
* adds dev to the beginning of the list
*/
static void
{
if (*list) {
} else {
}
}
/*
* usb_remove_device:
* removes dev from a list
*/
static void
{
} else {
}
}
}
/*
* usb_check_device_in_list:
* checks if dev is in list
*
* Returns: 1 (yes), 0 (no)
*/
static int
{
usb_device_t *d = list;
while (d != NULL) {
if (d == dev) {
return (1);
}
d = d->next;
}
return (0);
}
/*
* usb_free_bus:
* frees the entire bus structure, not used, just for
* completeness
*/
static void
{
}
/*
* usb_free_dev:
* frees all configs and then the device structure itself
*/
static void
{
}
/*
* usb_get_device_status:
* gets status of device
*
* Returns: ugen dev status values
*/
static int
{
error);
return (USB_DEV_STAT_UNAVAILABLE);
} else {
switch (status) {
case USB_DEV_STAT_ONLINE:
break;
"disconnected\n");
break;
case USB_DEV_STAT_RESUMED:
"Device has been resumed\n");
break;
case USB_DEV_STAT_UNAVAILABLE:
"Device is powered down\n");
break;
default:
"Device status=%d\n", status);
}
}
return (status);
}
/*
* usb_search_dev_usb:
*
* Returns: errno
*/
static int
{
return (ENOMEM);
}
return (ENOMEM);
}
return (errno);
}
/* make sure we only open ugen directories */
REG_EXTENDED) != 0)) {
return (EINVAL);
}
/* search for devices */
continue;
}
/*
* which will get them unlinked from the virtual console
*/
continue;
}
continue;
}
continue;
}
/* need to search instances */
continue;
}
int fd;
continue;
}
return (ENOMEM);
}
1)) == NULL) {
return (ENOMEM);
}
/* See if the device is online */
"usb_search_dev_usb: Couldn't open %s\n",
filename);
continue;
}
continue;
}
}
}
return (0);
}
/*
* usb_get_status:
* gets status of endpoint
*
* Returns: ugen's last cmd status
*/
static int
{
switch (status) {
case USB_LC_STAT_NOERROR:
break;
case USB_LC_STAT_CRC:
break;
case USB_LC_STAT_BITSTUFFING:
break;
break;
case USB_LC_STAT_STALL:
break;
case USB_LC_STAT_DEV_NOT_RESP:
break;
break;
case USB_LC_STAT_UNEXP_PID:
break;
case USB_LC_STAT_DATA_OVERRUN:
break;
break;
break;
break;
case USB_LC_STAT_TIMEOUT:
break;
case USB_LC_STAT_NOT_ACCESSED:
break;
break;
case USB_LC_STAT_NO_BANDWIDTH:
break;
case USB_LC_STAT_HW_ERR:
"Host Controller h/w Error\n");
break;
case USB_LC_STAT_SUSPENDED:
break;
case USB_LC_STAT_DISCONNECTED:
break;
"Interrupt buffer was full\n");
break;
case USB_LC_STAT_INVALID_REQ:
break;
case USB_LC_STAT_INTERRUPTED:
break;
case USB_LC_STAT_NO_RESOURCES:
"request\n");
break;
break;
default:
status);
break;
}
}
return (status);
}
/*
* Descriptor parsing functions, taken from USBA code
*
* usb_parse_data:
* take a raw buffer and pads it according to format
*
* Returns: USB_PARSE_ERROR or length parsed
*/
static size_t
{
int fmt;
int multiplier = 0;
return (USB_PARSE_ERROR);
}
/*
* Could some one pass a "format" that is greater than
* the structlen? Conversely, one could pass a ret_buf_len
* that is less than the "format" length.
* If so, we need to protect against writing over memory.
*/
break;
}
if (fmt == 'c') {
~(_CHAR_ALIGNMENT - 1));
break;
if (multiplier) {
multiplier--;
}
if (multiplier == 0) {
format++;
}
} else if (fmt == 's') {
~(_SHORT_ALIGNMENT - 1));
break;
data += 2;
if (multiplier) {
multiplier--;
}
if (multiplier == 0) {
format++;
}
} else if (fmt == 'l') {
~(_INT_ALIGNMENT - 1));
break;
*lp++ = (((((
data += 4;
if (multiplier) {
multiplier--;
}
if (multiplier == 0) {
format++;
}
} else if (fmt == 'L') {
~(_LONG_LONG_ALIGNMENT - 1));
break;
data[0];
data += 8;
if (multiplier) {
multiplier--;
}
if (multiplier == 0) {
format++;
}
counter--;
format++;
} else {
multiplier = 0;
break;
}
}
}
/*
* usb_nth_descr:
* finds pointer to n-th descriptor of
* type descr_type, unless the end of the buffer or a descriptor
* of type stop_descr_type1 or stop_descr_type2 is encountered first.
*
* Returns: returns pointer to n-th descriptor
*/
static uchar_t *
int stop_descr_type1, int stop_descr_type2)
{
return (NULL);
}
return (NULL);
}
if ((descr_type == USB_DESCR_TYPE_ANY) ||
if (n-- == 0) {
return (buf);
}
}
/*
* Check for a bad buffer.
* If buf[0] is 0, then this will be an infite loop
*/
}
return (NULL);
}
/*
* usb_parse_dev_descr:
* parse device descriptor
*
* Returns: #bytes parsed
*/
static size_t
{
return (USB_PARSE_ERROR);
}
return (usb_parse_data("ccsccccssscccc",
}
/*
* usb_parse_cfg_descr:
* parse config descriptor
*
* Returns: #bytes parsed
*/
static size_t
{
return (USB_PARSE_ERROR);
}
return (rval);
}
/*
* usb_parse_if_descr:
* parse interface descriptor
*
* Returns: #bytes parsed
*/
static size_t
{
return (USB_PARSE_ERROR);
}
return (rval);
}
/*
* Check for a bad buffer.
* If buf[0] is 0, then this will be an infinite loop
*/
}
return (USB_PARSE_ERROR);
}
/*
* usb_parse_ep_descr:
* parse config descriptor
* the endpoint index is relative to the interface. index 0 is
* the first endpoint
*
* Returns: #bytes parsed
*/
{
return (USB_PARSE_ERROR);
}
break;
}
return (rval);
}
/*
* Check for a bad buffer.
* If buf[0] is 0, then this will be an infinite loop
*/
}
return (USB_PARSE_ERROR);
}
/*
* extra descriptor handling
*
* usb_find_extra:
* finds any non-standard descriptor after the current
* standard descriptor and puts a pointer in extra argument
* and the length in extralen
*/
static void
{
*extralen = 0;
return;
}
}
}
/*
* error handling
*
* usb_strerror:
* lookup error string
*
* Returns: error string
*/
char *
usb_strerror(void)
{
switch (usb_error_type) {
case USB_ERROR_TYPE_NONE:
return ("No error");
case USB_ERROR_TYPE_STRING:
return (usb_error_string);
case USB_ERROR_TYPE_ERRNO:
if (usb_error_errno > 0) {
return (strerror(usb_error_errno));
}
default:
break;
}
return ("Unknown error");
}
/*
* usb_error:
* stores the error number in the global usb_error_errno
*
* Returns: negative error number
*/
static int
usb_error(int x)
{
usb_error_errno = x;
return (-x);
}
/*
* usb_error_str:
* creates error string
*/
static void
{
usb_error_errno = x;
}
/*
* usb_dprintf:
* prints out tracing messages according to level
*/
static void
{
if (libusb_debug >= level) {
}
}
/*
* usb_dump_data:
* print data buffer
*/
static void
{
int i;
if (libusb_debug >= DEBUG_DATA_DUMP) {
for (i = 0; i < size; i++) {
if (i % 16 == 0) {
}
}
}
}