USB gadget 驱动之 android.c
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 configuration
和USB 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相关推荐
- linux usb gadget驱动详解(一)
由于PC的推广,USB(通用串行总线)是我们最熟知的通信总线规范之一,其他的还有诸如以太网.PCIE总线和RS232串口等.这里我们主要讨论USB. USB是一个主从通信架构,但只能一主多从.其中us ...
- linux usb gadget驱动详解(二)
在上篇<linux usb gadget驱动详解(一)>中,我们了解到gadget的测试方法,但在最后,我们留下一个问题,就是怎样使用新的方法进行usb gadget驱动测试. 我们发现l ...
- linux usb gadget驱动详解(三)
本文将对linux4.4.19版本usb gadget源码进行简单分析.鉴于前文反复测试U盘设备驱动,现从linux-4.4.19/drivers/usb/gadget/legacy/mass_sto ...
- linux usb gadget驱动详解(四)
现从msg_bind()函数(drivers/usb/gadget/legacy/mass_storage.c)开始讲起. U盘的gadget驱动比较复杂,因为它包含几部分,包括gadget驱动.U盘 ...
- linux usb gadget驱动详解(五)
现从fsg_bind()讲起. //不失一般性,删掉错误处理和configfs相关代码 static int fsg_bind(struct usb_configuration *c, struct ...
- 继续写usb gadget驱动(解决枚举失败问题)
上个小patch吧... 关于昨天的usb枚举失败(获取配置描述符失败) 简要描述下: 1. 我的gadget配置成了usb3.2版本, (设置成1.0, 2.0也遇到一些问题, 暂表不论) Pro ...
- android usb wifi驱动下载,android 平台USB wifi驱动移植及使用
一. Android平台Wifi的基本代码路径 1. Wpa_supplicant源码部分 external/wpa_supplicant_6/ 生成库libwpa_client.so ...
- Android 8.1 usb gadget configuration
Android 8.1 usb gadget configuration Android的usb gadget配置流程 开机过程中usb gadget配置 第一种:rc脚本 第二种:UsbDevice ...
- USB总线-Linux内核USB3.0设备控制器之dwc3 gadget驱动初始化过程分析(五)
1.概述 USB设备控制器(UDC)驱动的框图如下图所示,由三部分组成.第一部分是UDC驱动核心层,在drivers/usb/gadget/udc/core.c文件中实现,该层是一个兼容层,将USB ...
最新文章
- FAST:基于FPGA的SDN交换机开源项目
- 《JAVA练习题目4》 训练要点:String和StringTokenizer的使用,以及排序算法。
- mysql 业务账户_mysql的事务
- react-natvie-fetch-blob使用
- 用eclips连hadoop报Unknown protocol to job tracker: org.apache.hadoop.hdfs.protocol.ClientProtoco
- JVM中OutOFMemory和StackOverflowError异常代码
- Knozen:新型职场社交评论匿名应用,已获多家风投投资
- 【安全测试自学】初探web安全处测试(三)
- 就说现在的钱有多难挣
- java udp 流量控制_基于UDP传输协议的实现分析之流量和拥塞控制
- 引入方式之内部样式表(CSS、HTML)
- 路灯干扰者路过时,路灯熄灭的照片
- java核心技术.pdf
- 红蜘蛛多媒体网络教室v7.2版一款网络教学的软件_我是亲民_新浪博客
- imdisk虚拟光驱安装linux,使用imdisk虚拟光驱加载镜像文件操作方法
- 针对VMware安装Win10需要安装.NET Framework 3.5常见的0x800F0906、0x800F081F错误解决办法
- [2]十道算法题【Java实现】
- 手机网页版JS压缩上传图片--base64位 兼容IOS和安卓
- 看steam教育之风带来创新与变革
- 9.查找算法--二叉排序树