Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;

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

	/* maybe allocate device-global string ID */
	if (gser_string_defs[0].id == 0) {
		status = usb_string_id(c->cdev);
		if (status < 0)
			return status;
		gser_string_defs[0].id = status;
	}

	/* 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

	/* support all relevant hardware speeds... we expect that when
	 * hardware is dual speed, all bulk-capable endpoints work at
	 * both speeds
	 */
	gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
	gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;

	gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
	gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;

	if (gadget_is_dualspeed(c->cdev->gadget)) {
#ifdef CONFIG_MODEM_SUPPORT
		gser_hs_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif
	}
	if (gadget_is_superspeed(c->cdev->gadget)) {
#ifdef CONFIG_MODEM_SUPPORT
		gser_ss_notify_desc.bEndpointAddress =
				gser_fs_notify_desc.bEndpointAddress;
#endif
	}

	status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
			gser_ss_function);
	if (status)
		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:
#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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
0
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;
}
/* 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;
}