Fork me on GitHub
侧边栏

gadget驱动框架(二)

usb_composite_driver的创建于注册

源码:drivers/usb/legacy/serial.c

//创建usb_composite_driver
static struct usb_composite_driver gserial_driver = {
    .name        = "g_serial",
    .dev        = &device_desc,
    .strings    = dev_strings,
    .max_speed    = USB_SPEED_SUPER,
    .bind        = gs_bind,
    .unbind        = gs_unbind,
};

static int __init init(void)
{
    /* We *could* export two configs; that'd be much cleaner...
     * but neither of these product IDs was defined that way.
     */bConfigurationValue、class、pid等
     //初始化
    if (use_acm) {
        serial_config_driver.label = "CDC ACM config";
        serial_config_driver.bConfigurationValue = 2;
        device_desc.bDeviceClass = USB_CLASS_COMM;
        device_desc.idProduct =
                cpu_to_le16(GS_CDC_PRODUCT_ID);
    } else if (use_obex) {
        serial_config_driver.label = "CDC OBEX config";
        serial_config_driver.bConfigurationValue = 3;
        device_desc.bDeviceClass = USB_CLASS_COMM;
        device_desc.idProduct =
            cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID);
    } else {
        serial_config_driver.label = "Generic Serial config";
        serial_config_driver.bConfigurationValue = 1;
        device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
        device_desc.idProduct =
                cpu_to_le16(GS_PRODUCT_ID);
    }
    strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;

    //注册usb_composite_driver与usb_composite_dev
    return usb_composite_probe(&gserial_driver);
}
module_init(init);

static void __exit cleanup(void)
{
    usb_composite_unregister(&gserial_driver);
}
module_exit(cleanup);

注意adb、mtp等功能已经通过g_ffs.c(functionfs)来与应用通信,如果没有这个的话,也可以通过g_adb.c来通信。(需要确认版本问题。)只要有合适的functionfs driver来实现。

usb_gadget_driver的创建与注册

//创建usb_gadget_driver
static const struct usb_gadget_driver composite_driver_template = {
    .bind        = composite_bind,
    .unbind        = composite_unbind,

    .setup        = composite_setup,
    .reset        = composite_disconnect,
    .disconnect    = composite_disconnect,

    .suspend    = composite_suspend,
    .resume        = composite_resume,

    .driver    = {
        .owner        = THIS_MODULE,
    },
};

int usb_composite_probe(struct usb_composite_driver *driver)
{
    struct usb_gadget_driver *gadget_driver;

    if (!driver || !driver->dev || !driver->bind)
        return -EINVAL;

    if (!driver->name)
        driver->name = "composite";

    driver->gadget_driver = composite_driver_template;
    gadget_driver = &driver->gadget_driver;

    gadget_driver->function =  (char *) driver->name;
    gadget_driver->driver.name = driver->name;
    gadget_driver->max_speed = driver->max_speed;

    //注册usb_gadget_driver
    return usb_gadget_probe_driver(gadget_driver);
}
EXPORT_SYMBOL_GPL(usb_composite_probe);

//注册usb_gadget_driver
int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
    struct usb_udc        *udc = NULL;
    int            ret = -ENODEV;

    if (!driver || !driver->bind || !driver->setup)
        return -EINVAL;

    mutex_lock(&udc_lock);
    if (driver->udc_name) {
        list_for_each_entry(udc, &udc_list, list) {
            ret = strcmp(driver->udc_name, dev_name(&udc->dev));
            if (!ret)
                break;
        }
        if (ret)
            ret = -ENODEV;
        else if (udc->driver)
            ret = -EBUSY;
        else
            goto found;
    } else {
        list_for_each_entry(udc, &udc_list, list) {
            /* For now we take the first one */
            if (!udc->driver)
                goto found;
        }
    }

    //无udc设备,则将usb_gadget_driver添加到gadget_driver_pending_list链表
    if (!driver->match_existing_only) {
        list_add_tail(&driver->pending, &gadget_driver_pending_list);
        pr_info("udc-core: couldn't find an available UDC - added [%s] to list of pending drivers\n",
            driver->function);
        ret = 0;
    }

    mutex_unlock(&udc_lock);
    return ret;
found:
    //udc设备与usb_gadget_driver绑定
    ret = udc_bind_to_driver(udc, driver);
    mutex_unlock(&udc_lock);
    return ret;
}

usb_gadget的创建及注册

源码:linux4.19.123-drivers/usb/gadget/udc/s3c2410_udc.c

static const struct usb_ep_ops s3c2410_ep_ops = {
    .enable        = s3c2410_udc_ep_enable,
    .disable    = s3c2410_udc_ep_disable,

    .alloc_request    = s3c2410_udc_alloc_request,
    .free_request    = s3c2410_udc_free_request,

    .queue        = s3c2410_udc_queue,
    .dequeue    = s3c2410_udc_dequeue,

    .set_halt    = s3c2410_udc_set_halt,
};

static const struct usb_gadget_ops s3c2410_ops = {
    .get_frame        = s3c2410_udc_get_frame,
    .wakeup            = s3c2410_udc_wakeup,
    .set_selfpowered    = s3c2410_udc_set_selfpowered,
    .pullup            = s3c2410_udc_pullup,
    .vbus_session        = s3c2410_udc_vbus_session,
    .vbus_draw        = s3c2410_vbus_draw,
    .udc_start        = s3c2410_udc_start,
    .udc_stop        = s3c2410_udc_stop,
};

/*---------------------------------------------------------------------------*/
static struct s3c2410_udc memory = {
    //usb_gadget初始化
    .gadget = {
        .ops        = &s3c2410_ops,
        .ep0        = &memory.ep[0].ep,
        .name        = gadget_name,
        .dev = {
            .init_name    = "gadget",
        },
    },

    /* control endpoint */
    .ep[0] = {
        .num        = 0,
        .ep = {
            .name        = ep0name,
            .ops        = &s3c2410_ep_ops,
            .maxpacket    = EP0_FIFO_SIZE,
            .caps        = USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL,
                        USB_EP_CAPS_DIR_ALL),
        },
        .dev        = &memory,
    },

    /* first group of endpoints */
    .ep[1] = {
        .num        = 1,
        .ep = {
            .name        = "ep1-bulk",
            .ops        = &s3c2410_ep_ops,
            .maxpacket    = EP_FIFO_SIZE,
            .caps        = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
                        USB_EP_CAPS_DIR_ALL),
        },
        .dev        = &memory,
        .fifo_size    = EP_FIFO_SIZE,
        .bEndpointAddress = 1,
        .bmAttributes    = USB_ENDPOINT_XFER_BULK,
    },
    .ep[2] = {
        .num        = 2,
        .ep = {
            .name        = "ep2-bulk",
            .ops        = &s3c2410_ep_ops,
            .maxpacket    = EP_FIFO_SIZE,
            .caps        = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
                        USB_EP_CAPS_DIR_ALL),
        },
        .dev        = &memory,
        .fifo_size    = EP_FIFO_SIZE,
        .bEndpointAddress = 2,
        .bmAttributes    = USB_ENDPOINT_XFER_BULK,
    },
    .ep[3] = {
        .num        = 3,
        .ep = {
            .name        = "ep3-bulk",
            .ops        = &s3c2410_ep_ops,
            .maxpacket    = EP_FIFO_SIZE,
            .caps        = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
                        USB_EP_CAPS_DIR_ALL),
        },
        .dev        = &memory,
        .fifo_size    = EP_FIFO_SIZE,
        .bEndpointAddress = 3,
        .bmAttributes    = USB_ENDPOINT_XFER_BULK,
    },
    .ep[4] = {
        .num        = 4,
        .ep = {
            .name        = "ep4-bulk",
            .ops        = &s3c2410_ep_ops,
            .maxpacket    = EP_FIFO_SIZE,
            .caps        = USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK,
                        USB_EP_CAPS_DIR_ALL),
        },
        .dev        = &memory,
        .fifo_size    = EP_FIFO_SIZE,
        .bEndpointAddress = 4,
        .bmAttributes    = USB_ENDPOINT_XFER_BULK,
    }

};
/*
 *    probe - binds to the platform device
 */
static int s3c2410_udc_probe(struct platform_device *pdev)
{
    struct s3c2410_udc *udc = &memory;
    struct device *dev = &pdev->dev;
    int retval;
    int irq;

    dev_dbg(dev, "%s()\n", __func__);

    ......

    //创建/注册udc,注册usb_gadget
    retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
    if (retval)
        goto err_add_udc;

    ......

    return 0;

err_add_udc:
    if (udc_info && !udc_info->udc_command &&
            gpio_is_valid(udc_info->pullup_pin))
        gpio_free(udc_info->pullup_pin);
err_vbus_irq:
    if (udc_info && udc_info->vbus_pin > 0)
        free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
err_gpio_claim:
    if (udc_info && udc_info->vbus_pin > 0)
        gpio_free(udc_info->vbus_pin);
err_int:
    free_irq(IRQ_USBD, udc);
err_map:
    iounmap(base_addr);
err_mem:
    release_mem_region(rsrc_start, rsrc_len);

    return retval;
}

usb_udc的创建及注册

源码:linux-4.19.123-drivers/usb/gadget/udc/core.c

int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
{
    return usb_add_gadget_udc_release(parent, gadget, NULL);
}
EXPORT_SYMBOL_GPL(usb_add_gadget_udc);


/**
 * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list
 * @parent: the parent device to this udc. Usually the controller driver's
 * device.
 * @gadget: the gadget to be added to the list.
 * @release: a gadget release function.
 *
 * Returns zero on success, negative errno otherwise.
 * Calls the gadget release function in the latter case.
 */
int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
        void (*release)(struct device *dev))
{
    struct usb_udc        *udc;
    int            ret = -ENOMEM;

    dev_set_name(&gadget->dev, "gadget");
    INIT_WORK(&gadget->work, usb_gadget_state_work);
    gadget->dev.parent = parent;

    if (release)
        gadget->dev.release = release;
    else
        gadget->dev.release = usb_udc_nop_release;

    device_initialize(&gadget->dev);

    //创建usb_udc
    udc = kzalloc(sizeof(*udc), GFP_KERNEL);
    if (!udc)
        goto err_put_gadget;

    device_initialize(&udc->dev);
    udc->dev.release = usb_udc_release;
    udc->dev.class = udc_class;
    udc->dev.groups = usb_udc_attr_groups;
    udc->dev.parent = parent;
    ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
    if (ret)
        goto err_put_udc;

    ret = device_add(&gadget->dev);
    if (ret)
        goto err_put_udc;

    udc->gadget = gadget;
    gadget->udc = udc;

    mutex_lock(&udc_lock);
    //将新创建的usb_udc添加到udc_list链表中
    list_add_tail(&udc->list, &udc_list);

    ret = device_add(&udc->dev);
    if (ret)
        goto err_unlist_udc;

    usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
    udc->vbus = true;

    /* pick up one of pending gadget drivers */
    ret = check_pending_gadget_drivers(udc);
    if (ret)
        goto err_del_udc;

    mutex_unlock(&udc_lock);

    return 0;

 err_del_udc:
    device_del(&udc->dev);

 err_unlist_udc:
    list_del(&udc->list);
    mutex_unlock(&udc_lock);

    device_del(&gadget->dev);

 err_put_udc:
    put_device(&udc->dev);

 err_put_gadget:
    put_device(&gadget->dev);
    return ret;
}

小结

至此,已完成usb_gadget_driver、usb_composite_driver、usb_gadget、usb_udc等几个核心结构体的创建及注册。后面将介绍usb_composite_dev等的创建及注册,以及usb_gadget_driver与usb_udc的绑定过程。

image

posted @ 2024-09-05 15:46  yooooooo  阅读(163)  评论(0)    收藏  举报