int rawbulk_function_bind(struct usb_configuration *c, struct
        usb_function *f) {
    int rc, ifnum;
    struct rawbulk_function *fn = function_to_rbf(f);
    struct usb_gadget *gadget = c->cdev->gadget;
    struct usb_ep *ep_out, *ep_in;
    
    printk("%s\n", __func__);
    rc = usb_interface_id(c, f);
    if (rc < 0)
        return rc;
    ifnum = rc;

    fn->interface.bInterfaceNumber = cpu_to_le16(ifnum);

    ep_out = usb_ep_autoconfig(gadget, (struct usb_endpoint_descriptor *)
            fn->fs_descs[BULKOUT_DESC]);
    if (!ep_out) {
        printk(KERN_ERR "%s %d config ep_out error  \n", __FUNCTION__,__LINE__);
        return -ENOMEM;
    }

    ep_in = usb_ep_autoconfig(gadget, (struct usb_endpoint_descriptor *)
            fn->fs_descs[BULKIN_DESC]);
    if (!ep_in) {
        usb_ep_disable(ep_out);
        printk(KERN_ERR "%s %d config ep_in error  \n", __FUNCTION__,__LINE__);
        return -ENOMEM;
    }

    ep_out->driver_data = fn;
    ep_in->driver_data = fn;
    fn->bulk_out = ep_out;
    fn->bulk_in = ep_in;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 4, 100))
    f->fs_descriptors = usb_copy_descriptors(fn->fs_descs);
	if (unlikely(!f->fs_descriptors))
		return -ENOMEM;
#else
	f->descriptors = usb_copy_descriptors(fn->fs_descs);
	if (unlikely(!f->descriptors))
		return -ENOMEM;
#endif

    if (gadget_is_dualspeed(gadget)) {
        fn->hs_bulkin_endpoint.bEndpointAddress =
            fn->fs_bulkin_endpoint.bEndpointAddress;
        fn->hs_bulkout_endpoint.bEndpointAddress =
            fn->fs_bulkout_endpoint.bEndpointAddress;
    }

    fn->cdev = c->cdev;
    fn->activated = 0;
   
    return rawbulk_bind_function(fn->transfer_id, f, ep_out, ep_in,
            rawbulk_auto_reconnect);
           
}
Esempio n. 2
0
int f_cloner_bind(struct usb_configuration *c,
		struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct cloner *cloner = func_to_cloner(f);

	debug_cond(BURNNER_DEBUG,"f_cloner_bind\n");

	intf_desc.bInterfaceNumber = usb_interface_id(c, f);
	if(intf_desc.bInterfaceNumber < 0 )
		return intf_desc.bInterfaceNumber;

	cloner->ep0 = cdev->gadget->ep0;
	cloner->ep0req = cdev->req;
	cloner->gadget = cdev->gadget;
	cloner->ack = 0;
	cloner->cdev = cdev;

	cloner->cmd = (union cmd *)cloner->ep0req->buf;

	if (gadget_is_dualspeed(cdev->gadget)) {
		hs_bulk_in_desc.bEndpointAddress =
			fs_bulk_in_desc.bEndpointAddress;
		hs_bulk_out_desc.bEndpointAddress =
			fs_bulk_out_desc.bEndpointAddress;
	}

	cdev->req->context = cloner;

	cloner->ep_in = usb_ep_autoconfig(cdev->gadget, &fs_bulk_in_desc);
	cloner->ep_out = usb_ep_autoconfig(cdev->gadget, &fs_bulk_out_desc);

	cloner->write_req = usb_ep_alloc_request(cloner->ep_out,0);
	cloner->args_req = usb_ep_alloc_request(cloner->ep_out,0);
	cloner->read_req = usb_ep_alloc_request(cloner->ep_in,0);

	cloner->buf_size = 1024*1024;
	cloner->buf = malloc(1024*1024);
	cloner->write_req->complete = handle_write;
	cloner->write_req->buf = cloner->buf;
	cloner->write_req->length = 1024*1024;
	cloner->write_req->context = cloner;

	cloner->args_req->complete = handle_write;
	cloner->args_req->buf = cloner->args;
	cloner->args_req->length = ARGS_LEN;
	cloner->args_req->context = cloner;

	cloner->read_req->complete = handle_read_complete;
	cloner->read_req->buf = cloner->buf;
	cloner->read_req->length = 1024*1024;
	cloner->read_req->context = cloner;

	return 0;
}
Esempio n. 3
0
static int dtf_allocate_interface_ids( struct usb_configuration *c, struct usb_function *f )
{
	int id;
	struct dtf_dev *dev = func_to_dtf(f);

	_dbgmsg( "IN\n" );

	/* Allocate Interface ID: PipeGroup1 communication interface */
	_dbgmsg_gadget( "usb_interface_id\n" );
	id = usb_interface_id(c, f);
	_dbgmsg( "usb_interface_id() = %d\n", id );
	if( id < 0 )
		return id;

	dev->pg.mCtrl_id = id;
	id = 0;     /* fixed interface number */
	vPg1_intf_comm_desc.bInterfaceNumber = id;
	vPg1_union_desc.bMasterInterface0 = id;

	/* Allocate Interface ID: PipeGroup1 bulk interface */
	_dbgmsg_gadget( "usb_interface_id\n" );
	id = usb_interface_id(c, f);
	_dbgmsg( "usb_interface_id() = %d(%d)\n", id, vPg1_intf_comm_desc.bInterfaceNumber );
	if( id < 0 )
		return id;

	dev->pg.mData_id = id;
	id = 1;     /* fixed interface number */
	vPg1_intf_bulk_desc.bInterfaceNumber = id;
	vPg1_union_desc.bSlaveInterface0 = id;
	vPg1_call_mng.bDataInterface = id;
	_dbgmsg( "usb_interface_id() = %d(%d)\n", id, vPg1_intf_bulk_desc.bInterfaceNumber );

	_dbgmsg( "OUT\n" );
	return 0;
}
Esempio n. 4
0
/* config the rockusb device*/
static int rockusb_bind(struct usb_configuration *c, struct usb_function *f)
{
	int id;
	struct usb_gadget *gadget = c->cdev->gadget;
	struct f_rockusb *f_rkusb = func_to_rockusb(f);
	const char *s;

	id = usb_interface_id(c, f);
	if (id < 0)
		return id;
	interface_desc.bInterfaceNumber = id;

	id = usb_string_id(c->cdev);
	if (id < 0)
		return id;

	rkusb_string_defs[0].id = id;
	interface_desc.iInterface = id;

	f_rkusb->in_ep = usb_ep_autoconfig(gadget, &fs_ep_in);
	if (!f_rkusb->in_ep)
		return -ENODEV;
	f_rkusb->in_ep->driver_data = c->cdev;

	f_rkusb->out_ep = usb_ep_autoconfig(gadget, &fs_ep_out);
	if (!f_rkusb->out_ep)
		return -ENODEV;
	f_rkusb->out_ep->driver_data = c->cdev;

	f->descriptors = rkusb_fs_function;

	if (gadget_is_dualspeed(gadget)) {
		hs_ep_in.bEndpointAddress = fs_ep_in.bEndpointAddress;
		hs_ep_out.bEndpointAddress = fs_ep_out.bEndpointAddress;
		f->hs_descriptors = rkusb_hs_function;
	}

	s = env_get("serial#");
	if (s)
		g_dnl_set_serialnumber((char *)s);

	return 0;
}
Esempio n. 5
0
static int
acc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct acc_dev	*dev = func_to_dev(f);
	int			id;
	int			ret;

	DBG(cdev, "acc_function_bind dev: %p\n", dev);

	dev->start_requested = 0;

	/* allocate interface ID(s) */
	id = usb_interface_id(c, f);
	if (id < 0)
		return id;
	acc_interface_desc.bInterfaceNumber = id;

	/* allocate endpoints */
	ret = create_bulk_endpoints(dev, &acc_fullspeed_in_desc,
			&acc_fullspeed_out_desc);
	if (ret)
		return ret;

	/* support high speed hardware */
	if (gadget_is_dualspeed(c->cdev->gadget)) {
		acc_highspeed_in_desc.bEndpointAddress =
			acc_fullspeed_in_desc.bEndpointAddress;
		acc_highspeed_out_desc.bEndpointAddress =
			acc_fullspeed_out_desc.bEndpointAddress;
	}

	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			f->name, dev->ep_in->name, dev->ep_out->name);
	return 0;
}
static int
gser_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_gser		*gser = func_to_gser(f);
	int			status;
	struct usb_ep		*ep;

	
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	gser->data_id = status;
	gser_interface_desc.bInterfaceNumber = status;

	status = -ENODEV;

	
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
	if (!ep)
		goto fail;
	gser->port.in = ep;
	ep->driver_data = cdev;	

	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
	if (!ep)
		goto fail;
	gser->port.out = ep;
	ep->driver_data = cdev;	

#ifdef CONFIG_MODEM_SUPPORT
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
	if (!ep)
		goto fail;
	gser->notify = ep;
	ep->driver_data = cdev;	
	
	gser->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 2,
			GFP_KERNEL);
	if (!gser->notify_req)
		goto fail;

	gser->notify_req->complete = gser_notify_complete;
	gser->notify_req->context = gser;
#endif

	
	f->descriptors = usb_copy_descriptors(gser_fs_function);

	if (!f->descriptors)
		goto fail;

	if (gadget_is_dualspeed(c->cdev->gadget)) {
		gser_hs_in_desc.bEndpointAddress =
				gser_fs_in_desc.bEndpointAddress;
		gser_hs_out_desc.bEndpointAddress =
				gser_fs_out_desc.bEndpointAddress;
#ifdef CONFIG_MODEM_SUPPORT
		gser_hs_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif

		
		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);

		if (!f->hs_descriptors)
			goto fail;

	}

	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
			gser->port_num,
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			gser->port.in->name, gser->port.out->name);
	return 0;

fail:
	if (f->descriptors)
		usb_free_descriptors(f->descriptors);
#ifdef CONFIG_MODEM_SUPPORT
	if (gser->notify_req)
		gs_free_req(gser->notify, gser->notify_req);

	
	if (gser->notify)
		gser->notify->driver_data = NULL;
#endif
	
	if (gser->port.out)
		gser->port.out->driver_data = NULL;
	if (gser->port.in)
		gser->port.in->driver_data = NULL;

	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

	return status;
}
Esempio n. 7
0
static int
gser_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_gser		*gser = func_to_gser(f);
	int			status;
	struct usb_ep		*ep;

	/* allocate instance-specific interface IDs */
#if defined(CONFIG_ANDROID_PANTECH_USB)
//	if((pantech_usb_carrier != CARRIER_QUALCOMM) && b_pantech_usb_module){
	if(pantech_usb_carrier != CARRIER_QUALCOMM){
		gser_fs_function = pantech_gser_fs_function;
		gser_hs_function = pantech_gser_hs_function;

		status = usb_interface_id(c, f);
		if (status < 0)
			goto fail;
		gser->data_id = status; //data_id : cdc interface number
		gser_acm_cdc_interface_desc.bInterfaceNumber = status;

#if defined(FEATURE_ANDROID_PANTECH_USB_IAD)
	gser_interface_assoc_desc.bFirstInterface = status;
#endif
		//acm interface
		status = usb_interface_id(c, f);
		if (status < 0)
			goto fail;
		gser_acm_data_interface_desc.bInterfaceNumber = status;
	}else{
		gser_fs_function = qualcomm_gser_fs_function;
		gser_hs_function = qualcomm_gser_hs_function;

		status = usb_interface_id(c, f);
		if (status < 0)
			goto fail;
		gser->data_id = status;
		gser_interface_desc.bInterfaceNumber = status;
	}
#else  
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	gser->data_id = status;
	gser_interface_desc.bInterfaceNumber = status;
#endif
	status = -ENODEV;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
	if (!ep)
		goto fail;
	gser->port.in = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
	if (!ep)
		goto fail;
	gser->port.out = ep;
	ep->driver_data = cdev;	/* claim */

#ifdef CONFIG_MODEM_SUPPORT
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
	if (!ep)
		goto fail;
	gser->notify = ep;
	ep->driver_data = cdev;	/* claim */
	/* allocate notification */
	gser->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 2,
			GFP_KERNEL);
	if (!gser->notify_req)
		goto fail;

	gser->notify_req->complete = gser_notify_complete;
	gser->notify_req->context = gser;
#endif

	/* copy descriptors, and track endpoint copies */
	f->descriptors = usb_copy_descriptors(gser_fs_function);

	if (!f->descriptors)
		goto fail;

	gser->fs.in = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_in_desc);
	gser->fs.out = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_out_desc);
#ifdef CONFIG_MODEM_SUPPORT
	gser->fs.notify = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_notify_desc);
#endif


	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	if (gadget_is_dualspeed(c->cdev->gadget)) {
		gser_hs_in_desc.bEndpointAddress =
				gser_fs_in_desc.bEndpointAddress;
		gser_hs_out_desc.bEndpointAddress =
				gser_fs_out_desc.bEndpointAddress;
#ifdef CONFIG_MODEM_SUPPORT
		gser_hs_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif

		/* copy descriptors, and track endpoint copies */
		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);

		if (!f->hs_descriptors)
			goto fail;

		gser->hs.in = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_in_desc);
		gser->hs.out = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_out_desc);
#ifdef CONFIG_MODEM_SUPPORT
		gser->hs.notify = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_notify_desc);
#endif
	}

	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
			gser->port_num,
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			gser->port.in->name, gser->port.out->name);
	return 0;

fail:
	if (f->descriptors)
		usb_free_descriptors(f->descriptors);
#ifdef CONFIG_MODEM_SUPPORT
	if (gser->notify_req)
		gs_free_req(gser->notify, gser->notify_req);

	/* we might as well release our claims on endpoints */
	if (gser->notify)
		gser->notify->driver_data = NULL;
#endif
	/* we might as well release our claims on endpoints */
	if (gser->port.out)
		gser->port.out->driver_data = NULL;
	if (gser->port.in)
		gser->port.in->driver_data = NULL;

	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

	return status;
}
Esempio n. 8
0
static int __init
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct uvc_device *uvc = to_uvc(f);
	struct usb_ep *ep;
	int ret = -EINVAL;

	INFO(cdev, "uvc_function_bind\n");

	/* sanity check the streaming endpoint module parameters */
	if (streaming_interval < 1)
		streaming_interval = 1;
	if (streaming_interval > 16)
		streaming_interval = 16;
	if (streaming_mult > 2)
		streaming_mult = 2;
	if (streaming_maxburst > 15)
		streaming_maxburst = 15;

	/*
	 * fill in the FS video streaming specific descriptors from the
	 * module parameters
	 */
	uvc_fs_streaming_ep.wMaxPacketSize = streaming_maxpacket > 1023 ?
						1023 : streaming_maxpacket;
	uvc_fs_streaming_ep.bInterval = streaming_interval;

	/* Allocate endpoints. */
	ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_control_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate control EP\n");
		goto error;
	}
	uvc->control_ep = ep;
	ep->driver_data = uvc;

	ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate streaming EP\n");
		goto error;
	}
	uvc->video.ep = ep;
	ep->driver_data = uvc;

	/* Allocate interface IDs. */
	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_iad.bFirstInterface = ret;
	uvc_control_intf.bInterfaceNumber = ret;
	uvc->control_intf = ret;

	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
	uvc->streaming_intf = ret;

	/* sanity check the streaming endpoint module parameters */
	if (streaming_maxpacket > 1024)
		streaming_maxpacket = 1024;

	/* Copy descriptors for FS. */
	f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);

	/* support high speed hardware */
	if (gadget_is_dualspeed(cdev->gadget)) {
		/*
		 * Fill in the HS descriptors from the module parameters for the
		 * Video Streaming endpoint.
		 * NOTE: We assume that the user knows what they are doing and
		 * won't give parameters that their UDC doesn't support.
		 */
		uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
		uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
		uvc_hs_streaming_ep.bInterval = streaming_interval;
		uvc_hs_streaming_ep.bEndpointAddress =
				uvc_fs_streaming_ep.bEndpointAddress;

		/* Copy descriptors. */
		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
	}

	/* support super speed hardware */
	if (gadget_is_superspeed(c->cdev->gadget)) {
		/*
		 * Fill in the SS descriptors from the module parameters for the
		 * Video Streaming endpoint.
		 * NOTE: We assume that the user knows what they are doing and
		 * won't give parameters that their UDC doesn't support.
		 */
		uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
		uvc_ss_streaming_ep.bInterval = streaming_interval;
		uvc_ss_streaming_comp.bmAttributes = streaming_mult;
		uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
		uvc_ss_streaming_comp.wBytesPerInterval =
			streaming_maxpacket * (streaming_mult + 1) *
			(streaming_maxburst + 1);
		uvc_ss_streaming_ep.bEndpointAddress =
				uvc_fs_streaming_ep.bEndpointAddress;

		/* Copy descriptors. */
		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
	}

	/* Preallocate control endpoint request. */
	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	uvc->control_req->buf = uvc->control_buf;
	uvc->control_req->complete = uvc_function_ep0_complete;
	uvc->control_req->context = uvc;

	/* Avoid letting this gadget enumerate until the userspace server is
	 * active.
	 */
	if ((ret = usb_function_deactivate(f)) < 0)
		goto error;

	/* Initialise video. */
	ret = uvc_video_init(&uvc->video);
	if (ret < 0)
		goto error;

	/* Register a V4L2 device. */
	ret = uvc_register_video(uvc);
	if (ret < 0) {
		printk(KERN_INFO "Unable to register video device\n");
		goto error;
	}

	return 0;

error:
	uvc_function_unbind(c, f);
	return ret;
}
Esempio n. 9
0
File: f_uvc.c Progetto: 7799/linux
static int __init
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct uvc_device *uvc = to_uvc(f);
	unsigned int max_packet_mult;
	unsigned int max_packet_size;
	struct usb_ep *ep;
	int ret = -EINVAL;

	INFO(cdev, "uvc_function_bind\n");

	/* Sanity check the streaming endpoint module parameters.
	 */
	streaming_interval = clamp(streaming_interval, 1U, 16U);
	streaming_maxpacket = clamp(streaming_maxpacket, 1U, 3072U);
	streaming_maxburst = min(streaming_maxburst, 15U);

	/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
	 * module parameters.
	 *
	 * NOTE: We assume that the user knows what they are doing and won't
	 * give parameters that their UDC doesn't support.
	 */
	if (streaming_maxpacket <= 1024) {
		max_packet_mult = 1;
		max_packet_size = streaming_maxpacket;
	} else if (streaming_maxpacket <= 2048) {
		max_packet_mult = 2;
		max_packet_size = streaming_maxpacket / 2;
	} else {
		max_packet_mult = 3;
		max_packet_size = streaming_maxpacket / 3;
	}

	uvc_fs_streaming_ep.wMaxPacketSize = min(streaming_maxpacket, 1023U);
	uvc_fs_streaming_ep.bInterval = streaming_interval;

	uvc_hs_streaming_ep.wMaxPacketSize = max_packet_size;
	uvc_hs_streaming_ep.wMaxPacketSize |= ((max_packet_mult - 1) << 11);
	uvc_hs_streaming_ep.bInterval = streaming_interval;

	uvc_ss_streaming_ep.wMaxPacketSize = max_packet_size;
	uvc_ss_streaming_ep.bInterval = streaming_interval;
	uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
	uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
	uvc_ss_streaming_comp.wBytesPerInterval =
		max_packet_size * max_packet_mult * streaming_maxburst;

	/* Allocate endpoints. */
	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate control EP\n");
		goto error;
	}
	uvc->control_ep = ep;
	ep->driver_data = uvc;

	if (gadget_is_superspeed(c->cdev->gadget))
		ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
					  &uvc_ss_streaming_comp);
	else if (gadget_is_dualspeed(cdev->gadget))
		ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
	else
		ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);

	if (!ep) {
		INFO(cdev, "Unable to allocate streaming EP\n");
		goto error;
	}
	uvc->video.ep = ep;
	ep->driver_data = uvc;

	uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
	uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
	uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;

	/* Allocate interface IDs. */
	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_iad.bFirstInterface = ret;
	uvc_control_intf.bInterfaceNumber = ret;
	uvc->control_intf = ret;

	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
	uvc->streaming_intf = ret;

	/* Copy descriptors */
	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
	if (gadget_is_dualspeed(cdev->gadget))
		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
	if (gadget_is_superspeed(c->cdev->gadget))
		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);

	/* Preallocate control endpoint request. */
	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	uvc->control_req->buf = uvc->control_buf;
	uvc->control_req->complete = uvc_function_ep0_complete;
	uvc->control_req->context = uvc;

	/* Avoid letting this gadget enumerate until the userspace server is
	 * active.
	 */
	if ((ret = usb_function_deactivate(f)) < 0)
		goto error;

	if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
		printk(KERN_INFO "v4l2_device_register failed\n");
		goto error;
	}

	/* Initialise video. */
	ret = uvc_video_init(&uvc->video);
	if (ret < 0)
		goto error;

	/* Register a V4L2 device. */
	ret = uvc_register_video(uvc);
	if (ret < 0) {
		printk(KERN_INFO "Unable to register video device\n");
		goto error;
	}

	return 0;

error:
	v4l2_device_unregister(&uvc->v4l2_dev);
	if (uvc->vdev)
		video_device_release(uvc->vdev);

	if (uvc->control_ep)
		uvc->control_ep->driver_data = NULL;
	if (uvc->video.ep)
		uvc->video.ep->driver_data = NULL;

	if (uvc->control_req) {
		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
		kfree(uvc->control_buf);
	}

	usb_free_all_descriptors(f);
	return ret;
}
Esempio n. 10
0
static int
gser_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_gser		*gser = func_to_gser(f);
	int			status;
	struct usb_ep		*ep;

	/* allocate instance-specific interface IDs */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
#ifdef CONFIG_LGE_USB_GADGET_DRIVER
	gser_iad_descriptor.bFirstInterface = status;

	gser_control_interface_desc.bInterfaceNumber = status;
	gser_union_desc .bMasterInterface0 = status;

	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	gser->data_id = status;
// [START] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial
	gser_data_interface_desc.bInterfaceNumber = status;
	gser_union_desc.bSlaveInterface0 = status;
	gser_call_mgmt_descriptor.bDataInterface = status;
#else
	gser->data_id = status;
	gser_interface_desc.bInterfaceNumber = status;
// [START] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial
#endif
// [END] seunghun.kim : temp_modify for using LG_USB_MODEM on ES3 by f_serial

	status = -ENODEV;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
	if (!ep)
		goto fail;
	gser->port.in = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
	if (!ep)
		goto fail;
	gser->port.out = ep;
	ep->driver_data = cdev;	/* claim */

#ifdef CONFIG_MODEM_SUPPORT
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
	if (!ep)
		goto fail;
	gser->notify = ep;
	ep->driver_data = cdev;	/* claim */
	/* allocate notification */
#ifdef CONFIG_LGE_USB_GADGET_DRIVER
	gser->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 8,
			GFP_KERNEL);
#else
	gser->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 2,
			GFP_KERNEL);
#endif
	if (!gser->notify_req)
		goto fail;

	gser->notify_req->complete = gser_notify_complete;
	gser->notify_req->context = gser;
#endif

	/* copy descriptors, and track endpoint copies */
	f->descriptors = usb_copy_descriptors(gser_fs_function);
	if (!f->descriptors)
		goto fail;

	gser->fs.in = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_in_desc);
	gser->fs.out = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_out_desc);
#ifdef CONFIG_MODEM_SUPPORT
	gser->fs.notify = usb_find_endpoint(gser_fs_function,
			f->descriptors, &gser_fs_notify_desc);
#endif


	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	if (gadget_is_dualspeed(c->cdev->gadget)) {
		gser_hs_in_desc.bEndpointAddress =
				gser_fs_in_desc.bEndpointAddress;
		gser_hs_out_desc.bEndpointAddress =
				gser_fs_out_desc.bEndpointAddress;
#ifdef CONFIG_MODEM_SUPPORT
		gser_hs_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif

		/* copy descriptors, and track endpoint copies */
		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);

		gser->hs.in = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_in_desc);
		gser->hs.out = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_out_desc);
#ifdef CONFIG_MODEM_SUPPORT
		gser->hs.notify = usb_find_endpoint(gser_hs_function,
				f->hs_descriptors, &gser_hs_notify_desc);
#endif
	}

	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
			gser->port_num,
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			gser->port.in->name, gser->port.out->name);
	return 0;

fail:
#ifdef CONFIG_MODEM_SUPPORT
	if (gser->notify_req)
		gs_free_req(gser->notify, gser->notify_req);

	/* we might as well release our claims on endpoints */
	if (gser->notify)
		gser->notify->driver_data = NULL;
#endif
	/* we might as well release our claims on endpoints */
	if (gser->port.out)
		gser->port.out->driver_data = NULL;
	if (gser->port.in)
		gser->port.in->driver_data = NULL;

	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

	return status;
}
Esempio n. 11
0
static int thor_func_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_gadget *gadget = c->cdev->gadget;
	struct f_thor *f_thor = func_to_thor(f);
	struct thor_dev *dev;
	struct usb_ep *ep;
	int status;

	thor_func = f_thor;
	dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev));
	if (!dev)
		return -ENOMEM;

	memset(dev, 0, sizeof(*dev));
	dev->gadget = gadget;
	f_thor->dev = dev;

	debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n",
	      __func__, c, f);
	debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev);

	/* EP0  */
	/* preallocate control response and buffer */
	dev->req = usb_ep_alloc_request(gadget->ep0, 0);
	if (!dev->req) {
		status = -ENOMEM;
		goto fail;
	}
	dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE,
				 THOR_PACKET_SIZE);
	if (!dev->req->buf) {
		status = -ENOMEM;
		goto fail;
	}

	dev->req->complete = thor_setup_complete;

	/* DYNAMIC interface numbers assignments */
	status = usb_interface_id(c, f);

	if (status < 0)
		goto fail;

	thor_downloader_intf_int.bInterfaceNumber = status;
	thor_downloader_cdc_union.bMasterInterface0 = status;

	status = usb_interface_id(c, f);

	if (status < 0)
		goto fail;

	thor_downloader_intf_data.bInterfaceNumber = status;
	thor_downloader_cdc_union.bSlaveInterface0 = status;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(gadget, &fs_in_desc);
	if (!ep) {
		status = -ENODEV;
		goto fail;
	}

	if (gadget_is_dualspeed(gadget)) {
		hs_in_desc.bEndpointAddress =
				fs_in_desc.bEndpointAddress;
	}

	dev->in_ep = ep; /* Store IN EP for enabling @ setup */
	ep->driver_data = dev;

	ep = usb_ep_autoconfig(gadget, &fs_out_desc);
	if (!ep) {
		status = -ENODEV;
		goto fail;
	}

	if (gadget_is_dualspeed(gadget))
		hs_out_desc.bEndpointAddress =
				fs_out_desc.bEndpointAddress;

	dev->out_ep = ep; /* Store OUT EP for enabling @ setup */
	ep->driver_data = dev;

	ep = usb_ep_autoconfig(gadget, &fs_int_desc);
	if (!ep) {
		status = -ENODEV;
		goto fail;
	}

	dev->int_ep = ep;
	ep->driver_data = dev;

	if (gadget_is_dualspeed(gadget)) {
		hs_int_desc.bEndpointAddress =
				fs_int_desc.bEndpointAddress;

		f->hs_descriptors = (struct usb_descriptor_header **)
			&hs_thor_downloader_function;

		if (!f->hs_descriptors)
			goto fail;
	}

	debug("%s: out_ep:%p out_req:%p\n", __func__,
	      dev->out_ep, dev->out_req);

	return 0;

 fail:
	free(dev);
	return status;
}
Esempio n. 12
0
static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
{
    struct usb_ep		*ep;
    struct f_hidg		*hidg = func_to_hidg(f);
    int			status;
    dev_t			dev;

    pr_info("%s: creating device %p\n", __func__, hidg);

    /* allocate instance-specific interface IDs, and patch descriptors */
    status = usb_interface_id(c, f);
    if (status < 0)
        goto fail;
    hidg_interface_desc.bInterfaceNumber = status;

    /* allocate instance-specific endpoints */
    status = -ENODEV;
    ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
    if (!ep)
        goto fail;
    ep->driver_data = c->cdev;	/* claim */
    hidg->in_ep = ep;

    /* preallocate request and buffer */
    status = -ENOMEM;
    hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
    if (!hidg->req)
        goto fail;


    hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
    if (!hidg->req->buf)
        goto fail;

    /* set descriptor dynamic values */
    hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
    hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
    hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
    hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
    hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;
    hidg_desc.desc[0].wDescriptorLength =
        cpu_to_le16(hidg->report_desc_length);

    hidg->set_report_buff = NULL;

    hidg_hs_in_ep_desc.bEndpointAddress =
        hidg_fs_in_ep_desc.bEndpointAddress;

    status = usb_assign_descriptors(f, hidg_fs_descriptors,
                                    hidg_hs_descriptors, NULL);
    if (status)
        goto fail;

    mutex_init(&hidg->lock);
    spin_lock_init(&hidg->spinlock);
    init_waitqueue_head(&hidg->write_queue);
    init_waitqueue_head(&hidg->read_queue);

    /* create char device */
    cdev_init(&hidg->cdev, &f_hidg_fops);
    dev = MKDEV(major, hidg->minor);
    status = cdev_add(&hidg->cdev, dev, 1);
    if (status)
        goto fail;

    device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);
    hacky_device_list_add(hidg);

    return 0;

fail:
    ERROR(f->config->cdev, "hidg_bind FAILED\n");
    if (hidg->req != NULL) {
        kfree(hidg->req->buf);
        if (hidg->in_ep != NULL)
            usb_ep_free_request(hidg->in_ep, hidg->req);
    }

    usb_free_all_descriptors(f);
    return status;
}
Esempio n. 13
0
/* ACM function driver setup/binding */
static int
acm_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_acm		*acm = func_to_acm(f);
	struct usb_string	*us;
	int			status;
	struct usb_ep		*ep;

	acm_string_defs[ACM_CTRL_IDX].s = acm->ctrl_string_buf;
	acm_string_defs[ACM_DATA_IDX].s = acm->data_string_buf;
	acm_string_defs[ACM_IAD_IDX].s = acm->iad_string_buf;

	/* maybe allocate device-global string IDs, and patch descriptors */
	us = usb_gstrings_attach(cdev, acm_strings,
			ARRAY_SIZE(acm_string_defs));
	if (IS_ERR(us))
		return PTR_ERR(us);

	acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id;
	acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
	acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;

	acm_iad_descriptor.bFunctionProtocol = acm->iad_proto;
	acm_control_interface_desc.bInterfaceProtocol = acm->ctrl_intf_proto;

	/* allocate instance-specific interface IDs, and patch descriptors */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	acm->ctrl_id = status;
	acm_iad_descriptor.bFirstInterface = status;

	acm_control_interface_desc.bInterfaceNumber = status;
	acm_union_desc .bMasterInterface0 = status;

	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	acm->data_id = status;

	acm_data_interface_desc.bInterfaceNumber = status;
	acm_union_desc.bSlaveInterface0 = status;
	acm_call_mgmt_descriptor.bDataInterface = status;

	status = -ENODEV;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
	if (!ep)
		goto fail;
	acm->port.in = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
	if (!ep)
		goto fail;
	acm->port.out = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
	if (!ep)
		goto fail;
	acm->notify = ep;
	ep->driver_data = cdev;	/* claim */

	/* allocate notification */
	acm->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 2,
			GFP_KERNEL);
	if (!acm->notify_req)
		goto fail;

	acm->notify_req->complete = acm_cdc_notify_complete;
	acm->notify_req->context = acm;

	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
	acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
	acm_hs_notify_desc.bEndpointAddress =
		acm_fs_notify_desc.bEndpointAddress;

	acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
	acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;

	status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
			acm_ss_function);
	if (status)
		goto fail;

	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
			acm->port_num,
			gadget_is_superspeed(c->cdev->gadget) ? "super" :
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			acm->port.in->name, acm->port.out->name,
			acm->notify->name);
	return 0;

fail:
	if (acm->notify_req) {
		gs_free_req(acm->notify, acm->notify_req);
		acm->notify_req = NULL;
	}

	/* we might as well release our claims on endpoints */
	if (acm->notify)
		acm->notify->driver_data = NULL;
	if (acm->port.out)
		acm->port.out->driver_data = NULL;
	if (acm->port.in)
		acm->port.in->driver_data = NULL;

	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);

	return status;
}
Esempio n. 14
0
static int
mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	int n, rc, id;
	struct usb_ep *ep;
	struct usb_request *req;
	struct proc_dir_entry *mtp_proc = NULL;

	spin_lock_init(&g_usb_mtp_context.lock);
	g_usb_mtp_context.cdev = c->cdev;
	/* allocate interface ID(s) */
	id = usb_interface_id(c, f);
	if (id < 0)
		return id;
	intf_desc.bInterfaceNumber = id;

	/* Find all the endpoints we will use */
	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_bulk_in_desc);
	if (!ep) {
		mtp_err("auto-configure hs_bulk_in_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.bulk_in = ep;

	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_bulk_out_desc);
	if (!ep) {
		mtp_err("auto-configure hs_bulk_out_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.bulk_out = ep;

	ep = usb_ep_autoconfig(g_usb_mtp_context.cdev->gadget,
						&fs_intr_in_desc);
	if (!ep) {
		mtp_err("auto-configure hs_intr_in_desc error\n");
		goto autoconf_fail;
	}
	ep->driver_data = &g_usb_mtp_context;
	g_usb_mtp_context.intr_in = ep;

	if (gadget_is_dualspeed(g_usb_mtp_context.cdev->gadget)) {
		/* Assume endpoint addresses are the same for both speeds */
		hs_bulk_in_desc.bEndpointAddress =
		    fs_bulk_in_desc.bEndpointAddress;
		hs_bulk_out_desc.bEndpointAddress =
		    fs_bulk_out_desc.bEndpointAddress;
		hs_intr_in_desc.bEndpointAddress =
		    fs_intr_in_desc.bEndpointAddress;
	}

	rc = -ENOMEM;

	for (n = 0; n < MAX_BULK_RX_REQ_NUM; n++) {
		req = req_new(g_usb_mtp_context.bulk_out, BULK_BUFFER_SIZE);
		if (!req)
			goto autoconf_fail;

		pending_reqs[n] = req;

		req->complete = mtp_out_complete;
		req_put(&g_usb_mtp_context.rx_reqs, req);
	}
	for (n = 0; n < MAX_BULK_TX_REQ_NUM; n++) {
		req = req_new(g_usb_mtp_context.bulk_in, BULK_BUFFER_SIZE);
		if (!req)
			goto autoconf_fail;

		req->complete = mtp_in_complete;
		req_put(&g_usb_mtp_context.tx_reqs, req);
	}

	for (n = 0; n < MAX_CTL_RX_REQ_NUM; n++)
		ctl_req_put(&g_usb_mtp_context.ctl_rx_reqs, &ctl_reqs[n]);

	g_usb_mtp_context.int_tx_req =
		req_new(g_usb_mtp_context.intr_in, BULK_BUFFER_SIZE);
	if (!g_usb_mtp_context.int_tx_req)
		goto autoconf_fail;
	g_usb_mtp_context.intr_in_busy = 0;
	g_usb_mtp_context.int_tx_req->complete = mtp_int_complete;

	g_usb_mtp_context.ctl_tx_req =
		req_new(g_usb_mtp_context.cdev->gadget->ep0, 512);
	if (!g_usb_mtp_context.ctl_tx_req)
		goto autoconf_fail;

	misc_register(&mtp_device);

	mtp_proc = create_proc_entry("mtpctl", 0666, 0);
	if (!mtp_proc) {
		mtp_err("creating /proc/mtpctl failed\n");
		goto autoconf_fail;
    }
    mtp_proc->proc_fops = &mtp_ctl_fops;

	return 0;

autoconf_fail:
	rc = -ENOTSUPP;
	mtp_function_unbind(c, f);
	return rc;
}
Esempio n. 15
0
static int
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct uvc_device *uvc = to_uvc(f);
	struct usb_string *us;
	unsigned int max_packet_mult;
	unsigned int max_packet_size;
	struct usb_ep *ep;
	struct f_uvc_opts *opts;
	int ret = -EINVAL;

	INFO(cdev, "uvc_function_bind\n");

	opts = fi_to_f_uvc_opts(f->fi);
	/* Sanity check the streaming endpoint module parameters.
	 */
	opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
	opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U);
	opts->streaming_maxburst = min(opts->streaming_maxburst, 15U);

	/* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */
	if (opts->streaming_maxburst &&
	    (opts->streaming_maxpacket % 1024) != 0) {
		opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024);
		INFO(cdev, "overriding streaming_maxpacket to %d\n",
		     opts->streaming_maxpacket);
	}

	/* Fill in the FS/HS/SS Video Streaming specific descriptors from the
	 * module parameters.
	 *
	 * NOTE: We assume that the user knows what they are doing and won't
	 * give parameters that their UDC doesn't support.
	 */
	if (opts->streaming_maxpacket <= 1024) {
		max_packet_mult = 1;
		max_packet_size = opts->streaming_maxpacket;
	} else if (opts->streaming_maxpacket <= 2048) {
		max_packet_mult = 2;
		max_packet_size = opts->streaming_maxpacket / 2;
	} else {
		max_packet_mult = 3;
		max_packet_size = opts->streaming_maxpacket / 3;
	}

	uvc_fs_streaming_ep.wMaxPacketSize =
		cpu_to_le16(min(opts->streaming_maxpacket, 1023U));
	uvc_fs_streaming_ep.bInterval = opts->streaming_interval;

	uvc_hs_streaming_ep.wMaxPacketSize =
		cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11));
	uvc_hs_streaming_ep.bInterval = opts->streaming_interval;

	uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size);
	uvc_ss_streaming_ep.bInterval = opts->streaming_interval;
	uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1;
	uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst;
	uvc_ss_streaming_comp.wBytesPerInterval =
		cpu_to_le16(max_packet_size * max_packet_mult *
			    (opts->streaming_maxburst + 1));

	/* Allocate endpoints. */
	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate control EP\n");
		goto error;
	}
	uvc->control_ep = ep;

	if (gadget_is_superspeed(c->cdev->gadget))
		ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
					  &uvc_ss_streaming_comp);
	else if (gadget_is_dualspeed(cdev->gadget))
		ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
	else
		ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);

	if (!ep) {
		INFO(cdev, "Unable to allocate streaming EP\n");
		goto error;
	}
	uvc->video.ep = ep;

	uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
	uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
	uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;

	us = usb_gstrings_attach(cdev, uvc_function_strings,
				 ARRAY_SIZE(uvc_en_us_strings));
	if (IS_ERR(us)) {
		ret = PTR_ERR(us);
		goto error;
	}
	uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
	uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
	ret = us[UVC_STRING_STREAMING_IDX].id;
	uvc_streaming_intf_alt0.iInterface = ret;
	uvc_streaming_intf_alt1.iInterface = ret;

	/* Allocate interface IDs. */
	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_iad.bFirstInterface = ret;
	uvc_control_intf.bInterfaceNumber = ret;
	uvc->control_intf = ret;

	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
	uvc->streaming_intf = ret;

	/* Copy descriptors */
	f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
	if (IS_ERR(f->fs_descriptors)) {
		ret = PTR_ERR(f->fs_descriptors);
		f->fs_descriptors = NULL;
		goto error;
	}
	if (gadget_is_dualspeed(cdev->gadget)) {
		f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
		if (IS_ERR(f->hs_descriptors)) {
			ret = PTR_ERR(f->hs_descriptors);
			f->hs_descriptors = NULL;
			goto error;
		}
	}
	if (gadget_is_superspeed(c->cdev->gadget)) {
		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
		if (IS_ERR(f->ss_descriptors)) {
			ret = PTR_ERR(f->ss_descriptors);
			f->ss_descriptors = NULL;
			goto error;
		}
	}

	/* Preallocate control endpoint request. */
	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	uvc->control_req->buf = uvc->control_buf;
	uvc->control_req->complete = uvc_function_ep0_complete;
	uvc->control_req->context = uvc;

	if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
		printk(KERN_INFO "v4l2_device_register failed\n");
		goto error;
	}

	/* Initialise video. */
	ret = uvcg_video_init(&uvc->video);
	if (ret < 0)
		goto error;

	/* Register a V4L2 device. */
	ret = uvc_register_video(uvc);
	if (ret < 0) {
		printk(KERN_INFO "Unable to register video device\n");
		goto error;
	}

	return 0;

error:
	v4l2_device_unregister(&uvc->v4l2_dev);

	if (uvc->control_req)
		usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
	kfree(uvc->control_buf);

	usb_free_all_descriptors(f);
	return ret;
}
Esempio n. 16
0
static int
ecm_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_ecm		*ecm = func_to_ecm(f);
	int			status;
	struct usb_ep		*ep;

	/* allocate instance-specific interface IDs */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	ecm->ctrl_id = status;

	ecm_control_intf.bInterfaceNumber = status;
#ifdef CONFIG_LGE_USB_GADGET_DRIVER
	ecm_iad.bFirstInterface = status;
#endif
	ecm_union_desc.bMasterInterface0 = status;

	status = usb_interface_id(c, f);
	printk(KERN_DEBUG "[MSG]>>f_ecm > ecm_bind   : interface = %d  !!	\n", status );
	if (status < 0)
		goto fail;
	ecm->data_id = status;

	ecm_data_nop_intf.bInterfaceNumber = status;
	ecm_data_intf.bInterfaceNumber = status;
	ecm_union_desc.bSlaveInterface0 = status;

	status = -ENODEV;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_in_desc);
	if (!ep)
		goto fail;
	ecm->port.in_ep = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_out_desc);
	if (!ep)
		goto fail;
	ecm->port.out_ep = ep;
	ep->driver_data = cdev;	/* claim */

	/* NOTE:  a status/notification endpoint is *OPTIONAL* but we
	 * don't treat it that way.  It's simpler, and some newer CDC
	 * profiles (wireless handsets) no longer treat it as optional.
	 */
	ep = usb_ep_autoconfig(cdev->gadget, &fs_ecm_notify_desc);
	if (!ep)
		goto fail;
	ecm->notify = ep;
	ep->driver_data = cdev;	/* claim */

	status = -ENOMEM;

	/* allocate notification request and buffer */
	ecm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
	if (!ecm->notify_req)
		goto fail;
	ecm->notify_req->buf = kmalloc(ECM_STATUS_BYTECOUNT, GFP_KERNEL);
	if (!ecm->notify_req->buf)
		goto fail;
	ecm->notify_req->context = ecm;
	ecm->notify_req->complete = ecm_notify_complete;

	/* copy descriptors, and track endpoint copies */
	f->descriptors = usb_copy_descriptors(ecm_fs_function);
	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
	 */
	if (gadget_is_dualspeed(c->cdev->gadget)) {
		hs_ecm_in_desc.bEndpointAddress =
				fs_ecm_in_desc.bEndpointAddress;
		hs_ecm_out_desc.bEndpointAddress =
				fs_ecm_out_desc.bEndpointAddress;
		hs_ecm_notify_desc.bEndpointAddress =
				fs_ecm_notify_desc.bEndpointAddress;

		printk(KERN_ERR "[MSG]>> f_ecm > ecm_bind  :  IN    EP = %d	!! \n", hs_ecm_in_desc.bEndpointAddress );
		printk(KERN_ERR "[MSG]>> f_ecm  > ecm_bind  : OUT EP= %d  !! \n", hs_ecm_out_desc.bEndpointAddress);
		printk(KERN_ERR "[MSG]>> f_ecm  > ecm_bind  : NOT EP= %d  !! \n", hs_ecm_notify_desc.bEndpointAddress);

		/* copy descriptors, and track endpoint copies */
		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);
	}

	/* NOTE:  all that is done without knowing or caring about
	 * the network link ... which is unavailable to this code
	 * until we're activated via set_alt().
	 */

	ecm->port.open = ecm_open;
	ecm->port.close = ecm_close;

	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			ecm->port.in_ep->name, ecm->port.out_ep->name,
			ecm->notify->name);
	return 0;

fail:
	if (f->descriptors)
		usb_free_descriptors(f->descriptors);

	if (ecm->notify_req) {
		kfree(ecm->notify_req->buf);
		usb_ep_free_request(ecm->notify, ecm->notify_req);
	}

	/* we might as well release our claims on endpoints */
	if (ecm->notify)
		ecm->notify->driver_data = NULL;
	if (ecm->port.out)
		ecm->port.out_ep->driver_data = NULL;
	if (ecm->port.in)
		ecm->port.in_ep->driver_data = NULL;

	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

	return status;
}
Esempio n. 17
0
static int __init
uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct uvc_device *uvc = to_uvc(f);
	struct usb_ep *ep;
	int ret = -EINVAL;

	INFO(cdev, "uvc_function_bind\n");

	/* Allocate endpoints. */
	ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate control EP\n");
		goto error;
	}
	uvc->control_ep = ep;
	ep->driver_data = uvc;

	ep = usb_ep_autoconfig(cdev->gadget, &uvc_streaming_ep);
	if (!ep) {
		INFO(cdev, "Unable to allocate streaming EP\n");
		goto error;
	}
	uvc->video.ep = ep;
	ep->driver_data = uvc;

	/* Allocate interface IDs. */
	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_iad.bFirstInterface = ret;
	uvc_control_intf.bInterfaceNumber = ret;
	uvc->control_intf = ret;

	if ((ret = usb_interface_id(c, f)) < 0)
		goto error;
	uvc_streaming_intf_alt0.bInterfaceNumber = ret;
	uvc_streaming_intf_alt1.bInterfaceNumber = ret;
	uvc->streaming_intf = ret;

	/* Copy descriptors. */
	f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
	f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);

	/* Preallocate control endpoint request. */
	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
	uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
	if (uvc->control_req == NULL || uvc->control_buf == NULL) {
		ret = -ENOMEM;
		goto error;
	}

	uvc->control_req->buf = uvc->control_buf;
	uvc->control_req->complete = uvc_function_ep0_complete;
	uvc->control_req->context = uvc;

	/* Avoid letting this gadget enumerate until the userspace server is
	 * active.
	 */
	if ((ret = usb_function_deactivate(f)) < 0)
		goto error;

	/* Initialise video. */
	ret = uvc_video_init(&uvc->video);
	if (ret < 0)
		goto error;

	/* Register a V4L2 device. */
	ret = uvc_register_video(uvc);
	if (ret < 0) {
		printk(KERN_INFO "Unable to register video device\n");
		goto error;
	}

	return 0;

error:
	uvc_function_unbind(c, f);
	return ret;
}
static int
rndis_bind(struct usb_configuration *c, struct usb_function *f)
{
    struct usb_composite_dev *cdev = c->cdev;
    struct f_rndis		*rndis = func_to_rndis(f);
    int			status;
    struct usb_ep		*ep;

    /* allocate instance-specific interface IDs */
    status = usb_interface_id(c, f);
    if (status < 0)
        goto fail;
    rndis->ctrl_id = status;
    rndis_iad_descriptor.bFirstInterface = status;

    rndis_control_intf.bInterfaceNumber = status;
    rndis_union_desc.bMasterInterface0 = status;

    status = usb_interface_id(c, f);
    if (status < 0)
        goto fail;
    rndis->data_id = status;

    rndis_data_intf.bInterfaceNumber = status;
    rndis_union_desc.bSlaveInterface0 = status;

    status = -ENODEV;

    /* allocate instance-specific endpoints */
    ep = usb_ep_autoconfig(cdev->gadget, &fs_in_desc);
    if (!ep)
        goto fail;
    rndis->port.in_ep = ep;
    ep->driver_data = cdev;	/* claim */

    ep = usb_ep_autoconfig(cdev->gadget, &fs_out_desc);
    if (!ep)
        goto fail;
    rndis->port.out_ep = ep;
    ep->driver_data = cdev;	/* claim */

    /* NOTE:  a status/notification endpoint is, strictly speaking,
     * optional.  We don't treat it that way though!  It's simpler,
     * and some newer profiles don't treat it as optional.
     */
    ep = usb_ep_autoconfig(cdev->gadget, &fs_notify_desc);
    if (!ep)
        goto fail;
    rndis->notify = ep;
    ep->driver_data = cdev;	/* claim */

    status = -ENOMEM;

    /* allocate notification request and buffer */
    rndis->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
    if (!rndis->notify_req)
        goto fail;
    rndis->notify_req->buf = kmalloc(STATUS_BYTECOUNT, GFP_KERNEL);
    if (!rndis->notify_req->buf)
        goto fail;
    rndis->notify_req->length = STATUS_BYTECOUNT;
    rndis->notify_req->context = rndis;
    rndis->notify_req->complete = rndis_response_complete;

    /* support all relevant hardware speeds... we expect that when
     * hardware is dual speed, all bulk-capable endpoints work at
     * both speeds
     */
    hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
    hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
    hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;

    ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
    ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
    ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;

    status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
                                    eth_ss_function);
    if (status)
        goto fail;

    rndis->port.open = rndis_open;
    rndis->port.close = rndis_close;

    status = rndis_register(rndis_response_available, rndis);
    if (status < 0)
        goto fail;
    rndis->config = status;

    rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
    rndis_set_host_mac(rndis->config, rndis->ethaddr);
    rndis_set_max_pkt_xfer(rndis->config, rndis_ul_max_pkt_per_xfer);

    if (rndis->manufacturer && rndis->vendorID &&
            rndis_set_param_vendor(rndis->config, rndis->vendorID,
                                   rndis->manufacturer))
        goto fail;

    /* NOTE:  all that is done without knowing or caring about
     * the network link ... which is unavailable to this code
     * until we're activated via set_alt().
     */

    DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
        gadget_is_superspeed(c->cdev->gadget) ? "super" :
        gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
        rndis->port.in_ep->name, rndis->port.out_ep->name,
        rndis->notify->name);
    return 0;

fail:
    usb_free_all_descriptors(f);

    if (rndis->notify_req) {
        kfree(rndis->notify_req->buf);
        usb_ep_free_request(rndis->notify, rndis->notify_req);
    }

    /* we might as well release our claims on endpoints */
    if (rndis->notify)
        rndis->notify->driver_data = NULL;
    if (rndis->port.out_ep)
        rndis->port.out_ep->driver_data = NULL;
    if (rndis->port.in_ep)
        rndis->port.in_ep->driver_data = NULL;

    ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

    return status;
}
Esempio n. 19
0
static int
gser_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_gser		*gser = func_to_gser(f);
	int			status;
	struct usb_ep		*ep;

	/* allocate instance-specific interface IDs */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;
	gser->data_id = status;
	gser_interface_desc.bInterfaceNumber = status;

	status = -ENODEV;

	/* allocate instance-specific endpoints */
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
	if (!ep)
		goto fail;
	gser->port.in = ep;
	ep->driver_data = cdev;	/* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
	if (!ep)
		goto fail;
	gser->port.out = ep;
	ep->driver_data = cdev;	/* claim */

#ifdef CONFIG_MODEM_SUPPORT
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
	if (!ep)
		goto fail;
	gser->notify = ep;
	ep->driver_data = cdev;	/* claim */
	/* allocate notification */
	gser->notify_req = gs_alloc_req(ep,
			sizeof(struct usb_cdc_notification) + 2,
			GFP_KERNEL);
	if (!gser->notify_req)
		goto fail;

	gser->notify_req->complete = gser_notify_complete;
	gser->notify_req->context = gser;
#endif

	/* copy descriptors, and track endpoint copies */
	f->descriptors = usb_copy_descriptors(gser_fs_function);

	if (!f->descriptors)
		goto fail;

	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	if (gadget_is_dualspeed(c->cdev->gadget)) {
		gser_hs_in_desc.bEndpointAddress =
				gser_fs_in_desc.bEndpointAddress;
		gser_hs_out_desc.bEndpointAddress =
				gser_fs_out_desc.bEndpointAddress;
#ifdef CONFIG_MODEM_SUPPORT
		gser_hs_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif

		/* copy descriptors, and track endpoint copies */
		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);

		if (!f->hs_descriptors)
			goto fail;

	}
	if (gadget_is_superspeed(c->cdev->gadget)) {
		gser_ss_in_desc.bEndpointAddress =
			gser_fs_in_desc.bEndpointAddress;
		gser_ss_out_desc.bEndpointAddress =
			gser_fs_out_desc.bEndpointAddress;

		/* copy descriptors, and track endpoint copies */
		f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
		if (!f->ss_descriptors)
			goto fail;
	}

	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
			gser->port_num,
			gadget_is_superspeed(c->cdev->gadget) ? "super" :
			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
			gser->port.in->name, gser->port.out->name);
	return 0;

fail:
	if (f->descriptors)
		usb_free_descriptors(f->descriptors);
#ifdef CONFIG_MODEM_SUPPORT
	if (gser->notify_req)
		gs_free_req(gser->notify, gser->notify_req);

	/* we might as well release our claims on endpoints */
	if (gser->notify)
		gser->notify->driver_data = NULL;
#endif
	/* we might as well release our claims on endpoints */
	if (gser->port.out)
		gser->port.out->driver_data = NULL;
	if (gser->port.in)
		gser->port.in->driver_data = NULL;

	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

	return status;
}
/* ACM function driver setup/binding */
static int
acm_bind(struct usb_configuration *c, struct usb_function *f)
{
	struct usb_composite_dev *cdev = c->cdev;
	struct f_acm        *acm = func_to_acm(f);
	struct usb_string   *us;
	int         status;
	struct usb_ep       *ep;

	D("+\n");


	/* REVISIT might want instance-specific strings to help
	 * distinguish instances ...
	 */

	/* maybe allocate device-global string IDs, and patch descriptors */
	us = usb_gstrings_attach(cdev, acm_strings,
				ARRAY_SIZE(acm_string_defs));
	if (IS_ERR(us))
		return PTR_ERR(us);
	acm_control_interface_desc.iInterface = us[ACM_CTRL_IDX].id;
	acm_data_interface_desc.iInterface = us[ACM_DATA_IDX].id;
	acm_iad_descriptor.iFunction = us[ACM_IAD_IDX].id;

	/* allocate instance-specific interface IDs, and patch descriptors */
	status = usb_interface_id(c, f);
	if (status < 0)
		goto fail;

	D("interface id: %d\n", status);

	if (g_acm_is_single_interface) {
		D("single interface\n");
		acm->ctrl_id = acm->data_id = status;
		acm_single_interface_desc.bInterfaceNumber = status;
		acm_call_mgmt_descriptor.bDataInterface = status;
	} else {
		acm->ctrl_id = (u8)status;
		acm_iad_descriptor.bFirstInterface = status;

		acm_control_interface_desc.bInterfaceNumber = status;
		acm_union_desc .bMasterInterface0 = status;

		status = usb_interface_id(c, f);
		if (status < 0)
			goto fail;
		acm->data_id = status;

		acm_data_interface_desc.bInterfaceNumber = status;
		acm_union_desc.bSlaveInterface0 = status;
		acm_call_mgmt_descriptor.bDataInterface = status;
	}

	bsp_usb_add_setup_dev((unsigned)acm->data_id);

	status = -ENODEV;

	/* allocate instance-specific endpoints */
	D("to ep autoconfig\n");
	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_in_desc);
	if (!ep)
		goto fail;
	acm->port.in = ep;
	ep->driver_data = cdev; /* claim */

	ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_out_desc);
	if (!ep)
		goto fail;
	acm->port.out = ep;
	ep->driver_data = cdev; /* claim */

	if (acm->support_notify) {
		ep = usb_ep_autoconfig(cdev->gadget, &acm_fs_notify_desc);
		if (!ep)
			goto fail;
		acm->notify = ep;
		ep->driver_data = cdev; /* claim */

		/* allocate notification */
		acm->notify_req = gs_acm_cdev_alloc_req(ep,
					sizeof(struct usb_cdc_notification) + 2,
					GFP_KERNEL);
		if (!acm->notify_req)
			goto fail;

		acm->notify_req->complete = acm_cdc_notify_complete;
		acm->notify_req->context = acm;
	} else {
		acm->notify = NULL;
		acm->notify_req = NULL;
	}

	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	D("do desc\n");
	acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
	acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;

	if (acm->support_notify)
		acm_hs_notify_desc.bEndpointAddress =
			acm_fs_notify_desc.bEndpointAddress;

	acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
	acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;

	D("to assign desc\n");
	acm_set_config_vendor(acm);

	status = usb_assign_descriptors(f, acm_fs_cur_function, acm_hs_cur_function,
				acm_ss_cur_function);
	if (status)
		goto fail;

	DBG(cdev, "acm_cdev%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
		acm->port_num,
		gadget_is_superspeed(c->cdev->gadget) ? "super" :
		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
		acm->port.in->name, acm->port.out->name,
		acm->notify ? acm->notify->name : "null");

	printk(KERN_INFO "acm_cdev%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
		acm->port_num,
		gadget_is_superspeed(c->cdev->gadget) ? "super" :
		gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
		acm->port.in->name, acm->port.out->name,
		acm->notify ? acm->notify->name : "null");

	return 0;

fail:
	if (acm->notify_req)
		gs_acm_cdev_free_req(acm->notify, acm->notify_req);

	/* we might as well release our claims on endpoints */
	if (acm->notify)
		acm->notify->driver_data = NULL;
	if (acm->port.out)
		acm->port.out->driver_data = NULL;
	if (acm->port.in)
		acm->port.in->driver_data = NULL;

	ERROR(cdev, "%s/%p: can't bind, err %d\n", f->name, f, status);

	D("-\n");
	return status;
}