19.串口驱动程序学习(一)

            串口驱动程序学习

  本文主要实现对串口驱动程序初始化的分析

一、串口驱动中的数据结构

  尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实现了UART设备的通用tty驱动层,称为串口核心层,这样,UART驱动的主要任务变成了实现serial_core.c中定义的一组uart_xxx接口而非tty_xxx接口。

1.1下图描述了串行系统间的层次结构关系,可以概括为:

  用户应用层 --> 线路规划层 --> TTY层 --> 底层驱动层 --> 物理硬件层

  

1.2下图是串口核心层在整个tty源文件关系及数据流向中的位置:

  

其中的xxx_uart.c在此处就是drivers/tty/serial/samsung.c和s3c6400.c

二、串口驱动中的数据结构

  

1.4使用到的数据结构

Uart驱动程序主要围绕三个关键的数据结构展开(include/linux/serial_core.h中定义):

  1. UART驱动程序结构:struct uart_driver
  2. UART端口结构: struct uart_port
  3. UART相关操作函数结构: struct uart_ops

1.4.1其中一个串口驱动对应一个struct uart_driver当然一个驱动是可以对应多个设备的:

 1 struct uart_driver {
 2     struct module        *owner;
 3     const char        *driver_name;
 4     const char        *dev_name;
 5     int             major;
 6     int             minor;
 7     int             nr;    //端口个数
 8     struct console        *cons;
 9
10     /*
11      * these are private; the low level driver should not
12      * touch these; they should be initialised to NULL
13      */
14     struct uart_state    *state;
15     struct tty_driver    *tty_driver;
16 };

其中的uart_state是设备状态结构结构体:

1 struct uart_state {
2     struct tty_port        port;
3     int            pm_state;
4     struct circ_buf        xmit;
5     struct tasklet_struct    tlet;
6     struct uart_port    *uart_port;
7 };

  在uart_open()中:

   tty->driver_data = state;

  在其他uart_xxx()中:

   struct uart_state *state = tty->driver_data;

   就可以获取设备私有信息结构体。

1.4.2uart_port用于描述一个UART端口(直接对应于一个串口)的I/O端口或者IO内存地址等信息--->即一个uart_port对应一个端口

 1 struct uart_port {
 2     spinlock_t        lock;            /* port lock */
 3     unsigned long        iobase;            /* in/out[bwl] */
 4     unsigned char __iomem    *membase;        /* read/write[bwl] */
 5     unsigned int        (*serial_in)(struct uart_port *, int);
 6     void            (*serial_out)(struct uart_port *, int, int);
 7     void            (*set_termios)(struct uart_port *,
 8                                struct ktermios *new,
 9                                struct ktermios *old);
10     void            (*pm)(struct uart_port *, unsigned int state,
11                       unsigned int old);
12     unsigned int        irq;            /* irq number */
13     unsigned long        irqflags;        /* irq flags  */
14     unsigned int        uartclk;        /* base uart clock */
15     unsigned int        fifosize;        /* tx fifo size */
16     unsigned char        x_char;            /* xon/xoff char */
17     unsigned char        regshift;        /* reg offset shift */
18     unsigned char        iotype;            /* io access style */
19     unsigned char        unused1;
20
21 #define UPIO_PORT        (0)
22 #define UPIO_HUB6        (1)
23 #define UPIO_MEM        (2)
24 #define UPIO_MEM32        (3)
25 #define UPIO_AU            (4)            /* Au1x00 type IO */
26 #define UPIO_TSI        (5)            /* Tsi108/109 type IO */
27 #define UPIO_DWAPB        (6)            /* DesignWare APB UART */
28 #define UPIO_RM9000        (7)            /* RM9000 type IO */
29 #define UPIO_DWAPB32        (8)            /* DesignWare APB UART (32 bit accesses) */
30
31     unsigned int        read_status_mask;    /* driver specific */
32     unsigned int        ignore_status_mask;    /* driver specific */
33     struct uart_state    *state;            /* pointer to parent state */
34     struct uart_icount    icount;            /* statistics */
35
36     struct console        *cons;            /* struct console, if any */
37 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
38     unsigned long        sysrq;            /* sysrq timeout */
39 #endif
40
41     upf_t            flags;
42
43 #define UPF_FOURPORT        ((__force upf_t) (1 << 1))
44 #define UPF_SAK            ((__force upf_t) (1 << 2))
45 #define UPF_SPD_MASK        ((__force upf_t) (0x1030))
46 #define UPF_SPD_HI        ((__force upf_t) (0x0010))
47 #define UPF_SPD_VHI        ((__force upf_t) (0x0020))
48 #define UPF_SPD_CUST        ((__force upf_t) (0x0030))
49 #define UPF_SPD_SHI        ((__force upf_t) (0x1000))
50 #define UPF_SPD_WARP        ((__force upf_t) (0x1010))
51 #define UPF_SKIP_TEST        ((__force upf_t) (1 << 6))
52 #define UPF_AUTO_IRQ        ((__force upf_t) (1 << 7))
53 #define UPF_HARDPPS_CD        ((__force upf_t) (1 << 11))
54 #define UPF_LOW_LATENCY        ((__force upf_t) (1 << 13))
55 #define UPF_BUGGY_UART        ((__force upf_t) (1 << 14))
56 #define UPF_NO_TXEN_TEST    ((__force upf_t) (1 << 15))
57 #define UPF_MAGIC_MULTIPLIER    ((__force upf_t) (1 << 16))
58 #define UPF_CONS_FLOW        ((__force upf_t) (1 << 23))
59 #define UPF_SHARE_IRQ        ((__force upf_t) (1 << 24))
60 /* The exact UART type is known and should not be probed.  */
61 #define UPF_FIXED_TYPE        ((__force upf_t) (1 << 27))
62 #define UPF_BOOT_AUTOCONF    ((__force upf_t) (1 << 28))
63 #define UPF_FIXED_PORT        ((__force upf_t) (1 << 29))
64 #define UPF_DEAD        ((__force upf_t) (1 << 30))
65 #define UPF_IOREMAP        ((__force upf_t) (1 << 31))
66
67 #define UPF_CHANGE_MASK        ((__force upf_t) (0x17fff))
68 #define UPF_USR_MASK        ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
69
70     unsigned int        mctrl;            /* current modem ctrl settings */
71     unsigned int        timeout;        /* character-based timeout */
72     unsigned int        type;            /* port type */
73     const struct uart_ops    *ops;
74     unsigned int        custom_divisor;
75     unsigned int        line;            /* port index */
76     resource_size_t        mapbase;        /* for ioremap */
77     struct device        *dev;            /* parent device */
78     unsigned char        hub6;            /* this should be in the 8250 driver */
79     unsigned char        suspended;
80     unsigned char        irq_wake;
81     unsigned char        unused[2];
82     void            *private_data;        /* generic platform data pointer */
83 };

1.4.3uart_ops定义了针对UART的一系列操作

 1 struct uart_ops {
 2     unsigned int    (*tx_empty)(struct uart_port *);
 3     void        (*set_mctrl)(struct uart_port *, unsigned int mctrl);
 4     unsigned int    (*get_mctrl)(struct uart_port *);
 5     void        (*stop_tx)(struct uart_port *);
 6     void        (*start_tx)(struct uart_port *);
 7     void        (*send_xchar)(struct uart_port *, char ch);
 8     void        (*stop_rx)(struct uart_port *);
 9     void        (*enable_ms)(struct uart_port *);
10     void        (*break_ctl)(struct uart_port *, int ctl);
11     int        (*startup)(struct uart_port *);
12     void        (*shutdown)(struct uart_port *);
13     void        (*flush_buffer)(struct uart_port *);
14     void        (*set_termios)(struct uart_port *, struct ktermios *new,
15                        struct ktermios *old);
16     void        (*set_ldisc)(struct uart_port *, int new);
17     void        (*pm)(struct uart_port *, unsigned int state,
18                   unsigned int oldstate);
19     int        (*set_wake)(struct uart_port *, unsigned int state);
20
21     /*
22      * Return a string describing the type of the port
23      */
24     const char *(*type)(struct uart_port *);
25
26     /*
27      * Release IO and memory resources used by the port.
28      * This includes iounmap if necessary.
29      */
30     void        (*release_port)(struct uart_port *);
31
32     /*
33      * Request IO and memory resources used by the port.
34      * This includes iomapping the port if necessary.
35      */
36     int        (*request_port)(struct uart_port *);
37     void        (*config_port)(struct uart_port *, int);
38     int        (*verify_port)(struct uart_port *, struct serial_struct *);
39     int        (*ioctl)(struct uart_port *, unsigned int, unsigned long);
40 #ifdef CONFIG_CONSOLE_POLL
41     void    (*poll_put_char)(struct uart_port *, unsigned char);
42     int        (*poll_get_char)(struct uart_port *);
43 #endif
44 };

UART信息结构: struct uart_info

二、串口初始化分析

  

分析过程:

2.1进入到内核的Samsung.c文件中

  找到内核模块加载函数:module_init(s3c24xx_serial_modinit);

  可以看到加载模块直接调用platform_driver_register,注册了 开发板串口这个平台驱动。

  因为把uart驱动注册为platform驱动,当平台驱动与平台设备进行匹配的时候会调用平台总线的match函数,匹配成功后就会调用平台驱动的xxx_probe()函数来进行一系列的初始化工作。

 1 int s3c24xx_serial_probe(struct platform_device *dev,
 2              struct s3c24xx_uart_info *info)
 3 {
 4     struct s3c24xx_uart_port *ourport;
 5     int ret;
 6
 7     dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
 8
 9     ourport = &s3c24xx_serial_ports[probe_index];
10     probe_index++;
11
12     dbg("%s: initialising port %p...\n", __func__, ourport);
13
14     ret = s3c24xx_serial_init_port(ourport, info, dev);
15     if (ret < 0)
16         goto probe_err;
17
18     dbg("%s: adding port\n", __func__);
19     uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
20     platform_set_drvdata(dev, &ourport->port);
21
22     ret = device_create_file(&dev->dev, &dev_attr_clock_source);
23     if (ret < 0)
24         printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
25
26     ret = s3c24xx_serial_cpufreq_register(ourport);
27     if (ret < 0)
28         dev_err(&dev->dev, "failed to add cpufreq notifier\n");
29
30     return 0;
31
32  probe_err:
33     return ret;
34 }
时间: 2024-10-03 13:38:50

19.串口驱动程序学习(一)的相关文章

模拟串口--基于STM8普通IO口的模拟串口驱动程序

基于STM8普通IO口的模拟串口驱动程序 标准串口通讯数据的格式为:起始位(1) + 数据位(8) + 校验位(1) + 停止位(1) 串口通讯另外一个重要的的部分是设置波特率,波特率就是1秒钟内串口所传输的Bit(位)数. 关于采样频率:为了较小读取或者发送串行数据的误差,我们采取了在N(我用的是4次)次中断中,取固定位置的读取的数据. 我以stm8中9600波特率计算的过程为例:(1秒钟传输9600位) 可以计算出传输1位所需要的时间 T1 = 1/9600 约为104us 由此可知,发送一

RT-Thread下的串口驱动程序分析【转载】

编写本文稿的目的,在于通过分析stm32平台上的串口中断源码,学习 RTT中如何编写中断处理程序 如何编写RTT设备驱动接口代码 了解串行设备的常见处理机制 先以RTT官方源码中的STM32 BSP包来分析.rt-thread\bsp\stm32f10x 下,涉及的文件为: usart.c usart.h serail.c serail.h RTT的设备驱动程序概述 编写uart的驱动程序,首先需要了解RTT的设备框架,RTT的设备框架我们已经大致的介绍了一下,这里以usart的驱动来具体分析R

C#串口通信学习笔记

因为参加一个小项目,需要对继电器进行串口控制,所以这两天学习了基本的串口编程.同事那边有JAVA的串口通信包,不过是从网上下载的,比较零乱,难以准确掌握串口通信的流程和内含.因此,个人通过学习网上大牛的方法,利用C#实现了基本的串口通信编程.下面对学习成果进行总结归纳,希望对大家有所帮助. 一.串口通信简介 串行接口(串口)是一种可以将接受来自CPU的并行数据字符转换为连续的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件.一般完成这种功能的电路,我们称为串行接口

Linux设备驱动程序学习笔记(一)

1.设备驱动程序扮演的角色:       设备程序是一个独立的“黑盒子”,使其某个特定硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节.用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序.将这些调用映射到作用于实际硬件的设备特有操作上,则是设备驱动程序的任务.2.驱动程序的作用:        驱动程序应该处理如何使用硬件可用的问题,而将怎样使用硬件的问题留给上层应用.(提供机制,而不是策略)3.内核功能划分:        进程管理    内存管理    文

奶爸业余单片机学习之:UART串口通信学习笔记(二)

/************************************** 串口通信实验* 晶振11.0592MHz* 波特率9600bps* 中断方式实现:单片机接收电脑数据,加1后发送回电脑***************************************/ #include<reg52.h> unsigned char dat; /**********串口通信配置*******************/void UART_CONFIG(unsigned long baud

事件驱动程序学习总结

 事件驱动程序,意思便是捕捉到某些预定想要的事件程序做出响应.在java中最常见的便是监听器的应用了. 监听器的声明: 1)通过接口继承,注意,当继承了接口,其内部的所有抽象方法都需要实现: 1 class ButtonListener implements ActionListener{ 2 3 @Override 4 public void actionPerformed(ActionEvent e) { 5 // TODO Auto-generated method stub 6 7 }

奶爸业余单片机学习之:UART串口通信学习笔记(一)

UART串口通信,全名:异步串口通信 UART的四种工作模式:(0,1,2,3) 模式1:SM0 = 0; SM1 = 1;REN = 1  //由SCON(串行口控制寄存器)控制,可位寻址.10位异步收发(8位数据),波特率可变(由定时器1的溢出率控制) 模式1功能:以TXD为例,平时没数据时,TXD为高电平,需要发送数据时,先发送一个起始位0,然后发送八位数据位(一个字节),最后发送一位停止位1: REN位为允许串行接收位:REN = 1:允许串行口接收数据:REN = 0:禁止串行口接收数

Linux设备驱动程序学习随笔1--从头文件 linux/moudle.h开始

所有的程序员入门的第一个程序都是从 Holle World 开始,linux嵌入式驱动开发也不例外,<Linux设备驱动程序>这本书的第一个程序就是hello world.然而,人生写驱动程序的第一次编译就异常的艰难. 以下是hello world 的程序,很简单,基本上学过C就能看懂,该程序包括两个头文件,引用了4个外部函数,内建2个函数. 1 #include <linux/init.h> 2 #include <linux/module.h> 3 4 MODULE

2017.08.19晚开始学习c语言

一个完全的新手,希望通过c的学习,来锻炼并为自己的将来构建一个美好的平台! 一 教程查找 1.习惯性使用种子搜索(坏笑)搜到c语言教程,选择其中自学去学习教程并开始学习.而后因视频下载过慢,百度搜索自学去,发现自学去论坛找到新的地址与B站视频...开始学习https://www.bilibili.com/video/av2427340/index_2.html?t=1045#page=4. 2.视频推荐使用工具 (1)notepad 用于编辑代码  (2)gcc   用于执行代码    并搭建开