首页 > 其他分享 >gadget驱动框架(二)

gadget驱动框架(二)

时间:2024-09-05 15:48:38浏览次数:10  
标签:usb 框架 gadget driver dev udc s3c2410 驱动

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的绑定过程。

标签:usb,框架,gadget,driver,dev,udc,s3c2410,驱动
From: https://www.cnblogs.com/linhaostudy/p/18398597

相关文章

  • 若依框架登录鉴权详解
    若依框架(Ruoyi)后端的登录权限身份认证流程是一个复杂但高效的过程,它确保了系统的安全性和数据的保护。以下是一个典型的若依框架后端登录权限身份认证流程,基于多个来源的信息进行归纳和整理:1.发起请求获取认证凭证(token)现象:用户未登录或者token过期,刷新页面将重定向至登录页......
  • 视频处理基础之gradio框架实现
    这些函数是用于处理视频文件的Python代码片段,它们依赖于`ffmpeg`和`ffprobe`工具,这些工具是`FFmpeg`项目的一部分,用于处理视频和音频数据。下面是每个函数的用途和用法的总结:1.`ffmpeg_installed()`函数:  -用途:检查系统是否安装了`ffmpeg`工具。  -用法:调用此函数......
  • ros2框架分析
    工作流包创建ros2pkgcreateimage_server--build-typeament_python--dependenciescv_bridgerclpysensor_msgsstd_msgs使用ros2pkgcreate创建的ROS2包默认位于你执行该命令时所在的当前工作目录下。定义消息类型定义服务接口配置包package.xml:作用:......
  • T8332FN凯钰Tmtech LED驱动芯片升降压降压
    T8332FN:高效LED驱动控制器的核心功能与应用分析T8332FN是一款由TMTechnology,Inc.设计的高效LED驱动控制器,广泛应用于高功率LED驱动领域,如汽车照明、LCD背光和室内外照明等。该芯片集成了多种保护功能和调节能力,能够在复杂应用中提供高精度、稳定的恒流输出。本文将对T8332F......
  • [开题报告]flask框架沧州交通学院二手交易系统2ht5t(python+程序+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景在沧州交通学院这一充满活力的学术社区中,随着学生人数的增加和校园生活的日益丰富,二手物品的流通与交易成为了广大师生普遍关注的话题。传......
  • [开题报告]flask框架的安心养老一站通服务系统的设计与实现c3af4(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着全球人口老龄化的加速,养老问题已成为社会关注的焦点。传统的养老模式已难以满足日益增长的多元化养老需求,特别是在健康监测、生活照料......
  • 数字化时代,为什么需要设计以用户体验为中心的企业架构框架
    在竞争激烈的市场环境中,用户体验(CustomerExperience,CX)已成为企业成功的关键因素。一个优质的用户体验不仅能够提升客户满意度,还能增强品牌忠诚度,推动业务增长。然而,打造卓越的用户体验并非易事,它需要企业在多个层面进行精细化的管理和优化。 本文将探讨企业架构如何通过优化流......
  • SeleniumBase 利用数据驱动 方式运行-使用笔记(五)
    自动化福音(爬虫、办公、测试等)SeleniumBase使用笔记(五)SeleniumBase利用数据驱动方式运行有同学问我,如何对SeleniumBase使用数据驱动见评论区,于是有了这个文章。目录SeleniumBase继承方式SeleniumBase夹具方式继承方式这种方式的使用,前提是你的代码使用的继承B......
  • 基于Java中的SSM框架实现校园门户网管理系统项目【项目源码+论文说明】
    基于Java中的SSM框架实现校园门户网管理系统演示摘要随着我国高校信息化建设内容的不断完善,很多高校都通过建立校园门户网站的方式搭建起高校与社会之间信息传递的桥梁,通过校园网站的建立来拓宽校园信息传播的渠道,利用全方位的校园环境及师资力量的介绍来吸引更多的学子,同......
  • 基于Java中的SSM框架实现私人书店管理系统项目【项目源码+论文说明】
    基于java中的SSM框架实现私人书店管理系统平台演示【内附项目源码+LW说明】摘要电子商务在近些年来已经成为了我国重要的第三产业之一,电子商务成为了我国经济增速中一个不可缺少的组成部分,而随着互联网技术的不断发展,现在的电子商务也已经日趋成熟,不仅仅是在技术层面实现......