USB驱动之四虚拟串口

usb的从模式可以让手机当成一个device,如adb,mtp,midi等,对应的usb控制器是udc,使用usb
虚拟串口来学习下。

kernel4.4/drivers/usb/gadget/legacy/Makefile
-obj-$(CONFIG_USB_G_SERIAL)     += g_serial.o
+obj-y                          += g_serial.o
kernel4.4/drivers/usb/gadget/legacy/serial.c
-static bool use_acm = true;
+static bool use_acm = false;
kernel4.4/drivers/usb/gadget/function/f_serial.c
-dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
+dev_err(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",

按上述修改后,烧写boot.img进手机,开机。

串口中有如下打印

g_serial gadget: generic ttyGS0: dual speed IN/ep1in OUT/ep1out

说明手机端生成的串口节点是/dev/ttyGS0

通过usb线连接电脑,adb无法正常连接手机,lsusb会多出如下的usb设备

Bus 001 Device 101: ID 0525:a4a6 Netchip Technology, Inc. Linux-USB Serial Gadget

参考kernel4.4/Documentation/usb/gadget_serial.txt,生成电脑端的串口设备/dev/ttyUSB1(ttyUSB0已连接手机的串口)

Installing the Linux Host Generic USB Serial Driver
---------------------------------------------------
To use the Linux generic USB serial driver you must configure the
Linux host side kernel for "Support for Host-side USB", for "USB
Serial Converter support", and for the "USB Generic Serial Driver".

Once the gadget serial driver is loaded and the USB device connected
to the Linux host with a USB cable, the host system should recognize
the gadget serial device.  For example, the command

  cat /proc/bus/usb/devices

should show something like this:

T:  Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#=  6 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=0525 ProdID=a4a6 Rev= 2.01
S:  Manufacturer=Linux 2.6.8.1 with net2280
S:  Product=Gadget Serial
S:  SerialNumber=0
C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr=  2mA
I:  If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms

You must load the usbserial driver and explicitly set its parameters
to configure it to recognize the gadget serial device, like this:

  echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id

The legacy way is to use module parameters:

  modprobe usbserial vendor=0x0525 product=0xA4A6

If everything is working, usbserial will print a message in the
system log saying something like "Gadget Serial converter now
attached to ttyUSB0".

运行命令

echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id(usb-serial目录在连接了usb转串口模块才生成,就是说该驱动默认没加载)
modprobe usbserial vendor=0x0525 product=0xA4A6

此时在手机端有节点/dev/ttyGS0,电脑端有节点/dev/ttyUSB1,可以向一个节点写数据,另一个节点收数据,如

cat /dev/ttyUSB1
echo "888888">/dev/ttyGS0(由于此时adb已不可用,可以在手机调试串口中输入)

可以看到数据是可以正常连通的,如

console:/dev # echo 88888888888 > ttyGS0  //手机调试串口
root@G480:/dev# cat ttyUSB1//电脑端
88888888888

开始时是想通过模块进行加载驱动的,运行时报如下错误

obj-m                          += g_serial.o
insmod g_serial.ko                                        
insmod: failed to load g_serial.ko: No such device

追踪代码到kernel4.4/drivers/usb/gadget/udc/udc-core.c

int usb_gadget_probe_driver(struct usb_gadget_driver *driver)
{
	struct usb_udc		*udc = NULL;
	int			ret;
	pr_err("usb_gadget_probe_driver\n");
	if (!driver || !driver->bind || !driver->setup)
		return -EINVAL;
	pr_err("usb_gadget_probe_driver1111\n");
	mutex_lock(&udc_lock);
	list_for_each_entry(udc, &udc_list, list) {
		/* For now we take the first one */
		if (!udc->driver)
			goto found;
	}
	
	pr_debug("couldn't find an available UDC\n");
	mutex_unlock(&udc_lock);
	return -ENODEV;
found:
	pr_err("udc_bind_to_driver\n");
	ret = udc_bind_to_driver(udc, driver);
	mutex_unlock(&udc_lock);
	return ret;
}

报错couldn't find an available UDC,也就是udc->driver不为空,再看udc->driver赋值的地方udc_bind_to_driver加上WARN_ON(1)查看调用关系,如下

[   58.867118] init: processing action (sys.usb.config=ptp,adb && sys.usb.configfs=1 && sys.usb.ffs.ready=1) from (/init.usb.configfs.rc:56)
[   58.870092] udc musb-hdrc.0.auto: registering UDC driver [g1]
[   58.880315] [<ffffff80086d0d78>] udc_bind_to_driver+0x3c/0x124
[   58.880332] [<ffffff80086d0ef0>] usb_udc_attach_driver+0x90/0xc8
[   58.880348] [<ffffff80086cf39c>] gadget_dev_desc_UDC_store+0xd0/0x12c
[   58.880366] [<ffffff80082aad38>] configfs_write_file+0xdc/0x154
[   58.880383] [<ffffff80082143f4>] vfs_write+0xb4/0x1f0
[   58.880399] [<ffffff8008214ea8>] SyS_write+0x60/0xc0
[   58.880419] [<ffffff8008085af0>] el0_svc_naked+0x24/0x

就是根据/root/init.usb.configfs.rc的配置,进行了相应的配置,导致无法安装g_serial.ko,应该也有相应的解绑方法,这里不深究,可以先采用将驱动编译到内核的方案,由于g_serial跑的比较早,相应的驱动也跑成功了。

本文涉及到的主要文件

kernel4.4/drivers/usb/gadget/legacy/serial.c

kernel4.4/drivers/usb/gadget/composite.c

kernel4.4/drivers/usb/gadget/function/f_serial.c

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值