1. Gadget驱动

1.1 Gadget框架结构

kernel/drivers/usb/gadget,这个目录是android下usb gadget的主要目录。
(1)Gadget功能组织单元:主要文件android.c,usb gadget功能的统领文件,负责组织usb 复合设备的功能,与上层应用提供交互的接口,面向市场需求的产品规划部门。

(2)复合设备逻辑处理单元(复合设备管理单元):composite.c,这个文件类似于一个项目管理组,负责各个单元的接口对接,资源整理。针对拥有多个usb功能的复合设备,这部分负责将支持的各个功能组织到一起,协助各个功能与UDC控制器单元建立联系。

流程:android.c init-- usb_composite_probe--usb_gadget_probe_driver---composite_bind---
composite_gadget_bind(android_bind)

(3)具体功能单元:以U盘为例,f_mass_storge.c文件,用来完成具体的功能。这个部分是一个功能性很强的部分,将与UDC控制器单元直接对话,完成数据的传输。

(4)UDC控制器单元:只做一件事情,收发usb数据,将数据透明的传递出去。

1.2 android.c

Android USB驱动中,上层应用协议里最重要的一个文件是android/kernel/drivers/usb/gadget/android.c。这个文件实现USB的上层应用协议。
在我们USB配置文件(system/core/usb/compositions/)中,直接往驱动在上层的接口中写值。

run_9607() {if [ $from_adb = "n" ]thenpkill adbdfiecho 0 > /sys/class/android_usb/android$num/enableecho 8241 > /sys/class/android_usb/android$num/idProductecho 2949 > /sys/class/android_usb/android$num/idVendorecho diag > /sys/class/android_usb/android$num/f_diag/clientsecho smd,tty,tty > /sys/class/android_usb/android$num/f_serial/transportsecho rndis,serial,diag > /sys/class/android_usb/android$num/functions echo 1 > /sys/class/android_usb/android$num/remote_wakeupecho 1 > /sys/class/android_usb/android$num/f_rndis_qc/wceissleep $delayecho 1 > /sys/class/android_usb/android$num/enableif [ $from_adb = "n" ]then/etc/init.d/adbd startfi
}

在上层*/sys/class/android_usb/android0*中可以看到如下接口:

1.2.1 android.c 功能代码解析

kernel/drivers/usb/gadget/android.c
(1)会调用到具体的function驱动,如下将调用f_serial.c

gserial_init_port()  gport_setup()



(2)android_init_functions()函数中会为function创建一个名为 f_xxx的sys class,比如说这里用到的是adb的function,那么名字就为 f_adb。因此可以在*/sys/class/android_usb/android0/看到f_adb*的目录。

(3)跳转执行adb驱动f_fs.c

(4)在android_bind()初始化USB设备描述符并分配string ID.

(5)添加functions到list中
这一步需要用户手动配置,因为我们是使用adb的功能,因此需要输入以下命令:

#echo adb > /sys/class/android_usb/android0/functions

对应的驱动接口是 functions_store()函数,这个函数的内容是先解析传进来的字符串,然后调用android_enable_function(),根据解析出来的字符串是否与之前 android_init_functions()中设定的名字(也就是该驱动现在支持哪些function)是否有相匹配的,如果有,那么就将名字添加到enabled_list中。

(6)使能androidadb

#echo 1 > /sys/class/android_usb/android0/enable

对应的驱动接口是enable_store(),在这个函数里面会去完善USB设备描述符,然后从enabled_list中找出与之对应的struct android_usb_function,并执行它的.enable()成员函数,这里当然是会去执行adb_android_function_enable()函数。注意,在adb_android_function_enable()函数中会去先执行一次android_disable()。执行完这一步还没绑定USB configuration和USB function。

(7)启动adbd进程
启动adbd进程,那么首先会去调用adb_open(),最终会调用usb_add_config()adb_bind_config()函数将USB configurationUSB function绑定起来。此时,这个USB设备已经配置完整了,可以接受USB Host的枚举。
f_fs.c

1.3 f_serial

在较新的版本中,通过USB gadget驱动程序与SMD层进行交互。这为QTI的设计提供了另一个变化,它引入了u_smd 驱动程序。

初始化流程与以前的实现类似。

1.3.1 gport_setup

SMD端口是在gport_setup()调用gsmd_setup()时分配的。

(1)gport_setup():两个tty_ports(NMEA和AT口)

[   22.709616] water_usb: line = 342, gport_setup
[   22.723022] water_usb: line = 342, gport_setup

(2)gsmd_setup():一个smd_ports(modem口)

[   22.735678] water_usb: line = 998, gsmd_setup


注意:此处调用platform_driver_register()注册gsmd驱动,并执行其probe函数gsmd_ch_probe

1.3.2 gser_alloc

(1)三个serial端口调用三次函数去分配端口,当前只支持三个端口:

端口0——modem口
端口1——NMEA口
端口2——modem2(因该是指AT口)


(2)gser_bind()

(3)gser_set_alt()

f_serial驱动程序从主机接收到SET_INTERFACE数据包后,将调用gport_connect(),它将根据所选内容打开传输。在本例中,它调用gsmd_connect()

gsmd_connect()然后负责使能USB端点和局部变量,并延时去打开SMD通道,打开SMD通道的函数是gsmd_connect_work()
smd_port

tty_port

(4)gsmd_connect和gser_connect
一个smd port:

[   23.431556] water_usb: line = 603, gsmd_connect_work

两个tty port:

[   23.526257] gs_open: start ttyGS1
[   23.529155] water_usb: line = 816, gser_connect
[   23.533056] gs_open: ttyGS1 (cb24a400,cb15ca80)
[   23.537564] water_usb: gs_open: ttyGS1 (cb24a400,cb15ca80)
[   23.545823] gs_open: start ttyGS0
[   23.548703] water_usb: line = 816, gser_connect
[   23.552618] gs_open: ttyGS0 (cb24a000,cb15c600)
[   23.557133] water_usb: gs_open: ttyGS0 (cb24a000,cb15c600)

2、Host:usb_serial 驱动

2.1 bus.c

(1)在usb.c中的usb_init()函数会调用bus_register(&usb_bus_type)注册一条USB总线。
(2)在usb.c中会在这条总线上注册一个驱动程序:

usb_generic_driver{generic_probe()device_id
}

在这个驱动中包含自己的probe函数和USB设备ID(注意,这里是设备ID而不是接口的ID)。

2.2 usb_serial.c

2.2.1 入口函数

module_init(usb_serial_init);

2.2.2 usb_serial_init()

1)按照 tty 驱动结构,先创建 tty_driver对象

usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);

2)注册USB转串口总线。会出现在:/sys/bus/usb-serial,其下挂载的驱动(/sys/bus/usb-serial/drivers)包括:generic、option1、sprd_u2s等。

result = bus_register(&usb_serial_bus_type);

3)向内核注册tty类USB转串口驱动,并在USB转串口总线上添加这个驱动

tty_register_driver(usb_serial_tty_driver);

4)向内核注册USB转串口驱动,该驱动挂载在USB总线下:

usb_register(&usb_serial_driver);/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {.name =     "usbserial",.probe =     usb_serial_probe,.disconnect = usb_serial_disconnect,.suspend =   usb_serial_suspend,.resume =   usb_serial_resume,.no_dynamic_id =     1,
};

5)向内核注册通用的USB转串口驱动。

usb_serial_generic_register(debug);

2.2.3 usb_serial_probe()

int usb_serial_probe(struct usb_interface *interface,const struct usb_device_id *id)
{. . ./* register all of the individual ports with the driver core */for (i = 0; i < num_ports; ++i) {port = serial->port[i];dev_set_name(&port->dev, "ttyUSB%d", port->number);dbg ("%s - registering %s", __func__, dev_name(&port->dev));port->dev_state = PORT_REGISTERING;device_enable_async_suspend(&port->dev);retval = device_add(&port->dev);if (retval) {dev_err(&port->dev, "Error registering port device, ""continuing\n");port->dev_state = PORT_UNREGISTERED;} else {port->dev_state = PORT_REGISTERED;}}. . .
}

2.3 option.c

该驱动挂载在usb-serial总线下,实现USB接口(端口),添加PID、VID在此文件中实现。
(1)option.c中的option_init()函数调用:

static struct usb_serial_driver option_1port_device = {.driver = {.owner =    THIS_MODULE,.name =        "option1",},.description       = "GSM modem (1-port)",.id_table          = option_ids,.num_ports         = 1,.probe             = option_probe,......
};static struct usb_serial_driver * const serial_drivers[] = {&option_1port_device, NULL
};module_usb_serial_driver(serial_drivers, option_ids);

(2)option.c在USB转串口总线上注册驱动option_1port_device(注意,这仅仅是在总线上注册,并不向内核注册)。

module_usb_serial_driver(serial_drivers, option_ids);

到这里,总线和驱动都已经注册完毕了,就等着设备过来了

2.4 generic.c

驱动generic挂载在usb-serial总线下。

static struct usb_serial_driver usb_serial_generic_device = {.driver = {.owner =  THIS_MODULE,.name =        "generic",},.id_table =      generic_device_ids,.probe =        usb_serial_generic_probe,.calc_num_ports = usb_serial_generic_calc_num_ports,.throttle =      usb_serial_generic_throttle,.unthrottle =      usb_serial_generic_unthrottle,.resume =        usb_serial_generic_resume,
};

注册 generic_driver 驱动主要是为了注册一个 generic_probe 函数,而该
函数将会在设备连上系统后被调用以来匹配设备。除此之外该驱动没什么用,而在这个初始化函数中把 vendor,product 都保存在了 generic_device_ids 里, 因此可以肯定以后的匹配将用这个设备列表.

2.5 设备

2.5.1 从设备插入到进入自己的probe函数——usb_serial_probe()的过程

(1)当我们的USB Modem设备插入USB端口时,要调用bus_add_device()在USB总线上添加一个USB设备。

(2)该USB设备由于有USB设备号,会找到刚才注册的usb_generic_driver()中的generic_probe()函数,在这个函数中经过一系列的函数调用最后会进入usb_set_configuration()

(3)usb_set_configuration()函数会根据HOST和Device沟通的情况,进行总线枚举,这个我们的设备会生成3个interface,该函数会依次将这三个interface添加到USB总线上。

(4)每个interface会根据VID和PID找到合适自己的probe函数,设备的三个接口会依次进入usb_serial_probe()

2.5.2 从进入自己的probe到虚拟出ttyUSB设备

(1)在usb_serial_probe()中,首先生成三个usb_serial_port,port1,port2,port3。接着调用device_add()函数——调用tty_register_device()-调用device_create()

(2)tty_register_device()函数主要做了三件事:
1)向系统注册这三个串口设备。
2)将串口设备,次设备号,串口驱动usb_serial_tty_driver绑定到一起。
3)在/dev目录下生成/dev/ttyUSB1,/dev/ttyUSB2,/dev/ttyUSB3三个设备。

2.6 总线

(1)挂载在usb-serial总线下的drivers(/sys/bus/usb-serial/drivers)有:generic、option1、sprd_u2s(展讯驱动)等;

(2)挂载在usb-serial总线下的devices(/sys/bus/usb-serial/devices)有:ttyUSB0、ttyUSB1、ttyUSB2等;

(3)挂载在usb总线下的drivers(/sys/bus/usb/drivers)有:cdc_ether、usbserial、sprd_u2s、option等。

2.7 设备描述符

设备——配置——接口——端点

/sys/bus/usb/devices/
2-1:1.0
根集线器-集线器端口号(-集线器端口号...):配置.接口

USB gadget 驱动之 android.c相关推荐

  1. linux usb gadget驱动详解(一)

    由于PC的推广,USB(通用串行总线)是我们最熟知的通信总线规范之一,其他的还有诸如以太网.PCIE总线和RS232串口等.这里我们主要讨论USB. USB是一个主从通信架构,但只能一主多从.其中us ...

  2. linux usb gadget驱动详解(二)

    在上篇<linux usb gadget驱动详解(一)>中,我们了解到gadget的测试方法,但在最后,我们留下一个问题,就是怎样使用新的方法进行usb gadget驱动测试. 我们发现l ...

  3. linux usb gadget驱动详解(三)

    本文将对linux4.4.19版本usb gadget源码进行简单分析.鉴于前文反复测试U盘设备驱动,现从linux-4.4.19/drivers/usb/gadget/legacy/mass_sto ...

  4. linux usb gadget驱动详解(四)

    现从msg_bind()函数(drivers/usb/gadget/legacy/mass_storage.c)开始讲起. U盘的gadget驱动比较复杂,因为它包含几部分,包括gadget驱动.U盘 ...

  5. linux usb gadget驱动详解(五)

    现从fsg_bind()讲起. //不失一般性,删掉错误处理和configfs相关代码 static int fsg_bind(struct usb_configuration *c, struct ...

  6. 继续写usb gadget驱动(解决枚举失败问题)

    上个小patch吧... 关于昨天的usb枚举失败(获取配置描述符失败) 简要描述下: 1. 我的gadget配置成了usb3.2版本,  (设置成1.0, 2.0也遇到一些问题, 暂表不论) Pro ...

  7. android usb wifi驱动下载,android 平台USB wifi驱动移植及使用

    一.   Android平台Wifi的基本代码路径 1.       Wpa_supplicant源码部分 external/wpa_supplicant_6/ 生成库libwpa_client.so ...

  8. Android 8.1 usb gadget configuration

    Android 8.1 usb gadget configuration Android的usb gadget配置流程 开机过程中usb gadget配置 第一种:rc脚本 第二种:UsbDevice ...

  9. USB总线-Linux内核USB3.0设备控制器之dwc3 gadget驱动初始化过程分析(五)

    1.概述 USB设备控制器(UDC)驱动的框图如下图所示,由三部分组成.第一部分是UDC驱动核心层,在drivers/usb/gadget/udc/core.c文件中实现,该层是一个兼容层,将USB ...

最新文章

  1. FAST:基于FPGA的SDN交换机开源项目
  2. 《JAVA练习题目4》 训练要点:String和StringTokenizer的使用,以及排序算法。
  3. mysql 业务账户_mysql的事务
  4. react-natvie-fetch-blob使用
  5. 用eclips连hadoop报Unknown protocol to job tracker: org.apache.hadoop.hdfs.protocol.ClientProtoco
  6. JVM中OutOFMemory和StackOverflowError异常代码
  7. Knozen:新型职场社交评论匿名应用,已获多家风投投资
  8. 【安全测试自学】初探web安全处测试(三)
  9. 就说现在的钱有多难挣
  10. java udp 流量控制_基于UDP传输协议的实现分析之流量和拥塞控制
  11. 引入方式之内部样式表(CSS、HTML)
  12. 路灯干扰者路过时,路灯熄灭的照片
  13. java核心技术.pdf
  14. 红蜘蛛多媒体网络教室v7.2版一款网络教学的软件_我是亲民_新浪博客
  15. imdisk虚拟光驱安装linux,使用imdisk虚拟光驱加载镜像文件操作方法
  16. 针对VMware安装Win10需要安装.NET Framework 3.5常见的0x800F0906、0x800F081F错误解决办法
  17. [2]十道算法题【Java实现】
  18. 手机网页版JS压缩上传图片--base64位 兼容IOS和安卓
  19. 看steam教育之风带来创新与变革
  20. 9.查找算法--二叉排序树

热门文章

  1. SpinalHDL资料汇总
  2. 2019 年最好用的 6 款数据库监控工具
  3. zz迅雷7无法自动登录解决办法
  4. 面试智力题-脑筋急转弯
  5. Matlab中legend()函数的用法:实现标注的显示及隐藏
  6. UVA10499 The Land of Justice 的题解
  7. css3 实现盒子四周光晕_CSS3给超链接增加阴影和光晕效果
  8. 计算文件CRC32数值
  9. 虚拟机安装Linux系统(保姆级教程)
  10. GUN Radio安装