usb_gadget

使用USB Gadget框架让USB变成串口设备 使用USB Gadget框架定义特殊的USB设备 阅读详情

第一次使用Astah画图,还不熟悉这个工具的使用,粗略的画了一个小流程

如下图所示,UDC驱动层会回调usb Gadget设备层提供的bind方法,即composite_bind,composite_bind又回调了我们在gadget功能驱动层提供的bind函数.
可以简单对比的是在platfrom bus中 :
platfrom bus 提供的 probe函数(如果总线有提供,如 IIC bus)最终也会回调我们platfrom driver 提供的probe()函数,我们就可以在probe函数中做一些操作了,如获取platfrom device 提供的一些资源信息

这里写图片描述

/*
    UDC驱动是一个platform driver,
    平台总线、平台设备、平台驱动 这样的设计真是太好了,驱动与设备信息分开
    貌似和 设备树 有一比,这些都是linux kernel 架构绝美精华部分,对之敬仰之情,犹如滔滔江水.........!!
*/
static int __init udc_init(void)
{
    int retval;
    ....
    ....    
    /*
        注册平台驱动,如果有同名的平台设备的话,那么该驱动的probe将会被调用
        下面看这个 udc_driver_24x0
    */
    retval = platform_driver_register(&udc_driver_24x0);
    if (retval)
        goto err;
    return 0;
err:
    debugfs_remove(s3c2410_udc_debugfs_root);
    return retval;
}

static struct platform_driver udc_driver_24x0 = {
    .driver = {
        .name  = "s3c24x0-usbgadget",
        .owner = THIS_MODULE,   
    },
    .probe    = s3c2410_udc_probe,   // probe函数

};

static int s3c2410_udc_probe(struct platform_device * pdev)
{
    /*
        这个是下面传递给中断处理函数的参数,下面看
    */
    struct s3c2410_udc * udc = &memory;
    /**
        注册了一个中断处理函数,看第五个参数 udc 被传递给中断处理函数s3c2410_udc_irq了 
    */
    retval = request_irq(IRQ_USBD,s3c2410_udc_irq,0,gadget_name,udc);
    if (retval != 0){
        ...
    }
}
/*
    传递给中断处理函数的参数,就是那个udc
    这是一个很重要的结构体,看它的成员gadget的ops 是 s3c2410_ops
    这个s3c2410_ops提供的函数都会被一一的按照顺序在各个时间段调用.
    什么阶段调用这里面的哪个函数,在下面会有分析
    这里先列出来
    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 = {
    .gadget = {
        .ops        = &s3c2410_ops,
        .ep0        = &memory.ep[0].ep,
        .name       = gadget_name,
        .dev = {
            .init_name  = "gadget",
        },
    },

    /* 控制端点,端点0  ep0 */
    .ep[0] = {
        .num        = 0,
        .ep = {
            .name       = ep0name,          // "ep0"
            .ops        = &s3c2410_ep_ops,  // ep0的操作函数
            .maxpacket  = EP0_FIFO_SIZE,    // 8
        },
        .dev        = &memory,
    },
    .ep[1] = {
        ....
    },
    .ep[2] = {
        ....
    },
    .ep[3] = {
        ....
    },
    .ep[4] = {
        ....
    }
};

/*
    好,上面演员都到场了,下面好戏要开始了
*/
static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
{
    /*
        那个 udc,就是那个memory
    */
    struct s3c2410_udc *dev = _dev;
    ...
    /*
        读取状态寄存器
    */
    usb_status  =  udc_read(S3C2410_UDC_USB_INT_REG);
    ...
    /*RESET  暂不分析实现 */
    if (usb_status & S3C2410_UDC_USBINT_RESET) {
    }
    /* RESUME  暂不分析实现*/
    if (usb_status & S3C2410_UDC_USBINT_RESUME) {
    }
    /*SUSPEND 暂不分析实现*/
    if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
    }
    /*
        看好了,要分析这个if分支了
    */
    if (usbd_status & S3C2410_UDC_INT_EP0) {
        dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
        /* Clear the interrupt bit by setting it to 1    清中断*/
        udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
        /**
            设备枚举的时候USB设备控制器产生的中断都会进入这个if分支,都会执行下面的这个函数,大名鼎鼎的端点0呀
            它最有可能会执行 switch case 分支中的 s3c2410_udc_handle_ep0_idle这个函数,
            所以,这里是一个设备枚举时操作的总入口
        */
        s3c2410_udc_handle_ep0(dev);
    }

}
static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
{
    /*
        端点0 的寄存器,下面会用udc_read()来读取S3C2410_UDC_IN_CSR1_REG
        到了底层都是与寄存器打交道了.这些寄存器中的数据是上面神马层、神马结构体、神马链表的活动基础,
        端点0寄存器说没有我,你们都别玩了,该干嘛干嘛去把.玩 你们也玩不转.哈哈!
    */
    u32         ep0csr;
    /*
        s3c2410_ep 表示的是一个s3c2410 usb 设备控制器的一个端点
        这个dev还是那个memory,ep[0]请参考上面的memory的成员
    */
    struct s3c2410_ep   *ep = &dev->ep[0];
    /*
        表示的是usb_request 一次传输请求,类似与主机端的urb,
        源码中是这样说的: 
         NOTE:* this is analogous to 'struct urb' on the host side, except that
              * it's thinner and promotes more pre-allocation.
        它里面有一个回调函数很重要,原型是这样的
        void (*complete)(struct usb_ep *ep,struct usb_request *req); 下面做重点关注

        这个req是表示的一个聚集在端点上的一次请求,后面会从链表上取出来赋值给它

        linux kernel 的函数一上来就定义一坨坨变量,这些变量绝大多数都会在下面被直接赋值,或则是
        作为传出参数,很少有其他的功能,而这些被赋值大部分是从全局数组、链表、寄存器中取出来,其他函数
        穿越一层层 把数据放入这些数组、链表上来,写到这儿,真心感觉到了内存就是一个大大的database
    */
    struct s3c2410_request  *req;
    /*
        源码中说是 :  SETUP data for a USB device control request
                    This structure is used to send control requests to a USB device
                神马鬼??
                里面有一个成员 bRequest,后面的函数会使用switch case 来判断这个bRequest,
                判断是什么传输类型,然后根据你是什么传输类型,干什么样的活把
                bRequest 的值来源于 端点0的FIFO
                s3c2410_udc_read_fifo_crq()
                {
                        unsigned char *outbuf = (unsigned char *)crq;
                        ....
                        bytes_read = s3c2410_udc_fifo_count_out();
                        ....
                        readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read);
                }
    */
    struct usb_ctrlrequest  crq;
    /*
        设备的每一个端点上聚集了很多usb_request ,这些usb_request都挂载在一个链表上,
        请参见上图2
    */
    if (list_empty(&ep->queue))
        req = NULL;
    else  //如果不为空,那么就取出来一个赋值给 req
        req = list_entry(ep->queue.next, struct s3c2410_request, queue);

    udc_write(0, S3C2410_UDC_INDEX_REG);
    /*
        读吧,吧端点0的状态给读取出来,看你是什么状态,就让你干什么活,别谈,都给你设计规划好了,你没有选择的余地
        我想知道在这寄存器背后的复杂电路是怎么被设计出来的???
    */
    ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG); 
    ....
    /*
        判断此刻端点0是处于哪种状态
        那么端点0是处于哪种状态呢?看它的值 dev->ep0state 
        我们知道,设备插入主机后,第一个执行的中断是复位操作,而不是枚举,对首先要复位设备,
        没有明白为什么要先复位设备,usb协议哪章规定了要先复位设备的??

        这段代码就是上面 复位的时候,我们暂时没有分析实现的
        看,if分支中的 dev->ep0state 被赋值为了 EP0_IDLE
        static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
        {
            ......
            ......
            if (usb_status & S3C2410_UDC_USBINT_RESET) //会首先执行这个if分支
            {
               ....
               dev->ep0state = EP0_IDLE;
               dev->gadget.speed = USB_SPEED_FULL;
               ....
            }
        }
    */
    switch (dev->ep0state) {
        /*
            由上面我们可以知道,这个case 是首先会被执行,
            而下面那个 获取描述符的case 是不会第一个被执行的,
            那么 s3c2410_udc_handle_ep0_idle这个函数就会被执行了,
            好,下面看一下这个函数
        */
        case EP0_IDLE:
            s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
            break;
        /*
            获取设备的描述符
        */  
        case EP0_IN_DATA_PHASE:         
            dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
            if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req)
                s3c2410_udc_write_fifo(ep, req);
            break;
        /*
            设置描述符
        */   
        case EP0_OUT_DATA_PHASE:        
            dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
            if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req)
                s3c2410_udc_read_fifo(ep, req);
            break;
        case EP0_END_XFER:
            ....
        case EP0_STALL:
            ....
        }
    }
}

简单的结构框图
这里写图片描述

端点数据流程
这里写图片描述

端点0
这里写图片描述

第16章 USB主机、设备与Gadget驱动之USB UDC与Gadget驱动(一) 16.4.1 UDC(USB设备控制器)和Gadget(小配件)驱动的关键数据结构与API    USB设备控制器(UDC)驱动指的是作为其他USB主机控制器外设的USB硬件设备上底层硬件控制器的驱动,该硬件和驱动负责将一个USB设备依附于一个USB主机控制器上。例如,当某运行Linux系统的手机作为PC的U盘时,手机中的底层USB控制器行使USB设备控制器的功能,这时运行在底层的是UDC驱动,手... 阅读详情

相关推荐

android usb gadget分析

Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c。这个文件实现USB的上层应用协议。 首先包含了一些系统级别的头文件,如模块、电源管理、of API等 #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #

viewsky11的专栏 6504

Linux: USB Gadget 驱动简介

Linux, USB Gadget

JiMoKuangXiangQu的专栏 1万+

Android/Linux USB Gadget:三层架构

1.前言 继Linux Gadget的一点研究后陆续续关注了很久Android USB Gadget,一直想写点什么记录一些认识,可是Linux USB实在是太复杂,让人有点无从下笔的感觉。它的复杂并不是说不可以被人理解,而且涉及的面很广。USB Host的驱动关注比较少,就对USB device驱动的认识来说,需从两大方面去对它进行认识和了解,一方面是USB协议本身,如果连USB端点、设备描述

wuyuwei45的专栏 5971

usb-gadget

内核支持usb 的配置nt9856 支持usb 的驱动 USB做dev的一般都在小东西里面CONFIG_USB_GADGET 小东西里面一般有三块 CONFIG_USB_CONFIGFS 这个一般是选着平台的usb控制器驱动 比如我想usb做设备当一个U盘用那么用这个config CONFIG_USB_CONFIGFS_MASS_STORAGE 下面这个就是一个工具让你挂载的目录配置这个驱动一挂载pc上就会出现一个U盘 insmod g_mass_storage.ko file=/dev/mtdbloc

weixin_41884251的博客 5378

Linux Android USB gadget(从设备驱动)

Linux usb 通讯使用

帅的没拼音 2456

CDC: 配置USB为Gadget serial device

Linux支持连接各种USB从设备,同时也支持自己作为设备插入到其他主机当中。最典型的例子就是Android OS的手机,插入电脑可以被识别为U盘之类的设备。 对于SOC来说,这部分直接对应了USB Device部分的操作。 为了避免与作为主机时支持的"设备驱动 (USB Device Driver)"一词混淆, Linux给这部分的实现取名为"Gadget" (小玩具)。内核源码的目录为\d

chrovery的专栏 8393

gadget之usb_gadget

gadget之usb_gadget 简介 略。 struct usb_gadget /** * struct usb_gadget - represents a usb slave device * @work: (internal use) Workqueue to be used for sysfs_notify() * @udc: struct usb_udc pointer for this gadget * @ops: Function pointers used to access ha

枫潇潇 2381

Linux usb【3】- gadget驱动介绍

在dwc3_gadget_init中主要就是调用dwc3_gadget_init_endpoints初始化ep, 并且申请了usb_gadget数据结构,并初始化里面的usb_gadget_ops回调函数, 然后调用usb_add_gadget。usb device设备对应的驱动是usb_gadget_driver ,这个驱动是在usb_gadget_probe_driver里面根据控制器名字绑定的,usb_gadget_probe_driver何时调用我们会在随后的文章中介绍。

liverdream的专栏 1062

开始写usb gadget驱动

usb主机端class驱动比较简单, 利用usb_register_driver, 向usb core子系统注册相应的class驱动即可。 主要填充usb_driver数据结构, 主要的包括id_table为设备-驱动匹配的依据(如pid, vid或class, protocol等), 其次就是probe, disconnect等回调函数, probe即匹配驱动后的探测函数, 需要做class...

River的专栏 1797

usb hid gadget调试

usb hid gadget调试 在调试hid gadget时,发现接收数据时多了一个数据头(struct usb_ctrlrequest),并且第一次接收不到数据,为了查找原因,看了一下内核代码,使用的是A20芯片。 gadget驱动,linux本身有框架可以看一下内核代码(drivers/usb/gadget)。usb接收过来的数据存放在struct usb_request结构中,发现此

wdsfup的专栏 6213

USB gadget configfs的原理及单片机实现

在单片机实现中,由于硬件资源的限制,不能像Linux内核那样使用configfs,而是需要手动设置各个寄存器的值来实现USB gadget从设备。然而,在某些情况下,我们可能需要一个自己定义的从设备,这时就需要使用USB gadget技术。在这里,我们使用 FFFF 作为我们自己的设备ID,这是一个保留值,表示自己定义的设备。最后,我们需要在USB模块中定义一些回调函数,用于处理USB设备的各种事件,如数据传输、控制命令等。然后,我们需要在USB模块中定义一些数据结构,用于描述各种USB设备的属性和功能。

qq_37934722的博客 889

USB Gadget 技术

USB Gadget 是 Linux 内核提供的一项技术,允许具备USB 设备控制器(USB Device Controller)的硬件(如嵌入式开发板、手机)模拟成各种 USB 设备(如 U 盘、串口、网卡、打印机等),从而与主机(如电脑)进行通信。简单来说,普通 USB 设备(如 U 盘)是“被动”被主机识别的,而 USB Gadget 让硬件能“主动”扮演不同的 USB 设备角色,实现灵活的 USB 通信功能。普通 USB 蓝牙适配器:是标准 USB 外设,依赖主机端驱动工作,

qq_45668408的博客 1886

linux usb gadget从机设备驱动示例程序

在linux gadget zero驱动的基础上实现了文件接口,阻塞读写,设备打开数量限制等功能,支持直接通过cat和echo的重定向机制操作此驱动,实现usb gadget驱动的读写,在linux3,3通过测试。 使用方法,将这些文件拷贝到内核源码目录driver/usb/gadget,在menuconfig中开启usb gadget的zero驱动编译,最好编译成模块,调试方便

linux usb Gadget (usb设备侧驱动分析)

Linux-USB Gadget 之简介  Linux-USB Gadget 驱动框架(以下简称 Gadget )实现了 USB 协议定义的设备端的软件功能。 相对于 Linux USB 主机端( Host ) 驱动而言, Gadget 驱动出现较晚,它出现在 2.4.23 以后。 Gadget 框架提出了一套标准 API, 在底层USB 设备控制器 (USB Device Contr

sun_x_t的专栏 3785

USB gadget设备驱动解析(3)

作者:刘洪涛,华清远见嵌入式学院讲师。   Linux USB 设备端驱动有两部分组成。一部分是USB 设备控制器(USB Device Controller, UDC)驱动、另一部分是硬件无关的功能驱动(如:鼠标、u盘、usb串口、usb网络等);也可以分为3层的,分别是:Controller Drivers、Gadget Drivers、Upper Layers,大概意思都差不多。   一、控制器(USB Device Controller, UDC)驱动   Gadget 框架提出了一套标准 API, 在底层, USB 设备控制器驱动则实现这一套 API, 不同的 UDC需要不同的

系统安装、qt配置、安装pcie驱动

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 安装Linux系统指定:ununtu20.04并配置相关软件环境 前言 提示:这里可以添加本文要记录的大概内容: ununtu20.04、Qt 5.9.0、pcie驱动 提示:以下是本篇文章正文内容,下面案例可供参考 一、安装系统 制作系统盘(win10),在开机时按相应键进入BIOS,(华硕需要先改配置启动->CSM->开启->第一个选项选第一个或第二个),等待即可 进入后按照https://www.sysgeek.

weixin_44832804的博客 2204

linux usb gadget

上一篇谈到了usb host以及usb core,这一篇来介绍下usb gadget,usb gadget较usb host出现较晚,随着linux越来越用作嵌入式设备而出现,是一套独立的架构,与usb core没有任何关系。 由上图可以看出gadget架构有两个核心抽象层,composite framework和udc core。 composite framewor

festival的专栏 3890

STM32 使用IO口模拟I2C时序

上一篇《I2C协议详解》 我们了解了I2C的操作流程,这一篇,我们就使用I2C,来对EEPROM进行操作吧。 我们做两种选择: 1.时序由IO口模拟高低电平,需要了解协议并按照协议操作相应的IO口。 2.时序由硬件自行产生,不需要人工干预; 由硬件产生的I2C时序,我们借助Stm32Cube配置实现便可,我们这一篇,抛开Stm32Cube,手撕代码,根据I2C的时序,一步步地实现I2C对...

8937

USB gadget 驱动之 android.c

weixin_42129680的博客 4456

别再只做游戏了!用虚幻引擎5(UE5)给你的工厂车间做个数字双胞胎(附数据对接教程)

本文详细介绍了如何利用虚幻引擎5(UE5)构建工业数字孪生系统,实现工厂车间的智能可视化。通过UE5的高质量渲染和实时数据处理能力,结合OPC UA和MQTT协议,打造高效的数据对接方案,提升异常识别和设备管理效率。文章还分享了模型优化、可视化设计及典型工业场景的实战案例,助力企业迈向工业4.0。

weixin_33738555的博客 206

ANSYS 2026 R1 Windows系统安装避坑指南:环境配置、模块部署与许可证实战

ANSYS作为主流CAE仿真平台,其安装部署已远超传统软件范畴,演变为涉及操作系统底层、GPU驱动兼容性、许可证微服务架构和统一缓存机制的系统工程。理解ANSYS安装原理,需从Windows 11 UEFI安全启动要求、DirectX 12 Ultimate图形栈依赖、gRPC架构的License Manager端口动态分配等核心机制切入;技术价值在于保障HFSS GPU加速、Fluent MPI并行稳定性及Workbench多模块协同可靠性;典型应用场景涵盖高校仿真实验室升级、工业设计院所平台重建及高性能

weixin_29251337的博客 1400

Linux下USB gadget设备详解

USB gadget是什么?Linux-USB Gadget 驱动框架(以下简称 Gadget)实现了USB 协议定义的设备端的软件功能。相对于 Linux USB 主机端(Host)驱动而言, Gadget 驱动出现较晚,它出现在2.4.23 以后。 Gadget 框架提出了一套标准 API, 在底层, USB 设备控制器(USB Device Controller, UDC)驱动则实现这

dream_server的专栏 1865

【数字IC设计】芯片设计中的RDC

在芯片设计中,RDC是的缩写,类似于CDC(clock domain crossing),由于现在SOC芯片是有很多ECUs组成,为了使整个系统能够快速从复位中恢复, 用户希望SOC里面每个ECU模块都可以有自己独立的异步复位信号,这样可以在出问题的时候只复位有错误逻辑的模块,而使其它模块保持正常工作。

qq_40268672的博客 2182
上一篇: tty driver 赏析
下一篇: Process scheduling - Linux Kernel 实现 欣赏
leesagacious
博客等级 码龄12年 146粉丝 179原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值