diff options
| author | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2011-08-08 14:30:29 +0200 | 
| commit | 0a2d31b62dba9b5b92a38c67c9cc42630513662a (patch) | |
| tree | f755d74ec85248de645e10c45ed1a2ed467530f6 /drivers/usb/gadget/f_ecm.c | |
| parent | 8039290a91c5dc4414093c086987a5d7738fe2fd (diff) | |
| parent | df944f66784e6d4f2f50739263a4947885d8b6ae (diff) | |
Merge branch 'fix/kconfig' into for-linus
Diffstat (limited to 'drivers/usb/gadget/f_ecm.c')
| -rw-r--r-- | drivers/usb/gadget/f_ecm.c | 152 | 
1 files changed, 115 insertions, 37 deletions
| diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index 544257a89ed2..3691a0cb9465 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -46,11 +46,6 @@   * and also means that a get_alt() method is required.   */ -struct ecm_ep_descs { -	struct usb_endpoint_descriptor	*in; -	struct usb_endpoint_descriptor	*out; -	struct usb_endpoint_descriptor	*notify; -};  enum ecm_notify_state {  	ECM_NOTIFY_NONE,		/* don't notify */ @@ -64,11 +59,7 @@ struct f_ecm {  	char				ethaddr[14]; -	struct ecm_ep_descs		fs; -	struct ecm_ep_descs		hs; -  	struct usb_ep			*notify; -	struct usb_endpoint_descriptor	*notify_desc;  	struct usb_request		*notify_req;  	u8				notify_state;  	bool				is_open; @@ -86,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)  /* peak (theoretical) bulk transfer rate in bits-per-second */  static inline unsigned ecm_bitrate(struct usb_gadget *g)  { -	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) +	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) +		return 13 * 1024 * 8 * 1000 * 8; +	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)  		return 13 * 512 * 8 * 1000 * 8;  	else -		return 19 *  64 * 1 * 1000 * 8; +		return 19 * 64 * 1 * 1000 * 8;  }  /*-------------------------------------------------------------------------*/ @@ -219,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = {  	(struct usb_descriptor_header *) &ecm_header_desc,  	(struct usb_descriptor_header *) &ecm_union_desc,  	(struct usb_descriptor_header *) &ecm_desc, +  	/* NOTE: status endpoint might need to be removed */  	(struct usb_descriptor_header *) &fs_ecm_notify_desc, +  	/* data interface, altsettings 0 and 1 */  	(struct usb_descriptor_header *) &ecm_data_nop_intf,  	(struct usb_descriptor_header *) &ecm_data_intf, @@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {  	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),  	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,  }; +  static struct usb_endpoint_descriptor hs_ecm_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = {  	(struct usb_descriptor_header *) &ecm_header_desc,  	(struct usb_descriptor_header *) &ecm_union_desc,  	(struct usb_descriptor_header *) &ecm_desc, +  	/* NOTE: status endpoint might need to be removed */  	(struct usb_descriptor_header *) &hs_ecm_notify_desc, +  	/* data interface, altsettings 0 and 1 */  	(struct usb_descriptor_header *) &ecm_data_nop_intf,  	(struct usb_descriptor_header *) &ecm_data_intf, @@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {  	NULL,  }; +/* super speed support: */ + +static struct usb_endpoint_descriptor ss_ecm_notify_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_INT, +	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT), +	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4, +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = { +	.bLength =		sizeof ss_ecm_intr_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 3 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +	.wBytesPerInterval =	cpu_to_le16(ECM_STATUS_BYTECOUNT), +}; + +static struct usb_endpoint_descriptor ss_ecm_in_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_IN, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_ecm_out_desc = { +	.bLength =		USB_DT_ENDPOINT_SIZE, +	.bDescriptorType =	USB_DT_ENDPOINT, + +	.bEndpointAddress =	USB_DIR_OUT, +	.bmAttributes =		USB_ENDPOINT_XFER_BULK, +	.wMaxPacketSize =	cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = { +	.bLength =		sizeof ss_ecm_bulk_comp_desc, +	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, + +	/* the following 2 values can be tweaked if necessary */ +	/* .bMaxBurst =		0, */ +	/* .bmAttributes =	0, */ +}; + +static struct usb_descriptor_header *ecm_ss_function[] = { +	/* CDC ECM control descriptors */ +	(struct usb_descriptor_header *) &ecm_control_intf, +	(struct usb_descriptor_header *) &ecm_header_desc, +	(struct usb_descriptor_header *) &ecm_union_desc, +	(struct usb_descriptor_header *) &ecm_desc, + +	/* NOTE: status endpoint might need to be removed */ +	(struct usb_descriptor_header *) &ss_ecm_notify_desc, +	(struct usb_descriptor_header *) &ss_ecm_intr_comp_desc, + +	/* data interface, altsettings 0 and 1 */ +	(struct usb_descriptor_header *) &ecm_data_nop_intf, +	(struct usb_descriptor_header *) &ecm_data_intf, +	(struct usb_descriptor_header *) &ss_ecm_in_desc, +	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, +	(struct usb_descriptor_header *) &ss_ecm_out_desc, +	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc, +	NULL, +}; +  /* string descriptors: */  static struct usb_string ecm_string_defs[] = { @@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  		if (ecm->notify->driver_data) {  			VDBG(cdev, "reset ecm control %d\n", intf);  			usb_ep_disable(ecm->notify); -		} else { +		} +		if (!(ecm->notify->desc)) {  			VDBG(cdev, "init ecm ctrl %d\n", intf); -			ecm->notify_desc = ep_choose(cdev->gadget, -					ecm->hs.notify, -					ecm->fs.notify); +			if (config_ep_by_speed(cdev->gadget, f, ecm->notify)) +				goto fail;  		} -		usb_ep_enable(ecm->notify, ecm->notify_desc); +		usb_ep_enable(ecm->notify);  		ecm->notify->driver_data = ecm;  	/* Data interface has two altsettings, 0 and 1 */ @@ -483,12 +551,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			gether_disconnect(&ecm->port);  		} -		if (!ecm->port.in) { +		if (!ecm->port.in_ep->desc || +		    !ecm->port.out_ep->desc) {  			DBG(cdev, "init ecm\n"); -			ecm->port.in = ep_choose(cdev->gadget, -					ecm->hs.in, ecm->fs.in); -			ecm->port.out = ep_choose(cdev->gadget, -					ecm->hs.out, ecm->fs.out); +			if (config_ep_by_speed(cdev->gadget, f, +					       ecm->port.in_ep) || +			    config_ep_by_speed(cdev->gadget, f, +					       ecm->port.out_ep)) { +				ecm->port.in_ep->desc = NULL; +				ecm->port.out_ep->desc = NULL; +				goto fail; +			}  		}  		/* CDC Ethernet only sends data in non-default altsettings. @@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f)  	if (ecm->notify->driver_data) {  		usb_ep_disable(ecm->notify);  		ecm->notify->driver_data = NULL; -		ecm->notify_desc = NULL; +		ecm->notify->desc = NULL;  	}  } @@ -665,13 +738,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	if (!f->descriptors)  		goto fail; -	ecm->fs.in = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_in_desc); -	ecm->fs.out = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_out_desc); -	ecm->fs.notify = usb_find_endpoint(ecm_fs_function, -			f->descriptors, &fs_ecm_notify_desc); -  	/* support all relevant hardware speeds... we expect that when  	 * hardware is dual speed, all bulk-capable endpoints work at  	 * both speeds @@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);  		if (!f->hs_descriptors)  			goto fail; +	} -		ecm->hs.in = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_in_desc); -		ecm->hs.out = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_out_desc); -		ecm->hs.notify = usb_find_endpoint(ecm_hs_function, -				f->hs_descriptors, &hs_ecm_notify_desc); +	if (gadget_is_superspeed(c->cdev->gadget)) { +		ss_ecm_in_desc.bEndpointAddress = +				fs_ecm_in_desc.bEndpointAddress; +		ss_ecm_out_desc.bEndpointAddress = +				fs_ecm_out_desc.bEndpointAddress; +		ss_ecm_notify_desc.bEndpointAddress = +				fs_ecm_notify_desc.bEndpointAddress; + +		/* copy descriptors, and track endpoint copies */ +		f->ss_descriptors = usb_copy_descriptors(ecm_ss_function); +		if (!f->ss_descriptors) +			goto fail;  	}  	/* NOTE:  all that is done without knowing or caring about @@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	ecm->port.close = ecm_close;  	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n", +			gadget_is_superspeed(c->cdev->gadget) ? "super" :  			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",  			ecm->port.in_ep->name, ecm->port.out_ep->name,  			ecm->notify->name); @@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  fail:  	if (f->descriptors)  		usb_free_descriptors(f->descriptors); +	if (f->hs_descriptors) +		usb_free_descriptors(f->hs_descriptors);  	if (ecm->notify_req) {  		kfree(ecm->notify_req->buf); @@ -723,9 +799,9 @@ fail:  	/* we might as well release our claims on endpoints */  	if (ecm->notify)  		ecm->notify->driver_data = NULL; -	if (ecm->port.out) +	if (ecm->port.out_ep->desc)  		ecm->port.out_ep->driver_data = NULL; -	if (ecm->port.in) +	if (ecm->port.in_ep->desc)  		ecm->port.in_ep->driver_data = NULL;  	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); @@ -740,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)  	DBG(c->cdev, "ecm unbind\n"); +	if (gadget_is_superspeed(c->cdev->gadget)) +		usb_free_descriptors(f->ss_descriptors);  	if (gadget_is_dualspeed(c->cdev->gadget))  		usb_free_descriptors(f->hs_descriptors);  	usb_free_descriptors(f->descriptors); | 
