Linux串口驱动分析初始化
<pre name="code" class="cpp">/*** uart分析** 其实串口分析就两个重要的文件: S3c2440.c Samsung.c** **//*1. 首先从Samsung.c的模块初始化函数看起*/static int __init s3c24xx_serial_modinit(void)
{int ret;ret = uart_register_driver(&s3c24xx_uart_drv);if (ret < 0) {printk(KERN_ERR "failed to register UART driver\n");return -1;}return 0;
}/*参数是需要程序员自己定义 */
/** s3c2440.c **/static struct s3c24xx_uart_info s3c2440_uart_inf = {.name = "Samsung S3C2440 UART",.type = PORT_S3C2440, //端口类型.fifosize = 64, //FIFO缓冲区大小.rx_fifomask = S3C2440_UFSTAT_RXMASK, .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,.rx_fifofull = S3C2440_UFSTAT_RXFULL,.tx_fifofull = S3C2440_UFSTAT_TXFULL,.tx_fifomask = S3C2440_UFSTAT_TXMASK,.tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,.get_clksrc = s3c2440_serial_getsource,.set_clksrc = s3c2440_serial_setsource,.reset_port = s3c2440_serial_resetport,
};/*platform 驱动定义: s3c2440_serial_driver*/
static struct platform_driver s3c2440_serial_driver = {.probe = s3c2440_serial_probe, //匹配后设备调用.remove = __devexit_p(s3c24xx_serial_remove),.driver = {.name = "s3c2440-uart", //驱动的名字.owner = THIS_MODULE,},
};/*分析uart_register_driver函数*/
/* 这个函数的主要作用是初始化tty_driver结构体。 其实tty_driver的主要成员都是通过传进来的参数drv赋值的* 其次是初始化uart_driver中的uart_state成员。* * uart_state是一个结构体包含了tty_port和uart_port。 而uart_port主要是和硬件相关。 其实每一个串口都对应一个uart_port结构* 这里只初始化了tty_port结构。而uart_port是在等设备匹配上后在设备的ops中的probe函数中初始化*/
int uart_register_driver(struct uart_driver *drv)
{/** Maybe we should be using a slab cache for this, especially if* we have a large number of ports to handle.*/drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);if (!drv->state)goto out;normal = alloc_tty_driver(drv->nr);if (!normal)goto out_kfree;drv->tty_driver = normal;normal->owner = drv->owner;normal->driver_name = drv->driver_name;normal->name = drv->dev_name;normal->major = drv->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);/** Initialise the UART state(s).*/for (i = 0; i < drv->nr; i++) {struct uart_state *state = drv->state + i;struct tty_port *port = &state->port;tty_port_init(port);port->ops = &uart_port_ops;port->close_delay = 500; /* .5 seconds */port->closing_wait = 30000; /* 30 seconds */tasklet_init(&state->tlet, uart_tasklet_action,(unsigned long)state);}retval = tty_register_driver(normal);
}/* 当设备与驱动匹配后,会调用此函数。** probe函数一般就是做的硬件相关的初始化。* * 其实uart_port的初始化也是通过s3c24xx_uart_port来初始化的。* */
int s3c24xx_serial_probe(struct platform_device *dev,struct s3c24xx_uart_info *info)
{struct s3c24xx_uart_port *ourport;int ret;dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);/*取得相应的端口*/ourport = &s3c24xx_serial_ports[probe_index];probe_index++;dbg("%s: initialising port %p...\n", __func__, ourport);/*初始化端口*/ret = s3c24xx_serial_init_port(ourport, info, dev);if (ret < 0)goto probe_err;dbg("%s: adding port\n", __func__);/*这个函数的主要作用是: 将uart_port和uart_driver关联起来*/uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);platform_set_drvdata(dev, &ourport->port);ret = device_create_file(&dev->dev, &dev_attr_clock_source);if (ret < 0)printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);ret = s3c24xx_serial_cpufreq_register(ourport);if (ret < 0)dev_err(&dev->dev, "failed to add cpufreq notifier\n");return 0;probe_err:return ret;
}/** 端口初始化函数* */
static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,struct s3c24xx_uart_info *info,struct platform_device *platdev)
{struct uart_port *port = &ourport->port;struct s3c2410_uartcfg *cfg;struct resource *res;int ret;dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);if (platdev == NULL)return -ENODEV;/*获取设备的资源,详细解析见下面*/cfg = s3c24xx_dev_to_cfg(&platdev->dev);if (port->mapbase != 0)return 0;/*判断是否大于总数4个*/if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);return -ERANGE;}port->dev = &platdev->dev;ourport->info = info;/*初始化port的大小 = 64*/ourport->port.fifosize = info->fifosize;dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);port->uartclk = 1;/*判断是否开启流控*/if (cfg->uart_flags & UPF_CONS_FLOW) {dbg("s3c24xx_serial_init_port: enabling flow control\n");port->flags |= UPF_CONS_FLOW;}/*获取uart资源*/res = platform_get_resource(platdev, IORESOURCE_MEM, 0);if (res == NULL) {printk(KERN_ERR "failed to find memory resource for uart\n");return -EINVAL;}dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);/*初始化基地址等*/port->mapbase = res->start;port->membase = S3C_VA_UART + (res->start & 0xfffff);ret = platform_get_irq(platdev, 0);if (ret < 0)port->irq = 0;else {port->irq = ret;ourport->rx_irq = ret;ourport->tx_irq = ret + 1;}ret = platform_get_irq(platdev, 1);if (ret > 0)ourport->tx_irq = ret;/*获取时钟*/ourport->clk = clk_get(&platdev->dev, "uart");dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",port->mapbase, port->membase, port->irq,ourport->rx_irq, ourport->tx_irq, port->uartclk);/* reset the fifos (and setup the uart) */s3c24xx_serial_resetport(port, cfg);return 0;
}#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
/** cfg = s3c24xx_dev_to_cfg(&platdev->dev)* * 那么cfg到底是如何获得?** 搜索s3c2410_uartcfg得到:*/#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODEstatic struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {[0] = {.hwport = 0,.flags = 0,.ucon = 0x3c5,.ulcon = 0x03,.ufcon = 0x51,},[1] = {.hwport = 1,.flags = 0,.ucon = 0x3c5,.ulcon = 0x03,.ufcon = 0x51,},[2] = {.hwport = 2,.flags = 0,.ucon = 0x3c5,.ulcon = 0x43,.ufcon = 0x51,}};void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{if (cpu == NULL)return;if (cpu->init_uarts == NULL) {printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");} else(cpu->init_uarts)(cfg, no);
}/*初始化系统上的串口资源*/
void __init s3c24xx_init_uartdevs(char *name,struct s3c24xx_uart_resources *res,struct s3c2410_uartcfg *cfg, int no)
{struct platform_device *platdev;struct s3c2410_uartcfg *cfgptr = uart_cfgs;struct s3c24xx_uart_resources *resp;int uart;memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {platdev = s3c24xx_uart_src[cfgptr->hwport];resp = res + cfgptr->hwport;s3c24xx_uart_devs[uart] = platdev;platdev->name = name;platdev->resource = resp->resources;platdev->num_resources = resp->nr_resources;/*从这里获取platform*/platdev->dev.platform_data = cfgptr;}nr_uarts = no;
}/*uart 所对应的资源 platform_get_resourced调用**/
/* Serial port registrations */static struct resource s3c2410_uart0_resource[] = {[0] = {.start = S3C2410_PA_UART0,.end = S3C2410_PA_UART0 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX0,.end = IRQ_S3CUART_ERR0,.flags = IORESOURCE_IRQ,}
};static struct resource s3c2410_uart1_resource[] = {[0] = {.start = S3C2410_PA_UART1,.end = S3C2410_PA_UART1 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX1,.end = IRQ_S3CUART_ERR1,.flags = IORESOURCE_IRQ,}
};static struct resource s3c2410_uart2_resource[] = {[0] = {.start = S3C2410_PA_UART2,.end = S3C2410_PA_UART2 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX2,.end = IRQ_S3CUART_ERR2,.flags = IORESOURCE_IRQ,}
};static struct resource s3c2410_uart3_resource[] = {[0] = {.start = S3C2443_PA_UART3,.end = S3C2443_PA_UART3 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX3,.end = IRQ_S3CUART_ERR3,.flags = IORESOURCE_IRQ,},
};struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {[0] = {.resources = s3c2410_uart0_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart0_resource),},[1] = {.resources = s3c2410_uart1_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart1_resource),},[2] = {.resources = s3c2410_uart2_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart2_resource),},[3] = {.resources = s3c2410_uart3_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart3_resource),},
};总结: 修改驱动需要设计的数据结构1. uart_driver:用于初始化tty_driver
2. s3c24xx_uart_port: 用于初始化uart_port
3. s3c24xx_serial_ops: 硬件的操作集
4. s3c24xx_uart_info: 用于初始化uart_port其实也就是:编写S3c2440.c这个串口文件。
Linux串口驱动分析初始化相关推荐
- linux串口驱动分析
linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...
- linux串口驱动分析【转】
转自:http://blog.csdn.net/hanmengaidudu/article/details/11946591 硬件资源及描述 s3c2440A 通用异步接收器和发送器(UART)提供了 ...
- linux串口发送数据程序,linux串口驱动分析——发送数据
一.应用程序中write函数到底层驱动历程 和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数 ...
- LINUX串口驱动分析——发送数据
https://www.cnblogs.com/51qianrushi/p/4324845.html
- GPS NMEA 0183 4.10协议/GPS Linux串口驱动
NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备制定的标准格式.现在已经成为GPS导航设备统一的RTCM(R ...
- Linux UART驱动分析及测试
1.Linux TTY驱动程序框架 Linux TTY驱动程序代码位于/drivers/tty下面.TTY的层次接口包括TTY应用层.TTY文件层.TTY线路规程层.TTY驱动层.TTY设备驱动层.T ...
- Linux串口驱动(2) - 线路规程
1. 注册tty的ldisc ldisc全称 line discipline(线路规程),因为历史原因,tty属于一类设备,而串口设备只是其中一种,所以该模块负责将用户操作桥接到不同的tty驱动.从代 ...
- Linux串口驱动(3) - open详解
1. 用户空间open的操作实现 串口设备是被注册为字符设备的,在注册过程中填充了struct file_operations tty_fops结构体,该结构体中的成员open.read.write等 ...
- wince串口驱动分析(转)
wince串口驱动分析 串行通讯接口主要是指UART(通用串行)和IRDA两种.通常的串行连接电气连接上有3wire和9wire两种.3wire的接线方式下定义了发送.接收和地三根连接.其用途就如名称 ...
- Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)
一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...
最新文章
- 面向对象 - 继承性
- 【STM32】FreeRTOS 移植到 STM32F103
- Xcode6.3 怎样使用Leaks查看内存泄露
- openstack vlan配置_为OpenStack和K8s集群提供无缝虚拟网络
- mysql查看执行计划_MySql中如何使用 explain 查询 SQL 的执行计划
- openssl java aes_请问如何使用AES对使用OpenSSL命令加密的Java文件进行解密?
- 算法复习第五章贪心法
- 20169210 2016-2017-2《网络攻防实践》第五周作业
- 第3次作业:阅读《构建之法》1-5章
- 最好用的十六进制编辑器010 Editor
- linux下文本去重
- 重装服务器系统鼠标键盘用不了,win7重装系统后鼠标键盘不能用怎么办
- Windows下Perl环境安装和使用
- Python运算(四)random模块secrets模块
- Drone 自定义 UI
- 视频压缩【亲测可用】
- 蓝牙4.0BLE中协议栈详解
- 【专业知识问答】问:什么叫突然短路?为什么突然短路时会产生很大短路电流?
- 【号外20191127】微软刚刚更新了snipping tool
- 细菌觅食算法(Bacterial Foraging Optimization)
热门文章
- 在Linux环境下安装MYSQL
- vue项目下,webpack.js/package.json配置
- 静态修饰词static以及图解分析
- 解决windows下的mysql匿名登陆无法使用mysql数据库的问题
- SQL 2005 带自增列 带外键约束 数据导入导出
- 深度学习基础系列(六)| 权重初始化的选择
- 关于虚拟机virtualbox使用无线卡上网的设置
- 轻松搞定RabbitMQ(四)——发布/订阅
- R6300V2 从 DD-WRT 回刷恢复 官方原厂固件 DD-WRT to R6300V2
- 环境配置就是安装软件,修改软件的配置文件,安装软件就是文件的复制,与新增--linux下一切皆文件...