Linux串口驱动(1) - serial层_linux serial-程序员宅基地

技术标签: # tty  driver  linux  uart  

1. serial 层的初始化

        以IMX6的串口驱动为例,文件在drivers/tty/serial/imx.c,初始化概述如下:

module_init(imx_serial_init)
    -->uart_register_driver(&imx_reg);
		-->tty_set_operations(normal, &uart_ops);
			-->driver->ops = op;
		-->tty_register_driver(normal);
			-->dev = MKDEV(driver->major, driver->minor_start); 
			-->error = register_chrdev_region(dev, driver->num, driver->name);     //注册字符设备ttymxc0~4
			-->tty_cdev_add(driver, dev, 0, driver->num);
				-->cdev_init(&driver->cdevs[index], &tty_fops);					      
					-->cdev->ops = fops;		//将我们定义好的file_operaionts与cdev关联起来
	-->platform_driver_register(&serial_imx_driver);
		-->driver_register(&drv->driver);

2. 具体代码分析

        初始化过程中注册和关联的五个重要结构体

#define DEV_NAME                "ttymxc"
static struct uart_driver imx_reg = {
	.owner          = THIS_MODULE,
	.driver_name    = DRIVER_NAME,
	.dev_name       = DEV_NAME,				//ttymxc
	.major          = SERIAL_IMX_MAJOR,
	.minor          = MINOR_START,
	.nr             = ARRAY_SIZE(imx_ports),
	.cons           = IMX_CONSOLE,
};

static struct uart_ops imx_pops = {
	.tx_empty	= imx_tx_empty,
	.set_mctrl	= imx_set_mctrl,
	.get_mctrl	= imx_get_mctrl,
	.stop_tx	= imx_stop_tx,
	.start_tx	= imx_start_tx,
	.stop_rx	= imx_stop_rx,
	.enable_ms	= imx_enable_ms,
	.break_ctl	= imx_break_ctl,
	.startup	= imx_startup,
	.shutdown	= imx_shutdown,
	.flush_buffer	= imx_flush_buffer,
	.set_termios	= imx_set_termios,
	.type		= imx_type,
	.config_port	= imx_config_port,
	.verify_port	= imx_verify_port,
#if defined(CONFIG_CONSOLE_POLL)
	.poll_get_char  = imx_poll_get_char,
	.poll_put_char  = imx_poll_put_char,
#endif
};

static struct platform_driver serial_imx_driver = {
	.probe		= serial_imx_probe,
	.remove		= serial_imx_remove,

	.suspend	= serial_imx_suspend,
	.resume		= serial_imx_resume,
	.id_table	= imx_uart_devtype,
	.driver		= {
		.name	= "imx-uart",
		.owner	= THIS_MODULE,
		.of_match_table = imx_uart_dt_ids,
	},
};

static const struct tty_operations uart_ops = {
	.open		= uart_open,
	.close		= uart_close,
	.write		= uart_write,
	.put_char	= uart_put_char,
	.flush_chars	= uart_flush_chars,
	.write_room	= uart_write_room,
	.chars_in_buffer= uart_chars_in_buffer,
	.flush_buffer	= uart_flush_buffer,
	.ioctl		= uart_ioctl,
	.throttle	= uart_throttle,
	.unthrottle	= uart_unthrottle,
	.send_xchar	= uart_send_xchar,
	.set_termios	= uart_set_termios,
	.set_ldisc	= uart_set_ldisc,
	.stop		= uart_stop,
	.start		= uart_start,
	.hangup		= uart_hangup,
	.break_ctl	= uart_break_ctl,
	.wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
	.proc_fops	= &uart_proc_fops,
#endif
	.tiocmget	= uart_tiocmget,
	.tiocmset	= uart_tiocmset,
	.get_icount	= uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
	.poll_init	= uart_poll_init,
	.poll_get_char	= uart_poll_get_char,
	.poll_put_char	= uart_poll_put_char,
#endif
};

static const struct file_operations tty_fops = {
	.llseek		= no_llseek,
	.read		= tty_read,
	.write		= tty_write,
	.poll		= tty_poll,
	.unlocked_ioctl	= tty_ioctl,
	.compat_ioctl	= tty_compat_ioctl,
	.open		= tty_open,
	.release	= tty_release,
	.fasync		= tty_fasync,
};

        驱动入口函数

static int __init imx_serial_init(void)
{
	ret = uart_register_driver(&imx_reg);  //1.关键结构体的注册
	ret = platform_driver_register(&serial_imx_driver);  //2.关键结构体的注册
     ······
	return ret;
}
module_init(imx_serial_init);

        注册串口驱动 imx_reg

//serial_core.c
int uart_register_driver(struct uart_driver *drv)
{
    struct tty_driver *normal;
	normal = alloc_tty_driver(drv->nr);
	drv->tty_driver = normal;
    //drv是传进来的imx_reg
	normal->driver_name	= drv->driver_name;   //即imx_reg->driver_name
	normal->name		= drv->dev_name;      //即imx_reg->dev_name
	normal->major		= drv->major;         //即imx_reg->major
	normal->minor_start	= drv->minor;
	normal->type		= TTY_DRIVER_TYPE_SERIAL;
	normal->subtype		= SERIAL_TYPE_NORMAL;
	normal->init_termios	= tty_std_termios;
	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;	/*配置串口默认的波特率、流控等设置*/	
	normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
	normal->driver_state    = drv;
	tty_set_operations(normal, &uart_ops);     //3.关键结构体的赋值,设置normal->ops = uart_ops
    ······
	retval = tty_register_driver(normal);
}

//tty_io.c
int tty_register_driver(struct tty_driver *driver)
{
	if (!driver->major) //imx_reg->major有设置,所以这里不成立
     ······
   else {
		dev = MKDEV(driver->major, driver->minor_start);
		error = register_chrdev_region(dev, driver->num, driver->name);  //注册字符设备ttymxc0~4
	}

	if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) 
		error = tty_cdev_add(driver, dev, 0, driver->num);

	list_add(&driver->tty_drivers, &tty_drivers);  //将tty_driver(即传进来的normal)添加到全局链表tty_drivers

	if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
		for (i = 0; i < driver->num; i++) 
			d = tty_register_device(driver, i, NULL);   //暂时没分析到
	}
	proc_tty_register_driver(driver);
	driver->flags |= TTY_DRIVER_INSTALLED;
	return 0;
}

static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
		unsigned int index, unsigned int count)
{
	cdev_init(&driver->cdevs[index], &tty_fops);  //4. 关键结构体的赋值,将tty_fops和字符设备cdev联系起来,注意tty_fops是file_operaionts类型哦,操作字符设备的接口集
	driver->cdevs[index].owner = driver->owner;
	return cdev_add(&driver->cdevs[index], dev, count);
}

//char_dev.c
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
	memset(cdev, 0, sizeof *cdev);
	INIT_LIST_HEAD(&cdev->list);
	kobject_init(&cdev->kobj, &ktype_cdev_default);
	cdev->ops = fops;   //关键操作
}

        注册平台驱动 serial_imx_driver

int platform_driver_register(struct platform_driver *drv)
{
	drv->driver.bus = &platform_bus_type;
	if (drv->probe)
		drv->driver.probe = platform_drv_probe;
	if (drv->remove)
		drv->driver.remove = platform_drv_remove;
	if (drv->shutdown)
		drv->driver.shutdown = platform_drv_shutdown;

	return driver_register(&drv->driver);
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_41076734/article/details/118149235

智能推荐

【jeecg-boot】jeecg-boot的一些功能扩展:-程序员宅基地

文章浏览阅读2k次。【jeecg-boot】jeecg-boot的一些功能扩展:_jeecg-boot

gitlab上克隆远程分支到本地(报错-error: RPC failed; curl 18 transfer closed with outstanding read data remaining)_gitlab 18: transfer closed with outstanding read d-程序员宅基地

文章浏览阅读2.7k次。首先确保你的电脑有安装git环境,本人使用的是windows下的git环境。双击桌面图标 的Git Bash 打开窗口修改配置git config --global user.namegit config --global user.email如:git config --global user.name "muzidigbig"git config --glo..._gitlab 18: transfer closed with outstanding read data remaining

springboot+Shiro快速入门:简洁版(快速搭建示例)_springboot+shiro快速入门:简洁版(快速搭建示例)-程序员宅基地

文章浏览阅读311次,点赞2次,收藏2次。springboot整合shiro快速入门简洁版_springboot+shiro快速入门:简洁版(快速搭建示例)

21 款 yyds 的 IDEA插件-程序员宅基地

文章浏览阅读347次。点击上方“朱小厮的博客”,选择“设为星标”后台回复"书",获取后台回复“k8s”,可领取k8s资料最近,闲来无事,为了改变一下枯燥的编程环境,特地搜寻了下有助提升代码功力的..._activate mybatis log

使用Jenkins Pipeline插件和Docker打造容器化构建环境-程序员宅基地

文章浏览阅读7k次。Docker和Jenkins像DevOps界的巧克力和花生酱那样,它们的组合产生了无数的机会,当然也产生了很多难题,笔者将提及这两个方面。本文中,我假定读者已经熟悉Jenkins和Docker,我将把焦点放在特定的配置上而不是把笔墨花费在许多博文已经介绍过的入门概念上。设定目标我所要达成的目标其实非常简单:在一个容器中搭建Jenkins主节点,并且在多个主机上搭建多个JNLP代理容器。这些代理节点..._jenkins 插件containernode.inside

青少年软件编程(202209)(C语言)(树&堆&图)等级考试(七级)试题及参考答案_青少年 c语言编程 题目-程序员宅基地

文章浏览阅读359次。给定一棵二叉树,求该二叉树的深度二叉树深度定义:从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的节点个数为树的深度时间限制:1000内存限制:65535输入第一行是一个整数n,表示二叉树的结点个数。二叉树结点编号从1到n,根结点为1,n _青少年 c语言编程 题目

随便推点

MATLAB db4小波分解与重构,语音降噪-程序员宅基地

文章浏览阅读4.4k次,点赞2次,收藏23次。小波变换3级分解Mallat图:将带噪语音作为输入信号进行逐级DWT小波分解,并将分解出的低频成分cA3cA_3cA3​与强制置0后的高频成分cD3cD_3cD3​,cD2cD_2cD2​,cD1cD_1cD1​进行小波重构。Demo:clc,clear[x,Fs]= audioread('MUsic_Test.wav');snr = 20; %设定信噪比,单位dbnoise = randn(size(x)); % 用randn函数产生高斯白噪声Nx = length(x_db4小波

安装和配置SNMP(windows10和Linux)--附SNMP客户端工具_snmp工具-程序员宅基地

文章浏览阅读8.3k次,点赞5次,收藏34次。首先需要安装 snmp ,使用下面的命令进行安装安装完毕之后,使用下面的命令查看是否安装成功当命令行显示如图即为安装成功。_snmp工具

如何正确的敲键盘(打字习惯改正)_怎么敲键盘-程序员宅基地

文章浏览阅读6.4k次,点赞5次,收藏40次。练习打字的官网:http://dazi.kukuw.com/关于打字的详细介绍:一个过来人的打字指法纠正之路_怎么敲键盘

网络安全解决方案-程序员宅基地

文章浏览阅读9.6k次,点赞3次,收藏68次。一,网络安全体系结构网络安全体系结构是对网络信息安全基本问题的应对措施的集合,通常由保护,检测,响应和恢复等手段构成。1,网络信息安全的基本问题研究信息安全的困难在于:边界模糊数据安全与平台安全相交叉;存储安全与传输安全相制约;网络安全,应用安全与系统安全共存;集中的安全模式与分权制约安全模式相互竞争等。评估困难安全结构非常复杂,网络层,系统层,应用层的安全设备,安全协议和安全程序构成一个有机的整体,加上安全机制与人的互动性,网络的动态运行带来的易变性,使得评价网络安全性成为极_网络安全解决方案

QGIS在Windows下的编译——QGIS3.28.15 + Qt5.15.3 +CMake3.28.0 + VS2022 ---64位版本_qgis windows编译-程序员宅基地

文章浏览阅读1.2k次,点赞22次,收藏29次。QGIS在Windows下的编译——QGIS3.28.15 + Qt5.15.3 +CMake3.28.0 + VS2022 ---64位版本_qgis windows编译

BAAF-Net源码阅读_baafnet-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏3次。BAAF-Net代码是基于RandLANet编写的,所以在数据预处理和训练策略是基本是一致的,这里我们只介绍一下BAAF-Net的网络结构。_baafnet

推荐文章

热门文章

相关标签