UART裝置驅動

來源:互聯網
上載者:User

 儘管一個特定的UART裝置驅動完全可以遵循14.2~14.5的方法來設計,即定義tty_driver並實現其中的成員函數,但是Linux已經在檔案 serial_core.c中實現了UART裝置的通用tty驅動層(姑且稱其為串口核心層),這樣,UART驅動的主要任務演變成實現serial- core.c中定義的一組uart_xxx介面而非tty_xxx介面,14.5所示。
    serial_core.c串口核心層完全可以被當作14.2~14.5節tty裝置驅動的執行個體,它實現了UART裝置的tty驅動。
    提示:Linux驅動的這種分層思想在許多類型的裝置驅動中都得到了體現,例如上一章IDE裝置驅動中,核心實現了通用的IDE層用於處理塊裝置I/O請求,而具體的IDE則只需使用ide_xxx這樣的介面,甚至不必理會複雜的塊裝置驅動結構。
             

 

                        圖14.5 串口核心層

串口核心層為串口裝置驅動提供了如下3個結構體:
1、uart_driver
uart_driver包含串口裝置的驅動名、裝置名稱、裝置號等資訊,它封裝了tty_driver,使得底層的UART驅動無需關心tty_driver,其定義如代碼清單14.13。
代碼清單14.13 uart_driver結構體
1  struct uart_driver
2  {
3    struct module *owner;
4    const char *driver_name; //驅動名
5    const char *dev_name;    //裝置名稱
6    const char *devfs_name;  //裝置檔案系統名
7    int major;  //主裝置號
8    int minor;   //次裝置號
9    int nr;
10   struct console *cons;
11
12   /* 私人的,底層驅動不應該訪問這些成員,應該被初始化為NULL */
13   struct uart_state *state;
14   struct tty_driver *tty_driver;
15 };
一個tty驅動必須註冊/登出tty_driver,而一個UART驅動則演變為註冊/登出uart_driver,使用如下介面:
int uart_register_driver(struct uart_driver *drv);
void uart_unregister_driver(struct uart_driver *drv);
實際上,uart_register_driver()和uart_unregister_driver()中分別包含了tty_register_driver()和tty_unregister_driver()的操作,如代碼清單14.14所示。
代碼清單14.14 uart_register_driver()和uart_unregister_driver()函數
1  int uart_register_driver(struct uart_driver *drv)
2  {
3   struct tty_driver *normal = NULL;
4   int i, retval;
5   ...
6    /* 分配tty_driver */
7   normal  = alloc_tty_driver(drv->nr);
8   if (!normal)
9    goto out;
10  drv->tty_driver = normal;
11   /* 初始化tty_driver */
12  normal->owner  = drv->owner;
13  normal->driver_name = drv->driver_name;
14  normal->devfs_name = drv->devfs_name;
15  normal->name  = drv->dev_name;
16  normal->major  = drv->major;
17  normal->minor_start = drv->minor;
18  normal->type  = TTY_DRIVER_TYPE_SERIAL;
19  normal->subtype  = SERIAL_TYPE_NORMAL;
20  normal->init_termios = tty_std_termios;
21  normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
22  normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
23  normal->driver_state    = drv;
24  tty_set_operations(normal, &uart_ops);
25
26  ...
27  /* 註冊tty驅動 */
28  retval = tty_register_driver(normal);
29  out:
30  if (retval < 0) {
31   put_tty_driver(normal);
32   kfree(drv->state);
33  }
34  return retval;
35 }
36
37 void uart_unregister_driver(struct uart_driver *drv)
38 {
39  struct tty_driver *p = drv->tty_driver;
40  tty_unregister_driver(p);  /* 登出tty驅動 */
41  put_tty_driver(p);
42  kfree(drv->state);
43  drv->tty_driver = NULL;
44 }
2、uart_port
uart_port用於描述一個UART連接埠(直接對應於一個串口)的I/O連接埠或I/O記憶體位址、FIFO大小、連接埠類型等資訊,其定義如代碼清單14.15。
代碼清單14.15 uart_port結構體
1  struct uart_port
2  {
3    spinlock_t lock; /* 連接埠鎖 */
4    unsigned int iobase; /* IO連接埠基地址 */
5    unsigned char __iomem *membase; /* IO記憶體基地址 */
6    unsigned int irq; /* 中斷號 */
7    unsigned int uartclk; /* UART時鐘 */
8    unsigned char fifosize; /* 傳輸fifo大小 */
9    unsigned char x_char; /* xon/xoff字元 */
10   unsigned char regshift; /* 寄存器位移 */
11   unsigned char iotype; /* IO存取類型 */
12
13   #define UPIO_PORT  (0)  /* IO連接埠*/
14   #define UPIO_HUB6  (1)
15   #define UPIO_MEM  (2)  /* IO記憶體*/
16   #define UPIO_MEM32  (3)
17   #define UPIO_AU   (4)   /* Au1x00類型IO */
18
19   unsigned int read_status_mask; /* 驅動相關的 */
20   unsigned int ignore_status_mask; /* 驅動相關的 */
21   struct uart_info *info; /* 指向parent資訊 */
22   struct uart_icount icount; /* 計數 */
23
24   struct console *cons; /* console結構體 */
25   #ifdef CONFIG_SERIAL_CORE_CONSOLE
26     unsigned long sysrq; /* sysrq逾時 */
27   #endif
28
29   upf_t flags;
30
31   #define UPF_FOURPORT  ((__force upf_t) (1 << 1))
32   #define UPF_SAK   ((__force upf_t) (1 << 2))
33   #define UPF_SPD_MASK  ((__force upf_t) (0x1030))
34   #define UPF_SPD_HI  ((__force upf_t) (0x0010))
35   #define UPF_SPD_VHI  ((__force upf_t) (0x0020))
36   #define UPF_SPD_CUST  ((__force upf_t) (0x0030))
37   #define UPF_SPD_SHI  ((__force upf_t) (0x1000))
38   #define UPF_SPD_WARP  ((__force upf_t) (0x1010))
39   #define UPF_SKIP_TEST  ((__force upf_t) (1 << 6))
40   #define UPF_AUTO_IRQ  ((__force upf_t) (1 << 7))
41   #define UPF_HARDPPS_CD  ((__force upf_t) (1 << 11))
42   #define UPF_LOW_LATENCY  ((__force upf_t) (1 << 13))
43   #define UPF_BUGGY_UART  ((__force upf_t) (1 << 14))
44   #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
45   #define UPF_CONS_FLOW  ((__force upf_t) (1 << 23))
46   #define UPF_SHARE_IRQ  ((__force upf_t) (1 << 24))
47   #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
48   #define UPF_IOREMAP  ((__force upf_t) (1 << 31))
49
50   #define UPF_CHANGE_MASK  ((__force upf_t) (0x17fff))
51   #define UPF_USR_MASK  ((__force upf_t)
52       (UPF_SPD_MASK|UPF_LOW_LATENCY))
53   unsigned int mctrl; /* 目前modem控制設定 */
54   unsigned int timeout; /* 基於字元的逾時 */
55   unsigned int type; /* 連接埠類型 */
56   const struct uart_ops *ops; /* UART操作集 */
57   unsigned int custom_divisor;
58   unsigned int line; /* 連接埠索引 */
59   unsigned long mapbase; /* ioremap後基地址 */
60   struct device *dev; /* parent裝置 */
61   unsigned char hub6;
62   unsigned char unused[3];
63 };
串口核心層提供如下函數來添加1個連接埠:
int uart_add_one_port(struct uart_driver *drv, struct uart_port *port);
    對上述函數的調用應該發生在uart_register_driver()之後,uart_add_one_port()的一個最重要作用是封裝了tty_register_device()。
    uart_add_one_port()的“反函數”是uart_remove_one_port(),其中會調用tty_unregister_device(),原型為:
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port);
    驅動中雖然不需要處理uart_port的uart_info成員,但是在發送時,從使用者來的資料被儲存在xmit(被定義為circ_buf,即環形緩衝 區)中,因此UART驅動在發送資料時(一般在發送中斷處理函數中),需要從這個circ_buf擷取上層傳遞下來的字元。
3、uart_ops
     uart_ops 定義了針對UART的一系列操作,包括髮送、接收及線路設定等,如果說tty_driver中的tty_operations對於串口還較為抽象,那麼 uart_ops則直接面向了串口的UART,其定義如代碼清單14.16。Linux驅動的這種層次非常類似於物件導向編程中基類、衍生類別的關係,衍生類別針對特定的事物會更加具體,而基類則站在更高的抽象層次上。
代碼清單14.16 uart_ops結構體
1  struct uart_ops
2  {
3    unsigned int(*tx_empty)(struct uart_port*);
4    void(*set_mctrl)(struct uart_port *, unsigned int mctrl);
5    unsigned int(*get_mctrl)(struct uart_port*);
6    void(*stop_tx)(struct uart_port*);    //停止發送
7    void(*start_tx)(struct uart_port*);   //開始發送
8    void(*send_xchar)(struct uart_port *, char ch); //發送xchar
9    void(*stop_rx)(struct uart_port*);   //停止接收
10   void(*enable_ms)(struct uart_port*);
11   void(*break_ctl)(struct uart_port *, int ctl);
12   int(*startup)(struct uart_port*);
13   void(*shutdown)(struct uart_port*);
14   void(*set_termios)(struct uart_port *, struct termios *new, struct termios
15     *old);        //設定termios
16   void(*pm)(struct uart_port *, unsigned int state, unsigned int oldstate);
17   int(*set_wake)(struct uart_port *, unsigned int state);
18
19   /* 返回1個描述連接埠類型的字串 */
20   const char *(*type)(struct uart_port*);
21
22   /* 釋放連接埠使用的IO和記憶體資源,必要的情況下,應該進行iounmap操作*/
23   void(*release_port)(struct uart_port*);
24   /* 申請連接埠使用的IO和記憶體資源 */
25   int(*request_port)(struct uart_port*);
26  
27   void(*config_port)(struct uart_port *, int);
28   int(*verify_port)(struct uart_port *, struct serial_struct*);
29   int(*ioctl)(struct uart_port *, unsigned int, unsigned long);
30 };
    serial_core.c 中定義了tty_operations的執行個體,包含uart_open()、uart_close()、uart_write()、 uart_send_xchar()等成員函數(如代碼清單14.17),這些函數會藉助uart_ops結構體中的成員函數來完成具體的操作,代碼清單 14.18給出了tty_operations的uart_send_xchar()成員函數利用uart_ops中start_tx()、 send_xchar()成員函數的例子。
代碼清單14.17 串口核心層的tty_operations執行個體
1  static struct tty_operations uart_ops =
2  {
3   .open  = uart_open,//串口開啟
4   .close  = uart_close,//串口關閉
5   .write  = uart_write,//串口發送
6   .put_char = uart_put_char,//...
7   .flush_chars = uart_flush_chars,
8   .write_room = uart_write_room,
9   .chars_in_buffer= uart_chars_in_buffer,
10  .flush_buffer = uart_flush_buffer,
11  .ioctl  = uart_ioctl,
12  .throttle = uart_throttle,
13  .unthrottle = uart_unthrottle,
14  .send_xchar = uart_send_xchar,
15  .set_termios = uart_set_termios,
16  .stop  = uart_stop,
17  .start  = uart_start,
18  .hangup  = uart_hangup,
19  .break_ctl = uart_break_ctl,
20  .wait_until_sent= uart_wait_until_sent,
21 #ifdef CONFIG_PROC_FS
22  .read_proc = uart_read_proc, //proc入口讀函數
23 #endif
24  .tiocmget = uart_tiocmget,
25  .tiocmset = uart_tiocmset,
26 };
代碼清單14.18 串口核心層的tty_operations與uart_ops關係
1  static void uart_send_xchar(struct tty_struct *tty, char ch)
2  {
3    struct uart_state *state = tty->driver_data;
4    struct uart_port *port = state->port;
5    unsigned long flags;
6    //如果uart_ops中實現了send_xchar成員函數
7    if (port->ops->send_xchar)
8      port->ops->send_xchar(port, ch); 
9    else //uart_ops中未實現send_xchar成員函數
10   {
11     port->x_char = ch; //xchar賦值
12     if (ch)
13     {
14       spin_lock_irqsave(&port->lock, flags);
15       port->ops->start_tx(port);  //發送xchar
16       spin_unlock_irqrestore(&port->lock, flags);
17     }
18   }
19 }

注意:  整個調用流程為:  系統調用write()->uart_write()(tty_driver)->port->ops->start_tx();
  在使用串口核心層這個通用串口tty驅動層的介面後,一個串口驅動要完成的主要工作將包括:
•  定義uart_driver、uart_ops、uart_port等結構體的執行個體並在適當的地方根據具體硬體和驅動的情況初始化它們,當然具體裝置 xxx的驅動可以將這些結構套在新定義的xxx_uart_driver、xxx_uart_ops、xxx_uart_port之內。
•  在模組初始化時調用uart_register_driver()和uart_add_one_port()以註冊UART驅動並添加連接埠,在模組卸載時 調用uart_unregister_driver()和uart_remove_one_port()以登出UART驅動並移除連接埠。
•  根據具體硬體的datasheet實現uart_ops中的成員函數,這些函數的實現成為UART驅動的主體工作

 

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/dongliqiang2006/archive/2009/09/09/4536293.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.