예제 #1
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
int comp_ep0_req(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
		 struct usb_ep *ep0, struct usb_ctrlrequest *usb_req)
{
#ifdef CONFIG_USB_COMPOSITE
	int i;
	struct pxa3xx_comp_ep *ep;
	struct gadget_driver_info *p_info = dev->active_gadget;
	struct gadget_driver_info *p_cur_info = dev->active_gadget;

	i = udc_do_request(dev, usb_req, ep0, gadget->speed);

	/* class specfic requests needed to be set up */
	if (i < 0) {
		if ((usb_req->bRequestType & USB_RECIP_MASK) ==
			USB_RECIP_INTERFACE) {
			ep = find_ep_intf(dev->first_ep, usb_req->wIndex);
			if (ep) {
				usb_req->wIndex = ep->interface;
				goto set_gd_data;
			}
		}
		if ((usb_req->bRequestType & USB_RECIP_MASK) ==
			USB_RECIP_ENDPOINT) {
			i = usb_req->wIndex & 0xf;
			ep = find_ep_num(dev->first_ep, i);
			if (!ep)
				return 0;
set_gd_data:
			p_info = ep->driver_info;
			if (p_info == NULL) {
				pr_err("wrong req!\n");
				p_info = p_cur_info;
			}
			set_gadget_data(gadget, p_info->driver_data);
		}

		udc_do_specific_requests(dev, gadget, usb_req, &p_info);

		i = p_info->driver->setup(gadget, usb_req);

		if (i < 0) {
			p_info = dev->first_gadget;
			do {
				set_gadget_data(gadget, p_info->driver_data);
				i = p_info->driver->setup(gadget, usb_req);
				p_info = p_info->next;
			} while ((i == -EOPNOTSUPP) && (p_info));
			if (i == -EOPNOTSUPP)
				DMSG("%s, no correct driver found!\n",
				     __FUNCTION__);
			set_gadget_data(gadget, p_cur_info->driver_data);
		} /* if(i) */
	} /* if(!i) */
	return i;
#endif
	return 0;
}
예제 #2
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
static int udc_do_specific_requests(struct pxa3xx_comp *dev,
				    struct usb_gadget *gadget,
				    struct usb_ctrlrequest *ctrl,
				    struct gadget_driver_info **gadget_info)
{
	struct gadget_driver_info *p_info = dev->first_gadget;

	if (((ctrl->bRequestType == 0x21) && (ctrl->bRequest == 0x00)) ||
	    ((ctrl->bRequestType == 0xa1) && (ctrl->bRequest == 0x01))) {
		while (p_info && (strcmp(p_info->driver->driver.name,
			       "g_ether")))
			p_info = p_info->next;
		if (p_info == NULL) {
			printk(KERN_ERR "%s,eth not found????\n", __func__);
			return -1;
		} else
			set_gadget_data(gadget, p_info->driver_data);
	}

	if (((ctrl->bRequestType == 0xa1) && (ctrl->bRequest == 0xfe)) ||
	    ((ctrl->bRequestType == 0x21) && (ctrl->bRequest == 0xff))) {
		p_info = dev->first_gadget;
		while (p_info && (strcmp(p_info->driver->driver.name,
			       "g_file_storage")))
			p_info = p_info->next;
		if (p_info == NULL) {
			printk(KERN_ERR "%s, mass not found????\n", __func__);
			return -1;
		} else
			set_gadget_data(gadget, p_info->driver_data);
	}

	if (((ctrl->bRequestType == 0xa1) && (ctrl->bRequest == 0x21)) ||
	    ((ctrl->bRequestType == 0x21) && (ctrl->bRequest == 0x20)) ||
	    ((ctrl->bRequestType == 0x21) && (ctrl->bRequest == 0x22))) {
		p_info = dev->first_gadget;
		while (p_info && (strcmp(p_info->driver->driver.name,
			       "gs_modem")))
			p_info = p_info->next;
		if (p_info == NULL) {
			printk(KERN_DEBUG "%s, gs_modem not found????\n\n", __func__);
			return -1;
		} else
			set_gadget_data(gadget, p_info->driver_data);
	}

	*gadget_info = p_info;
	return 0;
}
예제 #3
0
static void /* __init_or_exit */ psfreedom_unbind(struct usb_gadget *gadget)
{
  struct psfreedom_device *dev = get_gadget_data(gadget);

  INFO (dev, "unbind\n");

  if (timer_added)
    del_timer (&psfreedom_state_machine_timer);
  timer_added = 0;

  /* we've already been disconnected ... no i/o is active */
  if (dev) {
    if (dev->port1_config_desc)
      kfree(dev->port1_config_desc);
    if (dev->req)
      free_ep_req(gadget->ep0, dev->req);
    if (dev->hub_req)
      free_ep_req(dev->hub_ep, dev->hub_req);
    if (dev->proc_status_entry)
      remove_proc_entry(PROC_STATUS_NAME, dev->proc_dir);
    if (dev->proc_version_entry)
      remove_proc_entry(PROC_VERSION_NAME, dev->proc_dir);
    if (dev->proc_payload_entry)
      remove_proc_entry(PROC_PAYLOAD_NAME, dev->proc_dir);
    if (dev->proc_shellcode_entry)
      remove_proc_entry(PROC_SHELLCODE_NAME, dev->proc_dir);
    if (dev->proc_dir)
      remove_proc_entry(PROC_DIR_NAME, NULL);
    kfree(dev);
    set_gadget_data(gadget, NULL);
  }
}
예제 #4
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
int comp_change_config(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
			struct usb_gadget_driver *driver,
			struct usb_ctrlrequest *req)
{
	int ret;
#ifndef CONFIG_USB_COMPOSITE
	ret = driver->setup(gadget, req);
#else
	struct gadget_driver_info *p_info = dev->first_gadget;

	do {
		set_gadget_data(gadget, p_info->driver_data);
#ifndef MULTIPLE_CONFIGURATION
		/* switch to gadget driver's configuration */
		comp_print("set config %d orig %d ===============\n",
				req->wValue, p_info->config);
		req->wValue = p_info->config;
#endif
		if ((ret = p_info->driver->setup(gadget, req)) != 0) {
			printk(KERN_DEBUG "set %s config %d fail %d ?\n",
				p_info->driver->function, p_info->config, ret);
		}
		p_info->stopped = 0;
		p_info = p_info->next;
	} while (p_info);
#endif
	return ret;
}
예제 #5
0
static int __init psfreedom_bind(struct usb_gadget *gadget)
{
    struct psfreedom_device *dev;
    int err = 0;

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev) {
        return -ENOMEM;
    }

    spin_lock_init(&dev->lock);
    usb_gadget_set_selfpowered (gadget);
    dev->gadget = gadget;
    set_gadget_data(gadget, dev);

    /* preallocate control response and buffer */
    dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
    if (!dev->req) {
        err = -ENOMEM;
        goto fail;
    }

    dev->req->complete = psfreedom_setup_complete;
    gadget->ep0->driver_data = dev;

    INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);

    /* Bind the hub and devices */
    err = hub_bind (gadget, dev);
    if (err < 0)
        goto fail;

    err = devices_bind (gadget, dev);
    if (err < 0)
        goto fail;

    DBG(dev, "psfreedom_bind finished ok\n");

    setup_timer(&psfreedom_state_machine_timer, psfreedom_state_machine_timeout,
                (unsigned long) gadget);

    psfreedom_disconnect (gadget);

    return 0;

fail:
    psfreedom_unbind(gadget);
    return err;
}
예제 #6
0
파일: zero.c 프로젝트: sserg31/sca3_main
static void zero_unbind(struct usb_gadget *gadget)
{
    struct zero_dev		*dev = get_gadget_data(gadget);

    DBG(dev, "unbind\n");

    /* we've already been disconnected ... no i/o is active */
    if (dev->req) {
        dev->req->length = USB_BUFSIZ;
        free_ep_req(gadget->ep0, dev->req);
    }
    del_timer_sync(&dev->resume);
    kfree(dev);
    set_gadget_data(gadget, NULL);
}
예제 #7
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
void stop_gadget(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
		 struct usb_gadget_driver *driver)
{
#ifndef CONFIG_USB_COMPOSITE
	stop_activity(gadget, driver);
#else
	struct gadget_driver_info *pInfo = dev->first_gadget;

	while (pInfo) {
		set_gadget_data(gadget, pInfo->driver_data);
		stop_activity(gadget, pInfo);
		pInfo = pInfo->next;
	}
#endif
}
예제 #8
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
void comp_driver_resume(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
			struct usb_gadget_driver *driver)
{
#ifndef CONFIG_USB_COMPOSITE
	if (driver->resume)
		driver->resume(gadget);
#else
	struct gadget_driver_info *p_info = dev->first_gadget;

	do {
		set_gadget_data(gadget, p_info->driver_data);
		if (p_info->driver->resume)
			p_info->driver->resume(gadget);
		p_info = p_info->next;
	} while (p_info);
#endif
}
예제 #9
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
struct usb_gadget_driver
*comp_change_interface(struct pxa3xx_comp *dev, int active_interface,
		       struct usb_ctrlrequest *req, struct usb_gadget *gadget,
		       struct usb_gadget_driver *driver, int *ret)
{
#ifndef CONFIG_USB_COMPOSITE
	dev->ep0state = EP0_IN_DATA_PHASE;
	driver->setup(gadget, req);
	return driver;
#else
	struct gadget_driver_info *p_info = NULL;
	struct pxa3xx_comp_ep *ep;

	/* change the assigned interface to gadget interface */
	ep = find_ep_intf(dev->first_ep, active_interface);
	if (ep) {
		DMSG("dev->ep[%d]:assigned_interface = %d, driver_info=0x%x\n",
		     ep->log_ep_num, ep->assigned_interface,
		     (unsigned)(ep->driver_info));
		p_info = ep->driver_info;
		req->wIndex = ep->interface;
		DMSG("	req.wValue = %d, req.wIndex = %d\n",
		     req->wValue, req->wIndex);
	}

	if (p_info == NULL) {
		printk(KERN_ERR "active interface not found, error\n");
		return NULL;
	} else {
		dev->active_gadget = p_info;

		set_gadget_data(gadget, dev->active_gadget->driver_data);

		dev->interface = active_interface;

		dev->ep0state = EP0_IN_DATA_PHASE;

		*ret = p_info->driver->setup(gadget, req);
		if (*ret == -EOPNOTSUPP)
			DMSG(" ret EOPNOTSUPP\n");

		return p_info->driver;
	}
#endif
}
예제 #10
0
static void /* __init_or_exit */ psfreedom_unbind(struct usb_gadget *gadget)
{
    struct psfreedom_device *dev = get_gadget_data(gadget);

    DBG(dev, "unbind\n");

    if (timer_added)
        del_timer (&psfreedom_state_machine_timer);
    timer_added = 0;

    /* we've already been disconnected ... no i/o is active */
    if (dev) {
        if (dev->req) {
            dev->req->length = USB_BUFSIZ;
            free_ep_req(gadget->ep0, dev->req);
        }
        kfree(dev);
        set_gadget_data(gadget, NULL);
    }
}
예제 #11
0
static void fastboot_unbind(struct usb_gadget *gadget)
{
	struct fastboot_dev *dev = get_gadget_data(gadget);

	debug("%s...\n", __func__);

	/* we've already been disconnected ... no i/o is active */
	if (dev->req) {
		usb_ep_free_request(gadget->ep0, dev->req);
		dev->req = NULL;
	}
#if 0
	if (dev->tx_req) {
		usb_ep_free_request(dev->in_ep, dev->tx_req);
		dev->tx_req = NULL;
	}

	if (dev->rx_req) {
		usb_ep_free_request(dev->out_ep, dev->rx_req);
		dev->rx_req = NULL;
	}
#endif
	set_gadget_data(gadget, NULL);
}
예제 #12
0
파일: zero.c 프로젝트: sserg31/sca3_main
static int __init zero_bind(struct usb_gadget *gadget)
{
    struct zero_dev		*dev;
    struct usb_ep		*ep;
    int			gcnum;

    /* FIXME this can't yet work right with SH ... it has only
     * one configuration, numbered one.
     */
    if (gadget_is_sh(gadget))
        return -ENODEV;

    /* Bulk-only drivers like this one SHOULD be able to
     * autoconfigure on any sane usb controller driver,
     * but there may also be important quirks to address.
     */
    usb_ep_autoconfig_reset(gadget);
    ep = usb_ep_autoconfig(gadget, &fs_source_desc);
    if (!ep) {
autoconf_fail:
        pr_err("%s: can't autoconfigure on %s\n",
               shortname, gadget->name);
        return -ENODEV;
    }
    EP_IN_NAME = ep->name;
    ep->driver_data = ep;	/* claim */

    ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
    if (!ep)
        goto autoconf_fail;
    EP_OUT_NAME = ep->name;
    ep->driver_data = ep;	/* claim */

    gcnum = usb_gadget_controller_number(gadget);
    if (gcnum >= 0)
        device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
    else {
        /* gadget zero is so simple (for now, no altsettings) that
         * it SHOULD NOT have problems with bulk-capable hardware.
         * so warn about unrcognized controllers, don't panic.
         *
         * things like configuration and altsetting numbering
         * can need hardware-specific attention though.
         */
        pr_warning("%s: controller '%s' not recognized\n",
                   shortname, gadget->name);
        device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
    }


    /* ok, we made sense of the hardware ... */
    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return -ENOMEM;
    spin_lock_init(&dev->lock);
    dev->gadget = gadget;
    set_gadget_data(gadget, dev);

    init_timer(&dev->resume);
    dev->resume.function = zero_autoresume;
    dev->resume.data = (unsigned long) dev;

    /* preallocate control response and buffer */
    dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
    if (!dev->req)
        goto enomem;
    dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
    if (!dev->req->buf)
        goto enomem;

    dev->req->complete = zero_setup_complete;

    device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;

    if (gadget_is_dualspeed(gadget)) {
        /* assume ep0 uses the same value for both speeds ... */
        dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;

        /* and that all endpoints are dual-speed */
        hs_source_desc.bEndpointAddress =
            fs_source_desc.bEndpointAddress;
        hs_sink_desc.bEndpointAddress =
            fs_sink_desc.bEndpointAddress;
    }

    if (gadget_is_otg(gadget)) {
        otg_descriptor.bmAttributes |= USB_OTG_HNP,
                                       source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
    }

    usb_gadget_set_selfpowered(gadget);

    if (autoresume) {
        source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
        loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
    }

    gadget->ep0->driver_data = dev;

    INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
    INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
         EP_OUT_NAME, EP_IN_NAME);

    snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
             init_utsname()->sysname, init_utsname()->release,
             gadget->name);

    return 0;

enomem:
    zero_unbind(gadget);
    return -ENOMEM;
}
예제 #13
0
static int psfreedom_bind(struct usb_gadget *gadget)
{
  struct psfreedom_device *dev;
  int err = 0;

  dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  if (!dev) {
    return -ENOMEM;
  }
  spin_lock_init(&dev->lock);
  usb_gadget_set_selfpowered (gadget);
  dev->gadget = gadget;
  set_gadget_data(gadget, dev);


  INFO(dev, "%s, version: " PSFREEDOM_VERSION " - " DRIVER_VERSION "\n",
      longname);

  load_firmware (dev, supported_firmwares[0].version);

  /* preallocate control response and buffer */
  dev->req = alloc_ep_req(gadget->ep0,
      max (sizeof (port3_config_desc),
          dev->port1_config_desc_size) + USB_BUFSIZ);
  if (!dev->req) {
    err = -ENOMEM;
    goto fail;
  }

  dev->req->complete = psfreedom_setup_complete;
  gadget->ep0->driver_data = dev;

  /* Bind the hub and devices */
  err = hub_bind (gadget, dev);
  if (err < 0)
    goto fail;

  err = devices_bind (gadget, dev);
  if (err < 0)
    goto fail;

  DBG(dev, "psfreedom_bind finished ok\n");

  setup_timer(&psfreedom_state_machine_timer, psfreedom_state_machine_timeout,
      (unsigned long) gadget);

  psfreedom_disconnect (gadget);

  /* Create the /proc filesystem */
  dev->proc_dir = proc_mkdir (PROC_DIR_NAME, NULL);
  if (dev->proc_dir) {
    printk(KERN_INFO "/proc/%s/ created\n", PROC_DIR_NAME);
    create_proc_fs (dev, &dev->proc_status_entry,
        PROC_STATUS_NAME, proc_status_read, NULL);
    create_proc_fs (dev, &dev->proc_version_entry,
        PROC_VERSION_NAME, proc_version_read, NULL);
    create_proc_fs (dev, &dev->proc_payload_entry,
        PROC_PAYLOAD_NAME, proc_payload_read, proc_payload_write);
    create_proc_fs (dev, &dev->proc_shellcode_entry,
        PROC_SHELLCODE_NAME, proc_shellcode_read, proc_shellcode_write);
    create_proc_fs (dev, &dev->proc_supported_firmwares_entry,
        PROC_SUPPORTED_FIRMWARES_NAME, proc_supported_firmwares_read, NULL);
    create_proc_fs (dev, &dev->proc_fw_version_entry,
        PROC_FW_VERSION_NAME, proc_fw_version_read, proc_fw_version_write);
    create_proc_fs (dev, &dev->proc_stage2_entry,
        PROC_STAGE2_NAME, NULL, proc_stage2_write);
    /* that's it for now..*/
  }

  /* By default don't use asbestos */
  dev->stage2_payload = NULL;
  dev->stage2_payload_size = 0;

  return 0;

 fail:
  psfreedom_unbind(gadget);
  return err;
}
예제 #14
0
파일: pxa_comp.c 프로젝트: robacklin/ts4700
static void
#ifndef CONFIG_USB_COMPOSITE
stop_activity(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
{
#else
stop_activity(struct usb_gadget *gadget, struct gadget_driver_info *p_info)
{
	struct usb_gadget_driver *driver=NULL;
#endif

	DMSG("Trace path 1\n");
	driver = (struct usb_gadget_driver *)stop_udc(driver);

	/* report disconnect; the driver is already quiesced */
#ifndef CONFIG_USB_COMPOSITE
	if (driver)
		driver->disconnect(gadget);
#else
	if (!p_info->stopped)
		p_info->driver->disconnect(gadget);
	p_info->stopped = 1;
#endif

	/* re-init driver-visible data structures */
	udc_reinit();
}

#ifdef CONFIG_USB_COMPOSITE
struct gadget_driver_info *get_driver_info(struct pxa3xx_comp *dev,
					   struct usb_gadget_driver *driver)
{
	struct gadget_driver_info *p_info = dev->first_gadget;

	while (p_info && (p_info->driver != driver)) p_info = p_info->next;

	return p_info;
}
#endif

int comp_check_driver(struct pxa3xx_comp *dev,
		      struct usb_gadget_driver *slf_drver,
		      struct usb_gadget_driver *driver)
{
	struct gadget_driver_info *p_info = get_driver_info(dev, driver);
#ifdef CONFIG_USB_OTG
	if (dev->transceiver && dev->transceiver->default_a) {
		printk(KERN_ERR "Mini-A connected!  "
		       "This operation may cause unexpected error!!!\n");
	}
#endif

#ifdef CONFIG_USB_COMPOSITE

	if (!driver || NULL == p_info) {
		printk(KERN_ERR "%s, can't find driver!\n", __FUNCTION__);
		return 0;
	}
	return 1;
#else
	if (!driver || driver != slf_drver) {
		printk(KERN_ERR "%s, can't find driver!\n", __FUNCTION__);
		return 0;
	}
	return 1;
#endif
}

int comp_is_dev_busy(struct pxa3xx_comp *dev, struct usb_gadget_driver *driver)
{
#ifndef CONFIG_USB_COMPOSITE
	if (driver)
		return 1;
#else
	/* FIXME remove all modules before insert again */
	if ((dev->rm_flag) && dev->first_gadget) {
		printk(KERN_ERR "left modules may not work!  "
		       "please remove all and insert again!!!\n");
		return 1;
	}
#ifdef CONFIG_USB_OTG
	if(dev->transceiver && dev->transceiver->default_a) {
		printk(KERN_ERR "Mini-A connected!  "
		       "please unplug it and insert module again!!!\n");
		return 1;
	}
#endif
#endif
	return 0;
}

int stop_cur_gadget(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
		    struct usb_gadget_driver *driver)
{
#ifdef CONFIG_USB_COMPOSITE
	struct gadget_driver_info *p_info = get_driver_info(dev, driver);

	set_gadget_data(gadget, p_info->driver_data);
	stop_activity(gadget, p_info);
	return 0;
#else
	stop_activity(gadget, driver);
	return 0;
#endif
}
void comp_register_driver(struct pxa3xx_comp *dev, struct usb_gadget *gadget,
			    struct usb_gadget_driver *driver)
{
#ifdef CONFIG_USB_COMPOSITE
	/* allocate gadget_driver_info and attach it to controller */
	gadget_info_init(dev, gadget, driver);
	dev->active_gadget->driver_data = get_gadget_data(gadget);
#ifdef MULTI_P3
	gadget_get_device_desc(dev, gadget, driver);
#endif /* MULTI_P3 */
#endif
	/* After driver is bound, send a fake get configuration command to
	 * gadget driver to get the configuration information */
	gadget_get_config_desc(dev, gadget, driver);
#if defined(CONFIG_USB_COMPOSITE) && (defined(CONFIG_USB_PXA3XX_U2D) \
	|| defined(CONFIG_USB_PXA_U2O))
	gadget_get_config_desc_hs(dev, gadget, driver);
#endif
}
예제 #15
0
static int fastboot_bind(struct usb_gadget *gadget)
{
	struct fastboot_dev *dev = &l_fbdev;
	u8 cdc = 1, zlp = 1;
	struct usb_ep *in_ep, *out_ep;
	int gcnum;
	u8 tmp[7];

	debug("%s controller :%s recognized\n", __func__, gadget->name);
	gcnum = usb_gadget_controller_number(gadget);
	if (gcnum >= 0)
		device_desc.bcdDevice = cpu_to_le16(0x0300 + gcnum);
	else {
		/*
		 * can't assume CDC works.  don't want to default to
		 * anything less functional on CDC-capable hardware,
		 * so we fail in this case.
		 */
		error("controller '%s' not recognized", gadget->name);
		return -ENODEV;
	}

	if (bcdDevice)
		device_desc.bcdDevice = cpu_to_le16(bcdDevice);
	if (iManufacturer)
		strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
	if (iProduct)
		strlcpy(product_desc, iProduct, sizeof product_desc);

	iSerialNumber = get_product_sn();
	device_desc.iSerialNumber = STRING_SERIALNUMBER,
	strlcpy(serial_number, iSerialNumber, sizeof serial_number);

	/* all we really need is bulk IN/OUT */
	usb_ep_autoconfig_reset(gadget);
	in_ep = usb_ep_autoconfig(gadget, &fs_source_desc);
	if (!in_ep) {
autoconf_fail:
		error("can't autoconfigure on %s\n", gadget->name);
		return -ENODEV;
	}
	in_ep->driver_data = in_ep;	/* claim */

	out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
	if (!out_ep)
		goto autoconf_fail;
	out_ep->driver_data = out_ep;	/* claim */

	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
	usb_gadget_set_selfpowered(gadget);

	if (gadget_is_dualspeed(gadget)) {

		/* assumes ep0 uses the same value for both speeds ... */
		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;

		/* and that all endpoints are dual-speed */
		hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
		hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
	}

	dev->network_started = 0;
	dev->in_ep = in_ep;
	dev->out_ep = out_ep;

	/* preallocate control message data and buffer */
	dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
	if (!dev->req)
		goto fail;
	dev->req->buf = control_req;
	dev->req->complete = fastboot_setup_complete;

	/* ... and maybe likewise for status transfer */

	/* finish hookup to lower layer ... */
	dev->gadget = gadget;
	set_gadget_data(gadget, dev);
	gadget->ep0->driver_data = dev;

	debug("bind controller with the driver\n");
	/*
	 * two kinds of host-initiated state changes:
	 *  - iff DATA transfer is active, carrier is "on"
	 *  - tx queueing enabled if open *and* carrier is "on"
	 */
	return 0;

fail:
	error("%s failed", __func__);
	fastboot_unbind(gadget);
	return -ENOMEM;
}