freebsd-dev/lib/libusb/libusb10_desc.c
Andrew Thompson 8c8fff3177 Add files missed in r194674.
Add libusb 1.0 support which is compatible with the latest revision on
Sourceforge. Libusb 1.0 is a portable usb api released December 2008 and
supersedes the original libusb released 10 years ago, it supports isochronous
endpoints and asynchronous I/O.  Many applications have already started using
the interfaces.

This has been developed as part of Google Summer of Code this year by Sylvestre
Gallon and has been cribbed early due to it being desirable in FreeBSD 8.0

Submitted by: Sylvestre Gallon
Sponsored by: Google Summer of Code 2009
Reviewed by:  Hans Petter Selasky
2009-06-23 01:04:58 +00:00

302 lines
9.7 KiB
C

/* $FreeBSD$ */
/*-
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/queue.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include "libusb20.h"
#include "libusb20_desc.h"
#include "libusb20_int.h"
#include "libusb.h"
#include "libusb10.h"
/* USB descriptors */
int
libusb_get_device_descriptor(libusb_device * dev,
struct libusb_device_descriptor *desc)
{
struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
struct libusb20_device *pdev;
libusb_context *ctx;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_descriptor enter");
if ((dev == NULL) || (desc == NULL))
return (LIBUSB_ERROR_INVALID_PARAM);
pdev = dev->os_priv;
pdesc = libusb20_dev_get_device_desc(pdev);
desc->bLength = pdesc->bLength;
desc->bDescriptorType = pdesc->bDescriptorType;
desc->bcdUSB = pdesc->bcdUSB;
desc->bDeviceClass = pdesc->bDeviceClass;
desc->bDeviceSubClass = pdesc->bDeviceSubClass;
desc->bDeviceProtocol = pdesc->bDeviceProtocol;
desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0;
desc->idVendor = pdesc->idVendor;
desc->idProduct = pdesc->idProduct;
desc->bcdDevice = pdesc->bcdDevice;
desc->iManufacturer = pdesc->iManufacturer;
desc->iProduct = pdesc->iProduct;
desc->iSerialNumber = pdesc->iSerialNumber;
desc->bNumConfigurations = pdesc->bNumConfigurations;
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_descriptor leave");
return (0);
}
int
libusb_get_active_config_descriptor(libusb_device * dev,
struct libusb_config_descriptor **config)
{
struct libusb20_device *pdev;
libusb_context *ctx;
uint8_t idx;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_active_config_descriptor enter");
pdev = dev->os_priv;
idx = libusb20_dev_get_config_index(pdev);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_active_config_descriptor leave");
return (libusb_get_config_descriptor(dev, idx, config));
}
/*
* XXX Need to check if extra need a dup because
* XXX free pconf could free this char *
*/
int
libusb_get_config_descriptor(libusb_device * dev, uint8_t config_index,
struct libusb_config_descriptor **config)
{
struct libusb20_device *pdev;
struct libusb20_config *pconf;
struct libusb20_interface *pinf;
struct libusb20_endpoint *pend;
libusb_interface_descriptor *ifd;
libusb_endpoint_descriptor *endd;
libusb_context *ctx;
uint8_t nif, nend, nalt, i, j, k;
uint32_t if_idx, endp_idx;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor enter");
if (dev == NULL || config == NULL)
return (LIBUSB_ERROR_INVALID_PARAM);
pdev = dev->os_priv;
pconf = libusb20_dev_alloc_config(pdev, config_index);
if (pconf == NULL)
return (LIBUSB_ERROR_NOT_FOUND);
nalt = nif = pconf->num_interface;
nend = 0;
for (i = 0 ; i < nif ; i++) {
if (pconf->interface[i].num_altsetting > 0)
{
nalt += pconf->interface[i].num_altsetting;
for (j = 0 ; j < nalt ; j++) {
nend += pconf->interface[i].altsetting[j].num_endpoints;
}
}
nend += pconf->interface[i].num_endpoints;
}
*config = malloc(sizeof(libusb_config_descriptor) +
(nif * sizeof(libusb_interface)) +
(nalt * sizeof(libusb_interface_descriptor)) +
(nend * sizeof(libusb_endpoint_descriptor)));
if (*config == NULL) {
free(pconf);
return (LIBUSB_ERROR_NO_MEM);
}
(*config)->interface = (libusb_interface *)(*config +
sizeof(libusb_config_descriptor));
for (i = if_idx = endp_idx = 0 ; i < nif ; if_idx, i++) {
(*config)->interface[i].altsetting = (libusb_interface_descriptor *)
(*config + sizeof(libusb_config_descriptor) +
(nif * sizeof(libusb_interface)) +
(if_idx * sizeof(libusb_interface_descriptor)));
(*config)->interface[i].altsetting[0].endpoint =
(libusb_endpoint_descriptor *) (*config +
sizeof(libusb_config_descriptor) +
(nif * sizeof(libusb_interface)) +
(nalt * sizeof(libusb_interface_descriptor)) +
(endp_idx * sizeof(libusb_endpoint_descriptor)));
endp_idx += pconf->interface[i].num_endpoints;
if (pconf->interface[i].num_altsetting > 0)
{
for (j = 0 ; j < pconf->interface[i].num_altsetting ; j++, if_idx++) {
(*config)->interface[i].altsetting[j + 1].endpoint =
(libusb_endpoint_descriptor *) (*config +
sizeof(libusb_config_descriptor) +
(nif * sizeof(libusb_interface)) +
(nalt * sizeof(libusb_interface_descriptor)) +
(endp_idx * sizeof(libusb_endpoint_descriptor)));
endp_idx += pconf->interface[i].altsetting[j].num_endpoints;
}
}
}
(*config)->bLength = pconf->desc.bLength;
(*config)->bDescriptorType = pconf->desc.bDescriptorType;
(*config)->wTotalLength = pconf->desc.wTotalLength;
(*config)->bNumInterfaces = pconf->desc.bNumInterfaces;
(*config)->bConfigurationValue = pconf->desc.bConfigurationValue;
(*config)->iConfiguration = pconf->desc.iConfiguration;
(*config)->bmAttributes = pconf->desc.bmAttributes;
(*config)->MaxPower = pconf->desc.bMaxPower;
(*config)->extra_length = pconf->extra.len;
if ((*config)->extra_length != 0)
(*config)->extra = pconf->extra.ptr;
for (i = 0 ; i < nif ; i++) {
pinf = &pconf->interface[i];
(*config)->interface[i].num_altsetting = pinf->num_altsetting + 1;
for (j = 0 ; j < (*config)->interface[i].num_altsetting ; j++) {
if (j != 0)
pinf = &pconf->interface[i].altsetting[j - 1];
ifd = &(*config)->interface[i].altsetting[j];
ifd->bLength = pinf->desc.bLength;
ifd->bDescriptorType = pinf->desc.bDescriptorType;
ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber;
ifd->bAlternateSetting = pinf->desc.bAlternateSetting;
ifd->bNumEndpoints = pinf->desc.bNumEndpoints;
ifd->bInterfaceClass = pinf->desc.bInterfaceClass;
ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass;
ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol;
ifd->iInterface = pinf->desc.iInterface;
ifd->extra_length = pinf->extra.len;
if (ifd->extra_length != 0)
ifd->extra = pinf->extra.ptr;
for (k = 0 ; k < pinf->num_endpoints ; k++) {
pend = &pinf->endpoints[k];
endd = &ifd->endpoint[k];
endd->bLength = pend->desc.bLength;
endd->bDescriptorType = pend->desc.bDescriptorType;
endd->bEndpointAddress = pend->desc.bEndpointAddress;
endd->bmAttributes = pend->desc.bmAttributes;
endd->wMaxPacketSize = pend->desc.wMaxPacketSize;
endd->bInterval = pend->desc.bInterval;
endd->bRefresh = pend->desc.bRefresh;
endd->bSynchAddress = pend->desc.bSynchAddress;
endd->extra_length = pend->extra.len;
if (endd->extra_length != 0)
endd->extra = pend->extra.ptr;
}
}
}
free(pconf);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor leave");
return (0);
}
int
libusb_get_config_descriptor_by_value(libusb_device * dev,
uint8_t bConfigurationValue, struct libusb_config_descriptor **config)
{
struct LIBUSB20_DEVICE_DESC_DECODED *pdesc;
struct libusb20_device *pdev;
struct libusb20_config *pconf;
libusb_context *ctx;
int i;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor_by_value enter");
if (dev == NULL || config == NULL)
return (LIBUSB_ERROR_INVALID_PARAM);
pdev = dev->os_priv;
pdesc = libusb20_dev_get_device_desc(pdev);
for (i = 0 ; i < pdesc->bNumConfigurations ; i++) {
pconf = libusb20_dev_alloc_config(pdev, i);
if (pconf->desc.bConfigurationValue == bConfigurationValue) {
free(pconf);
return libusb_get_config_descriptor(dev, i, config);
}
free(pconf);
}
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor_by_value leave");
return (LIBUSB_ERROR_NOT_FOUND);
}
void
libusb_free_config_descriptor(struct libusb_config_descriptor *config)
{
libusb_context *ctx;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_config_descriptor enter");
free(config);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_config_descriptor leave");
}
int
libusb_get_string_descriptor_ascii(libusb_device_handle * dev,
uint8_t desc_index, unsigned char *data, int length)
{
struct libusb20_device *pdev;
libusb_context *ctx;
int ret;
ctx = NULL;
GET_CONTEXT(ctx);
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_string_descriptor_ascii enter");
if (dev == NULL || data == NULL)
return (LIBUSB20_ERROR_INVALID_PARAM);
pdev = dev->os_priv;
dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_string_descriptor_ascii leave");
if (libusb20_dev_req_string_simple_sync(pdev, desc_index,
data, length) == 0)
return (strlen(data));
return (LIBUSB_ERROR_OTHER);
}