config.c

来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 572 行 · 第 1/2 页

C
572
字号
#include <linux/usb.h>#include <linux/usb/ch9.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/device.h>#include <asm/byteorder.h>#include "usb.h"#include "hcd.h"#define USB_MAXALTSETTING		128	/* Hard limit */#define USB_MAXENDPOINTS		30	/* Hard limit */#define USB_MAXCONFIG			8	/* Arbitrary limit */static inline const char *plural(int n){	return (n == 1 ? "" : "s");}static int find_next_descriptor(unsigned char *buffer, int size,    int dt1, int dt2, int *num_skipped){	struct usb_descriptor_header *h;	int n = 0;	unsigned char *buffer0 = buffer;	/* Find the next descriptor of type dt1 or dt2 */	while (size > 0) {		h = (struct usb_descriptor_header *) buffer;		if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2)			break;		buffer += h->bLength;		size -= h->bLength;		++n;	}	/* Store the number of descriptors skipped and return the	 * number of bytes skipped */	if (num_skipped)		*num_skipped = n;	return buffer - buffer0;}static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,    int asnum, struct usb_host_interface *ifp, int num_ep,    unsigned char *buffer, int size){	unsigned char *buffer0 = buffer;	struct usb_endpoint_descriptor *d;	struct usb_host_endpoint *endpoint;	int n, i, j;	d = (struct usb_endpoint_descriptor *) buffer;	buffer += d->bLength;	size -= d->bLength;	if (d->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE)		n = USB_DT_ENDPOINT_AUDIO_SIZE;	else if (d->bLength >= USB_DT_ENDPOINT_SIZE)		n = USB_DT_ENDPOINT_SIZE;	else {		dev_warn(ddev, "config %d interface %d altsetting %d has an "		    "invalid endpoint descriptor of length %d, skipping\n",		    cfgno, inum, asnum, d->bLength);		goto skip_to_next_endpoint_or_interface_descriptor;	}	i = d->bEndpointAddress & ~USB_ENDPOINT_DIR_MASK;	if (i >= 16 || i == 0) {		dev_warn(ddev, "config %d interface %d altsetting %d has an "		    "invalid endpoint with address 0x%X, skipping\n",		    cfgno, inum, asnum, d->bEndpointAddress);		goto skip_to_next_endpoint_or_interface_descriptor;	}	/* Only store as many endpoints as we have room for */	if (ifp->desc.bNumEndpoints >= num_ep)		goto skip_to_next_endpoint_or_interface_descriptor;	endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];	++ifp->desc.bNumEndpoints;	memcpy(&endpoint->desc, d, n);	INIT_LIST_HEAD(&endpoint->urb_list);	/* If the bInterval value is outside the legal range,	 * set it to a default value: 32 ms */	i = 0;		/* i = min, j = max, n = default */	j = 255;	if (usb_endpoint_xfer_int(d)) {		i = 1;		switch (to_usb_device(ddev)->speed) {		case USB_SPEED_HIGH:			n = 9;		/* 32 ms = 2^(9-1) uframes */			j = 16;			break;		default:		/* USB_SPEED_FULL or _LOW */			/* For low-speed, 10 ms is the official minimum.			 * But some "overclocked" devices might want faster			 * polling so we'll allow it. */			n = 32;			break;		}	} else if (usb_endpoint_xfer_isoc(d)) {		i = 1;		j = 16;		switch (to_usb_device(ddev)->speed) {		case USB_SPEED_HIGH:			n = 9;		/* 32 ms = 2^(9-1) uframes */			break;		default:		/* USB_SPEED_FULL */			n = 6;		/* 32 ms = 2^(6-1) frames */			break;		}	}	if (d->bInterval < i || d->bInterval > j) {		dev_warn(ddev, "config %d interface %d altsetting %d "		    "endpoint 0x%X has an invalid bInterval %d, "		    "changing to %d\n",		    cfgno, inum, asnum,		    d->bEndpointAddress, d->bInterval, n);		endpoint->desc.bInterval = n;	}	/* Skip over any Class Specific or Vendor Specific descriptors;	 * find the next endpoint or interface descriptor */	endpoint->extra = buffer;	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,	    USB_DT_INTERFACE, &n);	endpoint->extralen = i;	if (n > 0)		dev_dbg(ddev, "skipped %d descriptor%s after %s\n",		    n, plural(n), "endpoint");	return buffer - buffer0 + i;skip_to_next_endpoint_or_interface_descriptor:	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,	    USB_DT_INTERFACE, NULL);	return buffer - buffer0 + i;}void usb_release_interface_cache(struct kref *ref){	struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);	int j;	for (j = 0; j < intfc->num_altsetting; j++) {		struct usb_host_interface *alt = &intfc->altsetting[j];		kfree(alt->endpoint);		kfree(alt->string);	}	kfree(intfc);}static int usb_parse_interface(struct device *ddev, int cfgno,    struct usb_host_config *config, unsigned char *buffer, int size,    u8 inums[], u8 nalts[]){	unsigned char *buffer0 = buffer;	struct usb_interface_descriptor	*d;	int inum, asnum;	struct usb_interface_cache *intfc;	struct usb_host_interface *alt;	int i, n;	int len, retval;	int num_ep, num_ep_orig;	d = (struct usb_interface_descriptor *) buffer;	buffer += d->bLength;	size -= d->bLength;	if (d->bLength < USB_DT_INTERFACE_SIZE)		goto skip_to_next_interface_descriptor;	/* Which interface entry is this? */	intfc = NULL;	inum = d->bInterfaceNumber;	for (i = 0; i < config->desc.bNumInterfaces; ++i) {		if (inums[i] == inum) {			intfc = config->intf_cache[i];			break;		}	}	if (!intfc || intfc->num_altsetting >= nalts[i])		goto skip_to_next_interface_descriptor;	/* Check for duplicate altsetting entries */	asnum = d->bAlternateSetting;	for ((i = 0, alt = &intfc->altsetting[0]);	      i < intfc->num_altsetting;	     (++i, ++alt)) {		if (alt->desc.bAlternateSetting == asnum) {			dev_warn(ddev, "Duplicate descriptor for config %d "			    "interface %d altsetting %d, skipping\n",			    cfgno, inum, asnum);			goto skip_to_next_interface_descriptor;		}	}	++intfc->num_altsetting;	memcpy(&alt->desc, d, USB_DT_INTERFACE_SIZE);	/* Skip over any Class Specific or Vendor Specific descriptors;	 * find the first endpoint or interface descriptor */	alt->extra = buffer;	i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,	    USB_DT_INTERFACE, &n);	alt->extralen = i;	if (n > 0)		dev_dbg(ddev, "skipped %d descriptor%s after %s\n",		    n, plural(n), "interface");	buffer += i;	size -= i;	/* Allocate space for the right(?) number of endpoints */	num_ep = num_ep_orig = alt->desc.bNumEndpoints;	alt->desc.bNumEndpoints = 0;		// Use as a counter	if (num_ep > USB_MAXENDPOINTS) {		dev_warn(ddev, "too many endpoints for config %d interface %d "		    "altsetting %d: %d, using maximum allowed: %d\n",		    cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);		num_ep = USB_MAXENDPOINTS;	}	if (num_ep > 0) {	/* Can't allocate 0 bytes */		len = sizeof(struct usb_host_endpoint) * num_ep;		alt->endpoint = kzalloc(len, GFP_KERNEL);		if (!alt->endpoint)			return -ENOMEM;	}	/* Parse all the endpoint descriptors */	n = 0;	while (size > 0) {		if (((struct usb_descriptor_header *) buffer)->bDescriptorType		     == USB_DT_INTERFACE)			break;		retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,		    num_ep, buffer, size);		if (retval < 0)			return retval;		++n;		buffer += retval;		size -= retval;	}	if (n != num_ep_orig)		dev_warn(ddev, "config %d interface %d altsetting %d has %d "		    "endpoint descriptor%s, different from the interface "		    "descriptor's value: %d\n",		    cfgno, inum, asnum, n, plural(n), num_ep_orig);	return buffer - buffer0;skip_to_next_interface_descriptor:	i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,	    USB_DT_INTERFACE, NULL);	return buffer - buffer0 + i;}static int usb_parse_configuration(struct device *ddev, int cfgidx,    struct usb_host_config *config, unsigned char *buffer, int size){	unsigned char *buffer0 = buffer;	int cfgno;	int nintf, nintf_orig;	int i, j, n;	struct usb_interface_cache *intfc;	unsigned char *buffer2;	int size2;	struct usb_descriptor_header *header;	int len, retval;	u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);	if (config->desc.bDescriptorType != USB_DT_CONFIG ||	    config->desc.bLength < USB_DT_CONFIG_SIZE) {		dev_err(ddev, "invalid descriptor for config index %d: "		    "type = 0x%X, length = %d\n", cfgidx,		    config->desc.bDescriptorType, config->desc.bLength);		return -EINVAL;	}	cfgno = config->desc.bConfigurationValue;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?