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 }

 

posted @ 2016-04-09 17:14  for_learning  阅读(744)  评论(0编辑  收藏  举报