USB CDC简介

USB CDC类、USB2.0标准与PSTN之间的关系
CDC(Communication Device Class)类是USB2.0标准下的一个子类,定义了通信相关设备的抽象集合。它与USB2.0标准以及其下的子类的相互关系如下图所示:

如上图,USB2.0标准下定义了很多子类,有音频类,CDC类,HID,打印,大容量存储类,HUB,智能卡等等,这些在urb.org官网上有具体的定义,这里我们主要讲的是通信类CDC,CDC类下面,根据具体的应用场合,又有一些子类,这里我们主要讲的是PSTN(Public Switched Telephone Network)。从PSTN官方标准文档来看,PSTN子类是一个与电信相关的子类,而这里,我们只是将它作为一个普通的通信设备使用,并没有使用到它的一些电话特性。

从一个具体的CDC类通信数据说起

如上图,USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的,这也就是为什么上图中,在操作虚拟串口之前会有两条数据通信的数据。

之所以会有虚拟串口操作,主要是我们通常使用PC作为host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口。这样以来,可以方便PC端软件通过操作串口的方式来与其进行通信。但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB的操作等。这里需要注意的是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率,驱动访问USB外设有效速率以及外部环境对通信本身造成的干扰率等因素。

CDC类设备枚举过程

CDC类设备与其他标准USB设备枚举过程并没有什么特殊的地方,在描述符内可以使用DeviceClass=0x00, SubClass=0x00, Protocol=0x00 表示此类信息在接口描述符内给出;或者也可以使用0x02,0x00,0x00 来表明该设备为CDC类设备。或者使用0xef, 0x02,0x01表示当前为复合设备。

 CDC类设备在枚举过程中最主要的信息存储在配置描述符内:

如上图所示,CDC类的配置描述符一般包含两个接口(interface0)为控制接口,另外一个是Interface1为数据接口,除此之外,还有一个虚线指向IAD(Interface Association Description)这个是可选的,得根据实际情况来确定其是否真实存在。

控制接口

控制接口侠包含一个类描述符和一个端口(ie:0x82),这个端点(中断传输模式)为异步通知消息的端点,当设备需要向Host端发送异步消息时,可以通过此端点来发送,但平时主机端都是通过端点0来向设备端发送控制消息的,比如哪些虚拟串口的操作指令等。

CDC-ACM

CDC ACM驱动实现以USB设备驱动和tty设备驱动为基础,可将USB设备驱动的实现看作tty驱动和硬件之间数据流转换的桥梁,即整个USB CDC协议的实现均体现在USB部分,USB设备的描述符定义、CD虚拟串口的设定、线路状态设置与读取、串口数据的发送与读取均遵循CDC协议规范。

驱动路径:/drivers/usb/class/cdc-acm.c

注册USB设备驱动&tty设备驱动

/*
 * Init / exit.
 */
 
static int __init acm_init(void)
{
	int retval;
	acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
	if (!acm_tty_driver)
		return -ENOMEM;
	acm_tty_driver->driver_name = "acm",
	acm_tty_driver->name = "ttyACM",
	acm_tty_driver->major = ACM_TTY_MAJOR,
	acm_tty_driver->minor_start = 0,
	acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
	acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
	acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	acm_tty_driver->init_termios = tty_std_termios;
	acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD |
								HUPCL | CLOCAL;
	tty_set_operations(acm_tty_driver, &acm_ops);
 
	retval = tty_register_driver(acm_tty_driver);
	if (retval) {
		put_tty_driver(acm_tty_driver);
		return retval;
	}
 
	retval = usb_register(&acm_driver);
	if (retval) {
		tty_unregister_driver(acm_tty_driver);
		put_tty_driver(acm_tty_driver);
		return retval;
	}
 
	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
 
	return 0;
}

实现USB设备操作 

static struct usb_driver acm_driver = {
	.name =		"cdc_acm",
	.probe =	acm_probe,
	.disconnect =	acm_disconnect,
#ifdef CONFIG_PM
	.suspend =	acm_suspend,
	.resume =	acm_resume,
	.reset_resume =	acm_reset_resume,
#endif
	.pre_reset =	acm_pre_reset,
	.id_table =	acm_ids,
#ifdef CONFIG_PM
	.supports_autosuspend = 1,
#endif
	.disable_hub_initiated_lpm = 1,
};

实现TTY设备操作集

/*
 * TTY driver structures.
 */
 
static const struct tty_operations acm_ops = {
	.install =			acm_tty_install,
	.open =				acm_tty_open,
	.close =			acm_tty_close,
	.cleanup =			acm_tty_cleanup,
	.hangup =			acm_tty_hangup,
	.write =			acm_tty_write,
	.write_room =		acm_tty_write_room,
	.ioctl =			acm_tty_ioctl,
	.throttle =			acm_tty_throttle,
	.unthrottle =		acm_tty_unthrottle,
	.chars_in_buffer =	acm_tty_chars_in_buffer,
	.break_ctl =		acm_tty_break_ctl,
	.set_termios =		acm_tty_set_termios,
	.tiocmget =			acm_tty_tiocmget,
	.tiocmset =			acm_tty_tiocmset,
	.get_serial =		get_serial_info,
	.set_serial =		set_serial_info,
	.get_icount =		acm_tty_get_icount,
};

完成USB数据到tty数据流的转换

tty数据发送,相当于将串口数据需要转换为USB数据,再经由USB设备驱动传递给CDC串口硬件。

tty数据接收,相当于硬件接受的数据先经过USB传递给USB设备驱动,在USB数据接收处理中将串口数据传递给TTY驱动程序。

其他总线,如SPI转串口,I2C转串口,蓝牙转串口等,与此同理。

实例分析

以USB转串口芯片CH342为例,介绍USB串口设备在Linux系统中识别过程。

可直接通过lsusb命令查看系统下所有USB设备

通过lsusb -v查看详细信息。通过dmesg内核消息查看设备连接信息及驱动匹配情况。

可以修改内核消息等级查看更多驱动log。Linux支持不同等级的日志输出,可在驱动代码中添加调试信息。系统的日志等级可以通过:/proc/sys/kernel/printk进行设定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李小白20200202

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值