Linux串口驅(qū)動編程_第1頁
Linux串口驅(qū)動編程_第2頁
Linux串口驅(qū)動編程_第3頁
Linux串口驅(qū)動編程_第4頁
Linux串口驅(qū)動編程_第5頁
已閱讀5頁,還剩62頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、Linux串口(serial、uart)驅(qū)動程序設(shè)計(jì)目錄Linux串口(serial、uart)驅(qū)動程序設(shè)計(jì)2一、核心數(shù)據(jù)結(jié)構(gòu)2二、串口驅(qū)動API6三、串口驅(qū)動例子9linux UART 串口驅(qū)動開發(fā)文檔27概念闡述27一、老版本的串口驅(qū)動程序28二、目前的串口驅(qū)動程序29三、3個數(shù)據(jù)結(jié)構(gòu)及其串口核心層API311、uart_driver312、uart_port323、uart_ops33四、uart_ops37五、注冊串口終端40六、支持platform_driver43七、串口接收數(shù)據(jù)和發(fā)送數(shù)據(jù)流程451. 相關(guān)文件452. 數(shù)據(jù)收發(fā)47基于Linux2.6.22和s3c2440的串口驅(qū)

2、動簡析-(1) 2013-11-21 15:56:3248基于Linux2.6.22和s3c2440的串口驅(qū)動簡析-(2) 2013-11-21 15:58:4956Linux串口(serial、uart)驅(qū)動程序設(shè)計(jì) 分類: LINUX原文地址:Linux串口(serial、uart)驅(qū)動程序設(shè)計(jì) 作者:lingdxuyan 一、核心數(shù)據(jù)結(jié)構(gòu) 串口驅(qū)動有3個核心數(shù)據(jù)結(jié)構(gòu),它們都定義在 1、uart_driver uart_driver包含了串口設(shè)備名、串口驅(qū)動名、主次設(shè)備號、串口控制臺(可選)等信息,還封裝了tty_driver(底層串口驅(qū)動無需關(guān)心tty_driver)。 struct u

3、art_driver struct module *owner; /* 擁有該uart_driver的模塊,一般為THIS_MODULE */ const char *driver_name; /* 串口驅(qū)動名,串口設(shè)備文件名以驅(qū)動名為基礎(chǔ) */ const char *dev_name; /* 串口設(shè)備名 */ int major; /* 主設(shè)備號 */ int minor; /* 次設(shè)備號 */ int nr; /* 該uart_driver支持的串口個數(shù)(最大) */ struct console *cons; /* 其對應(yīng)的console.若該uart_driver支持serial c

4、onsole,否則為NULL */ /* * these are private; the low level driver should not * touch these; they should be initialised to NULL */ struct uart_state *state; struct tty_driver *tty_driver; ; 2、uart_port uart_port用于描述串口端口的I/O端口或I/O內(nèi)存地址、FIFO大小、端口類型、串口時鐘等信息。實(shí)際上,一個uart_port實(shí)例對應(yīng)一個串口設(shè)備 struct uart_port spinloc

5、k_t lock; /* 串口端口鎖 */ unsigned int iobase; /* IO端口基地址 */ unsigned char _iomem *membase; /* IO內(nèi)存基地址,經(jīng)映射(如ioremap)后的IO內(nèi)存虛擬基地址 */ unsigned int irq; /* 中斷號 */ unsigned int uartclk; /* 串口時鐘 */ unsigned int fifosize; /* 串口FIFO緩沖大小 */ unsigned char x_char; /* xon/xoff字符 */ unsigned char regshift; /* 寄存器位移

6、*/ unsigned char iotype; /* IO訪問方式 */ unsigned char unused1; #define UPIO_PORT (0) /* IO端口 */ #define UPIO_HUB6 (1) #define UPIO_MEM (2) /* IO內(nèi)存 */ #define UPIO_MEM32 (3) #define UPIO_AU (4) /* Au1x00 type IO */ #define UPIO_TSI (5) /* Tsi108/109 type IO */ #define UPIO_DWAPB (6) /* DesignWare APB U

7、ART */ #define UPIO_RM9000 (7) /* RM9000 type IO */ unsigned int read_status_mask; /* 關(guān)心的Rx error status */ unsigned int ignore_status_mask;/* 忽略的Rx error status */ struct uart_info *info; /* pointer to parent info */ struct uart_icount icount; /* 計(jì)數(shù)器 */ struct console *cons; /* console結(jié)構(gòu)體 */ #ifdef

8、 CONFIG_SERIAL_CORE_CONSOLE unsigned long sysrq; /* sysrq timeout */ #endif upf_t flags; #define UPF_FOURPORT (_force upf_t) (1 1) #define UPF_SAK (_force upf_t) (1 2) #define UPF_SPD_MASK (_force upf_t) (0x1030) #define UPF_SPD_HI (_force upf_t) (0x0010) #define UPF_SPD_VHI (_force upf_t) (0x0020)

9、#define UPF_SPD_CUST (_force upf_t) (0x0030) #define UPF_SPD_SHI (_force upf_t) (0x1000) #define UPF_SPD_WARP (_force upf_t) (0x1010) #define UPF_SKIP_TEST (_force upf_t) (1 6) #define UPF_AUTO_IRQ (_force upf_t) (1 7) #define UPF_HARDPPS_CD (_force upf_t) (1 11) #define UPF_LOW_LATENCY (_force upf_

10、t) (1 13) #define UPF_BUGGY_UART (_force upf_t) (1 14) #define UPF_MAGIC_MULTIPLIER (_force upf_t) (1 16) #define UPF_CONS_FLOW (_force upf_t) (1 23) #define UPF_SHARE_IRQ (_force upf_t) (1 24) #define UPF_BOOT_AUTOCONF (_force upf_t) (1 28) #define UPF_FIXED_PORT (_force upf_t) (1 29) #define UPF_D

11、EAD (_force upf_t) (1 30) #define UPF_IOREMAP (_force upf_t) (1 flags. These are _private_ to serial_core, and * are specific to this structure. They may be queried by low level drivers. */ #define UIF_CHECK_CD (_force uif_t) (1 25) #define UIF_CTS_FLOW (_force uif_t) (1 26) #define UIF_NORMAL_ACTIV

12、E (_force uif_t) (1 29) #define UIF_INITIALIZED (_force uif_t) (1 31) #define UIF_SUSPENDED (_force uif_t) (1 30) int blocked_open; struct tasklet_struct tlet; wait_queue_head_t open_wait; wait_queue_head_t delta_msr_wait; ; 3、uart_ops uart_ops涵蓋了串口驅(qū)動可對串口設(shè)備進(jìn)行的所有操作。 /* * This structure describes all

13、the operations that can be * done on the physical hardware. */ struct uart_ops unsigned int (*tx_empty)(struct uart_port *); /* 串口的Tx FIFO緩存是否為空 */ void (*set_mctrl)(struct uart_port *, unsigned int mctrl); /* 設(shè)置串口modem控制 */ unsigned int (*get_mctrl)(struct uart_port *); /* 獲取串口modem控制 */ void (*sto

14、p_tx)(struct uart_port *); /* 禁止串口發(fā)送數(shù)據(jù) */ void (*start_tx)(struct uart_port *); /* 使能串口發(fā)送數(shù)據(jù) */ void (*send_xchar)(struct uart_port *, char ch);/* 發(fā)送xChar */ void (*stop_rx)(struct uart_port *); /* 禁止串口接收數(shù)據(jù) */ void (*enable_ms)(struct uart_port *); /* 使能modem的狀態(tài)信號 */ void (*break_ctl)(struct uart_por

15、t *, int ctl); /* 設(shè)置break信號 */ int (*startup)(struct uart_port *); /* 啟動串口,應(yīng)用程序打開串口設(shè)備文件時,該函數(shù)會被調(diào)用 */ void (*shutdown)(struct uart_port *); /* 關(guān)閉串口,應(yīng)用程序關(guān)閉串口設(shè)備文件時,該函數(shù)會被調(diào)用 */ void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); /* 設(shè)置串口參數(shù) */ void (*pm)(struct uart_port *,

16、unsigned int state, unsigned int oldstate); /* 串口電源管理 */ int (*set_wake)(struct uart_port *, unsigned int state); /* */ const char *(*type)(struct uart_port *); /* 返回一描述串口類型的字符串 */ void (*release_port)(struct uart_port *); /* 釋放串口已申請的IO端口/IO內(nèi)存資源,必要時還需iounmap */ int (*request_port)(struct uart_port *

17、); /* 申請必要的IO端口/IO內(nèi)存資源,必要時還可以重新映射串口端口 */ void (*config_port)(struct uart_port *, int); /* 執(zhí)行串口所需的自動配置 */ int (*verify_port)(struct uart_port *, struct serial_struct *); /* 核實(shí)新串口的信息 */ int (*ioctl)(struct uart_port *, unsigned int, unsigned long); /* IO控制 */ ; 二、串口驅(qū)動API 1、uart_register_driver /* 功能:

18、uart_register_driver用于將串口驅(qū)動uart_driver注冊到內(nèi)核(串口核心層)中,通常在模塊初始化函數(shù)調(diào)用該函數(shù)。 * 參數(shù) drv:要注冊的uart_driver * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_register_driver(struct uart_driver *drv) 2、uart_unregister_driver /* 功能: uart_unregister_driver用于注銷我們已注冊的uart_driver,通常在模塊卸載函數(shù)調(diào)用該函數(shù) * 參數(shù) drv:要注銷的uart_driver * 返回值: 成功,返回0;否

19、則返回錯誤碼 */ void uart_unregister_driver(struct uart_driver *drv) 3、uart_add_one_port /* 功能: uart_add_one_port用于為串口驅(qū)動添加一個串口端口,通常在探測到設(shè)備后(驅(qū)動的設(shè)備probe方法)調(diào)用該函數(shù) * 參數(shù) drv:串口驅(qū)動 * port:要添加的串口端口 * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 4、uart_remove_one_port

20、 /* 功能: uart_remove_one_port用于刪除一個已添加到串口驅(qū)動中的串口端口,通常在驅(qū)動卸載時調(diào)用該函數(shù) * 參數(shù) drv: 串口驅(qū)動 * port: 要刪除的串口端口 * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 5、uart_write_wakeup /* 功能: uart_write_wakeup喚醒上層因向串口端口寫數(shù)據(jù)而阻塞的進(jìn)程,通常在串口發(fā)送中斷處理函數(shù)中調(diào)用該函數(shù) * 參數(shù) port:需要喚醒寫阻塞進(jìn)程的串口

21、端口 */ void uart_write_wakeup(struct uart_port *port) 6、uart_suspend_port /* 功能: uart_suspend_port用于掛起特定的串口端口 * 參數(shù) drv: 要掛起的串口端口所屬的串口驅(qū)動 * port:要掛起的串口端口 * 返回值: 成功返回0;否則返回錯誤碼 */ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) 7、uart_resume_port /* 功能: uart_resume_port用于恢復(fù)某一已掛起的串口

22、 * 參數(shù) drv: 要恢復(fù)的串口端口所屬的串口驅(qū)動 * port:要恢復(fù)的串口端口 * 返回值: 成功返回0;否則返回錯誤碼 */ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) 8、uart_get_baud_rate /* 功能: uart_get_baud_rate通過解碼termios結(jié)構(gòu)體來獲取指定串口的波特率 * 參數(shù) port: 要獲取波特率的串口端口 * termios:當(dāng)前期望的termios配置(包含串口波特率) * old: 以前的termios配置,可以為NULL * min:

23、 可接受的最小波特率 * max: 可接受的最大波特率 * 返回值: 串口的波特率 */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) 9、uart_get_divisor /* 功能: uart_get_divisor用于計(jì)算某一波特率的串口時鐘分頻數(shù)(串口波特率除數(shù)) * 參數(shù) port:要計(jì)算時鐘分頻數(shù)的串口端口 * baud:期望的波特率 *返回值: 串口

24、時鐘分頻數(shù) */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud) 10、uart_update_timeout /* 功能: uart_update_timeout用于更新(設(shè)置)串口FIFO超時時間 * 參數(shù) port: 要更新超時時間的串口端口 * cflag:termios結(jié)構(gòu)體的cflag值 * baud: 串口的波特率 */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int

25、baud) 11、uart_match_port /* 功能:uart_match_port用于判斷兩串口端口是否為同一端口 * 參數(shù) port1、port2:要判斷的串口端口 * 返回值:不同返回0;否則返回非0 */ int uart_match_port(struct uart_port *port1, struct uart_port *port2) 12、uart_console_write/* 功能: uart_console_write用于向串口端口寫一控制臺信息 * 參數(shù) port: 要寫信息的串口端口 * s: 要寫的信息 * count: 信息的大小 * putchar:

26、用于向串口端口寫字符的函數(shù),該函數(shù)函數(shù)有兩個參數(shù):串口端口和要寫的字符 */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, void (*putchar)(struct uart_port *, int) 三、串口驅(qū)動例子 該串口驅(qū)動例子是我針對s3c2410處理器的串口2(uart2)獨(dú)立開發(fā)的。因?yàn)槲彝ㄟ^博創(chuàng)2410s開發(fā)板的GRPS擴(kuò)展板來測試該驅(qū)動(已通過測試),所以我叫該串口為gprs_uart。 該驅(qū)動將串口看作平臺(platform)設(shè)備。platform可以看

27、作一偽總線,用于將集成于片上系統(tǒng)的輕量級設(shè)備與Linux設(shè)備驅(qū)動模型聯(lián)系到一起,它包含以下兩部分(有關(guān)platform的聲明都在#include ,具體實(shí)現(xiàn)在drivers/base/platform.c): 1、platform設(shè)備。我們需要為每個設(shè)備定義一個platform_device實(shí)例 struct platform_device const char *name; /* 設(shè)備名 */ int id; /* 設(shè)備的id號 */ struct device dev; /* 其對應(yīng)的device */ u32 num_resources;/* 該設(shè)備用有的資源數(shù) */ struct re

28、source *resource; /* 資源數(shù)組 */ ; 為我們的設(shè)備創(chuàng)建platform_device實(shí)例有兩種方法:填充一個platform_device結(jié)構(gòu)體后用platform_device_register(一次注冊一個)或platform_add_devices(一次可以注冊多個platform設(shè)備)將platform_device注冊到內(nèi)核;更簡單的是使用platform_device_register_simple來建立并注冊我們的platform_device。 2、platform驅(qū)動。platform設(shè)備由platform驅(qū)動進(jìn)行管理。當(dāng)設(shè)備加入到系統(tǒng)中時,platf

29、orm_driver的probe方法會被調(diào)用來見對應(yīng)的設(shè)備添加或者注冊到內(nèi)核;當(dāng)設(shè)備從系統(tǒng)中移除時,platform_driver的remove方法會被調(diào)用來做一些清理工作,如移除該設(shè)備的一些實(shí)例、注銷一些已注冊到系統(tǒng)中去的東西。struct platform_driver int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device

30、 *, pm_message_t state); int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; ; 更詳細(xì)platform資料可參考網(wǎng)上相關(guān)文章。 例子驅(qū)動中申請和釋放IO內(nèi)存區(qū)的整個過程如下: insmod gprs_uart.kogprs_init_module()uart

31、_register_driver()gprs_uart_probe() uart_add_one_port()gprs_uart_config_port()gprs_uart_request_port()request_mem_region()rmmod gprs_uart.kogprs_exit_module()uart_unregister_driver()gprs_uart_remove()uart_remove_one_port()gprs_uart_release_port()release_mem_region()例子驅(qū)動中申請和釋放IRQ資源的整個過程如下:open /dev/g

32、prs_uartgprs_uart_startup()request_irq()close /dev/gprs_uartgprs_uart_shutdown()free_irq()想了解更詳細(xì)的調(diào)用過程可以在驅(qū)動模塊各函數(shù)頭插入printk(KERN_DEBUG %sn, _FUNCTION_);并在函數(shù)尾插入printk(KERN_DEBUG %s donen, _FUNCTION_); 下面是串口驅(qū)動例子和其GPRS測試程序源碼下載地址: #include #include #include /* printk() */ #include /* kmalloc() */ #include

33、/* everything. */ #include /* error codes */ #include /* size_t */ #include /* O_ACCMODE */ #include /* cli(), *_flags */ #include /* copy_*_user */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define

34、 DEV_NAME gprs_uart /* 設(shè)備名 */ /* 這里將串口的主設(shè)備號設(shè)為0,則串口設(shè)備編號由內(nèi)核動態(tài)分配;你也可指定串口的設(shè)備編號 */ #define GPRS_UART_MAJOR 0 /* 主設(shè)備號 */ #define GPRS_UART_MINOR 0 /* 次設(shè)備號 */ #define GPRS_UART_FIFO_SIZE 16 /* 串口FIFO的大小 */ #define RXSTAT_DUMMY_READ (0x10000000) #define MAP_SIZE (0x100) /* 要映射的串口IO內(nèi)存區(qū)大小 */ /* 串口發(fā)送中斷號 */ #de

35、fine TX_IRQ(port) (port)-irq + 1) /* 串口接收中斷號 */ #define RX_IRQ(port) (port)-irq) /* 允許串口接收字符的標(biāo)志 */ #define tx_enabled(port) (port)-unused0) /* 允許串口發(fā)送字符的標(biāo)志 */ #define rx_enabled(port) (port)-unused1) /* 獲取寄存器地址 */ #define portaddr(port, reg) (port)-membase + (reg) /* 讀8位寬的寄存器 */ #define rd_regb(port,

36、 reg) (ioread8(portaddr(port, reg) /* 讀32位寬的寄存器 */ #define rd_regl(port, reg) (ioread32(portaddr(port, reg) /* 寫8位寬的寄存器 */ #define wr_regb(port, reg, val) do iowrite8(val, portaddr(port, reg); while(0) /* 寫32位寬的寄存器 */ #define wr_regl(port, reg, val) do iowrite32(val, portaddr(port, reg); while(0) /*

37、 禁止串口發(fā)送數(shù)據(jù) */ static void gprs_uart_stop_tx(struct uart_port *port) if (tx_enabled(port) /* 若串口已啟動發(fā)送 */ disable_irq(TX_IRQ(port); /* 禁止發(fā)送中斷 */ tx_enabled(port) = 0; /* 設(shè)置串口為未啟動發(fā)送 */ /* 使能串口發(fā)送數(shù)據(jù) */ static void gprs_uart_start_tx(struct uart_port *port) if (!tx_enabled(port) /* 若串口未啟動發(fā)送 */ enable_irq(T

38、X_IRQ(port); /* 使能發(fā)送中斷 */ tx_enabled(port) = 1; /* 設(shè)置串口為已啟動發(fā)送 */ /* 禁止串口接收數(shù)據(jù) */ static void gprs_uart_stop_rx(struct uart_port *port) if (rx_enabled(port) /* 若串口已啟動接收 */ disable_irq(RX_IRQ(port); /* 禁止接收中斷 */ rx_enabled(port) = 0; /* 設(shè)置串口為未啟動接收 */ /* 使能modem的狀態(tài)信號 */ static void gprs_uart_enable_ms(s

39、truct uart_port *port) /* 串口的Tx FIFO緩存是否為空 */ static unsigned int gprs_uart_tx_empty(struct uart_port *port) int ret = 1; unsigned long ufstat = rd_regl(port, S3C2410_UFSTAT); unsigned long ufcon = rd_regl(port, S3C2410_UFCON); if (ufcon & S3C2410_UFCON_FIFOMODE) /* 若使能了FIFO */ if (ufstat & S3C2410_UFSTAT_TXMASK) != 0 | /* 0 FIFO lock, flags); ucon = rd_regl(port, S3C2410_UCON); if (break_state) ucon |= S3C2410_UCON_SBREAK; else ucon &= S3C2410_UCON_SBREAK; wr_regl(port, S3C2410_UCON, ucon); spin_u

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論