📄 usb.c
字号:
*
* If successful, it returns 0, othwise a negative error number.
* The number of actual bytes transferred will be plaed in the
* actual_timeout paramater.
*
* Don't use this function from within an interrupt context, like a
* bottom half handler. If you need a asyncronous message, or need to
* send a message from within interrupt context, use usb_submit_urb()
*/
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,void *data, int len, int *actual_length, int timeout)
{
urb_t *urb;
if (len < 0)
return -EINVAL;
urb=usb_alloc_urb(0);
if (!urb)
return -ENOMEM;
/* build urb */
FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len, (usb_complete_t)usb_api_blocking_completion,0);
return usb_start_wait_urb(urb,timeout,actual_length);
}
/*
* usb_get_current_frame_number()
*
* returns the current frame number for the parent USB bus/controller
* of the given USB device.
*/
int usb_get_current_frame_number(struct usb_device *usb_dev)
{
return usb_dev->bus->op->get_frame_number (usb_dev);
}
/*-------------------------------------------------------------------*/
static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
{
struct usb_descriptor_header *header;
unsigned char *begin;
int parsed = 0;
int len;
int numskipped;
header = (struct usb_descriptor_header *)buffer;
/* Everything should be fine being passed into here, but we sanity */
/* check JIC */
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
if (header->bDescriptorType != USB_DT_ENDPOINT) {
warn("unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X",
endpoint->bDescriptorType, USB_DT_ENDPOINT);
return parsed;
}
if (header->bLength == USB_DT_ENDPOINT_AUDIO_SIZE)
memcpy(endpoint, buffer, USB_DT_ENDPOINT_AUDIO_SIZE);
else
memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE);
le16_to_cpus(endpoint->wMaxPacketSize);
buffer =buffer + header->bLength;
size =size - header->bLength;
parsed =parsed + header->bLength;
/* Skip over the rest of the Class Specific or Vendor Specific */
/* descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
printf("skipping descriptor 0x%d",
header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
parsed += header->bLength;
}
// if (numskipped)
// dbg("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for drivers */
/* to later parse */
len = (int)(buffer - begin);
if (!len) {
endpoint->extra = NULL;
endpoint->extralen = 0;
return parsed;
}
endpoint->extra = (unsigned char *)malloc(len);
if (!endpoint->extra) {
err("couldn't allocate memory for endpoint extra descriptors");
endpoint->extralen = 0;
return parsed;
}
memcpy(endpoint->extra, begin, len);
endpoint->extralen = len;
return parsed;
}
static int usb_parse_interface(struct usb_interface *interfacep, unsigned char *buffer, int size)
{
int i, len, numskipped, retval, parsed = 0;
struct usb_descriptor_header *header;
struct usb_interface_descriptor *ifp;
unsigned char *begin;
interfacep->act_altsetting = 0;
interfacep->num_altsetting = 0;
interfacep->max_altsetting = USB_ALTSETTINGALLOC;
interfacep->altsetting = (struct usb_interface_descriptor *)malloc(sizeof(struct usb_interface_descriptor) * interfacep->max_altsetting);
if (!interfacep->altsetting) {
err("couldn't malloc interface->altsetting");
return -1;
}
while (size > 0) {
if (interfacep->num_altsetting >= interfacep->max_altsetting) {
void *ptr;
int oldmas;
oldmas = interfacep->max_altsetting;
interfacep->max_altsetting += USB_ALTSETTINGALLOC;
if (interfacep->max_altsetting > USB_MAXALTSETTING) {
warn("too many alternate settings (max %d)",
USB_MAXALTSETTING);
return -1;
}
ptr = interfacep->altsetting;
interfacep->altsetting = (struct usb_interface_descriptor *)malloc(sizeof(struct usb_interface_descriptor) * interfacep->max_altsetting);
if (!interfacep->altsetting) {
err("couldn't malloc interface->altsetting");
interfacep->altsetting = ptr;
return -1;
}
memcpy(interfacep->altsetting, ptr, sizeof(struct usb_interface_descriptor) * oldmas);
free(ptr);
}
ifp = interfacep->altsetting + interfacep->num_altsetting;
interfacep->num_altsetting++;
memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE);
/* Skip over the interface */
buffer += ifp->bLength;
parsed += ifp->bLength;
size -= ifp->bLength;
begin = buffer;
numskipped = 0;
/* Skip over any interface, class or vendor descriptors */
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
numskipped++;
buffer += header->bLength;
parsed += header->bLength;
size -= header->bLength;
}
if (numskipped)
printf("skipped %d class/vendor specific interface descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (!len) {
ifp->extra = NULL;
ifp->extralen = 0;
} else {
ifp->extra = (unsigned char *)malloc(len);
if (!ifp->extra) {
err("couldn't allocate memory for interface extra descriptors");
ifp->extralen = 0;
return -1;
}
memcpy(ifp->extra, begin, len);
ifp->extralen = len;
}
/* Did we hit an unexpected descriptor? */
header = (struct usb_descriptor_header *)buffer;
if ((size >= sizeof(struct usb_descriptor_header)) &&
((header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE)))
return parsed;
if (ifp->bNumEndpoints > USB_MAXENDPOINTS) {
warn("too many endpoints");
return -1;
}
ifp->endpoint = (struct usb_endpoint_descriptor *)
malloc(ifp->bNumEndpoints *
sizeof(struct usb_endpoint_descriptor));
if (!ifp->endpoint) {
err("out of memory");
return -1;
}
memset(ifp->endpoint, 0, ifp->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
for (i = 0; i < ifp->bNumEndpoints; i++) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength > size) {
err("ran out of descriptors parsing");
return -1;
}
retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
parsed += retval;
size -= retval;
}
/* We check to see if it's an alternate to this one */
ifp = (struct usb_interface_descriptor *)buffer;
if ((size < USB_DT_INTERFACE_SIZE)||(ifp->bDescriptorType != USB_DT_INTERFACE)||(!ifp->bAlternateSetting))
return parsed;
}
return parsed;
}
int usb_parse_configuration(struct usb_config_descriptor *config, unsigned char *buffer)
{
int i, retval, size;
struct usb_descriptor_header *header;
memcpy(config, buffer, USB_DT_CONFIG_SIZE);
le16_to_cpus(&config->wTotalLength);
size = config->wTotalLength;
if (config->bNumInterfaces > USB_MAXINTERFACES) {
warn("too many interfaces");
return -1;
}
config->interface = (struct usb_interface *)
malloc(config->bNumInterfaces *
sizeof(struct usb_interface));
// dbg("malloc IF %p, numif %i", config->interface, config->bNumInterfaces);
if (!config->interface) {
err("out of memory");
return -1;
}
memset(config->interface, 0,
config->bNumInterfaces * sizeof(struct usb_interface));
buffer += config->bLength;
size -= config->bLength;
config->extra = NULL;
config->extralen = 0;
for (i = 0; i < config->bNumInterfaces; i++) {
int numskipped, len;
char *begin;
/* Skip over the rest of the Class Specific or Vendor */
/* Specific descriptors */
begin = buffer;
numskipped = 0;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if ((header->bLength > size) || (header->bLength < 2)) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
/* If we find another "proper" descriptor then we're done */
if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
(header->bDescriptorType == USB_DT_INTERFACE) ||
(header->bDescriptorType == USB_DT_CONFIG) ||
(header->bDescriptorType == USB_DT_DEVICE))
break;
printf("skipping descriptor 0x%d", header->bDescriptorType);
numskipped++;
buffer += header->bLength;
size -= header->bLength;
}
if (numskipped)
printf("skipped %d class/vendor specific endpoint descriptors", numskipped);
/* Copy any unknown descriptors into a storage area for */
/* drivers to later parse */
len = (int)(buffer - begin);
if (len) {
if (config->extralen) {
warn("extra config descriptor");
} else {
config->extra = (unsigned char *)malloc(len);
if (!config->extra) {
err("couldn't allocate memory for config extra descriptors");
config->extralen = 0;
return -1;
}
memcpy(config->extra, begin, len);
config->extralen = len;
}
}
retval = usb_parse_interface(config->interface + i, buffer, size);
if (retval < 0)
return retval;
buffer += retval;
size -= retval;
}
return size;
}
/* for returning string descriptors in UTF-16LE */
static int ascii2utf (char *ascii, __u8 *utf, int utfmax)
{
int retval;
for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
*utf++ = *ascii++ & 0x7f;
*utf++ = 0;
}
return retval;
}
/*
* root_hub_string is used by each host controller's root hub code,
* so that they're identified consistently throughout the system.
*/
int usb_root_hub_string (int id, int serial, char *type, __u8 *data, int len)
{
char buf [30];
// assert (len > (2 * (sizeof (buf) + 1)));
// assert (strlen (type) <= 8);
// language ids
if (id == 0) {
*data++ = 4; *data++ = 3; /* 4 bytes data */
*data++ = 0; *data++ = 0; /* some language id */
return 4;
// serial number
} else if (id == 1) {
sprintf (buf, "%x", serial);
// product description
} else if (id == 2) {
sprintf (buf, "USB %s Root Hub", type);
// id 3 == vendor description
// unsupported IDs --> "stall"
} else
return 0;
data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
data [1] = 3;
return data [0];
}
/*
* __usb_get_extra_descriptor() finds a descriptor of specific type in the
* extra field of the interface and endpoint descriptor structs.
*/
int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
{
struct usb_descriptor_header *header;
while (size >= sizeof(struct usb_descriptor_header)) {
header = (struct usb_descriptor_header *)buffer;
if (header->bLength < 2) {
err("invalid descriptor length of %d", header->bLength);
return -1;
}
if (header->bDescriptorType == type) {
*ptr = header;
return 0;
}
buffer += header->bLength;
size -= header->bLength;
}
return -1;
}
/*
* Something got disconnected. Get rid of it, and all of its children.
*/
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device * dev = *pdev;
int i;
if (!dev)
return;
*pdev = NULL;
info("USB disconnect on device %d", dev->devnum);
if (dev->actconfig) {
for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
struct usb_interface *interface = &dev->actconfig->interface[i];
struct usb_driver *driver = interface->driver;
if (driver) {
// down(&driver->serialize);
driver->disconnect(dev, interface->private_data);
// up(&driver->serialize);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -