Linux CDC ACM驱动介绍

一、实现原理

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

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 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驱动第三节的tty数据发送,相当于将串口数据需要转换为USB数据,再经由USB设备驱动传递给CDC串口硬件。

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

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

三、实例分析

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

 

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

可以其后加“-v”查看更多设备信息。

通过dmesg内核消息查看设备连接信息及驱动匹配情况

可以修改内核消息等级查看更多驱动log日志。

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

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PC技术小能手

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

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

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

打赏作者

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

抵扣说明:

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

余额充值