串口驅動程序的編寫總結(一)


 8250/16450/16550芯片都用同個8250驅動

1、對現有驅動進行拷貝,然后進行局部修改

2、不必過多深入系統內核驅動的調用過程,區分好哪些是需要修改的,哪些是內核驅動自帶的
3、對於要修改的內容,參考別人成功的例子,看哪些需要修改的
4、必要時,可以先把原拷貝先不加載進驅動,把自己拷貝的驅動加載進去
5、謹記要實現的功能,按步驟實現
6、知道每個模塊的作用與功能,哪些是涉及硬件,哪些是涉及系統的,一般來說,進行設備、驅動的注冊時,一般不涉及驅動,只有應用層調用時才進行硬件的相關調用。

 

 

7、對串口驅動程序的改造時如果是采用外部模塊加載的方式,即insmod方式,而不是內置於內核生成vmlinux,則不能使用console驅動,否則編譯會出現

 error: redefinition of '__inittest'
/opt/kangear/hello/hello.c:16: note: previous definition of '__inittest' was here
錯誤,會出現重定義的情況。

解決方法:去除console的相關驅動,屏蔽console_initcall()函數的調用


8、對串口的發送的配置屬性,最終調用底層驅動的ioctl函數。而ioctl函數得執行copy_from_user、copy_to_user函數進行用戶與內核之間的數據拷貝,而在ioctl函數執行這些操作后,底層的驅動程序才能繼續對配置參數(波特率、數據位、停止位、檢驗位....)的設置

9、在用戶層面操作open()函數時,會調用底層驅動的一系列默認配置參數,這是在uart_core.c文件里進行屬性的配置


10、中斷有分系統中斷與外部中斷, 系統中斷在一開機時就已經初始好,而外部中斷是在驅動程序啟動時調用,而中斷的觸發是靠硬件進行中斷請求,cpu響應進行處理

 

 

 

驅動詳解:

 

1、在串口驅動中, 中斷的產生都是用戶態所觸發引起的。在底層接收到中斷后會進行數據往上推送或往底層數據硬件進行發送

    具體可參看文章:http://blog.csdn.net/hui523hui523hui523/article/details/7521981

2、在強類型的C語言里,要嚴格區分雙引號與單引號,雙引號是一個指針,單引號代表的是一個值。

    例如: 

          unsigned char a = "1";  
          unsigned char a='1';

  在弱類型的語言里,雙引號與單引號是混合用。例如php、asp、js。

3、usb總線協議規定的是底層硬件的通訊協議,在其上層還有其它各種各樣的通訊協議,有低速、高速設備的協議 ,其中包括hid協議 。

    hid協議是一種低速通訊的usb通訊,HID類設備屬於人機交互操作的設備。 可用於鍵盤、鼠標等

4、底層數據是如何進行獲取的往上推送的

     通過用戶層通過read時調用到底層的函數serial8250_handle_irq(),接着調用serial8250_rx_chars()進行數據接收及上層推送

5、C語言的.h與.c文件。.h文件主要是用來聲明,一般不用來開辟內存空間。.c文件主要用來分配內存空間,初始化全局變量及靜態變量。

     由於設置為全局變量,在一個進程的內存空間是全局可見的。

    一個.c文件要調用另一個.c文件的全局變量、靜態變量時,需通過加入extern關鍵詞。

    例如:

      a.c 文件

      int m_gmsr = 1;

  static m_socr = 2;

     b.c文件

     extern int m_gmsr;

     m_gmsr = 2;

    一個.c文件要調用另一個.c文件的函數時,只需要包含其該.c文件的頭文件即可

    

6、C語言將聲明與定義區分開,即將.c文件與.h文件區分開的好處是:

    當在.c文件的一個函數另外該文件的另一個函數時,可解決其依賴關系,而不會出錯。

   例如:

    a.c文件

    

   int diff(int a,int b)

  {

      return a>b?a:b;

   }

    int max(int a,int b)

  { 

         return diff(a,b);

     }

如果沒有定義頭文件,diff函數要放在max函數前面,否則會出現undefined symbol diff函數的情況。在頭文件聲明這兩個函數,則不會出現因位置而編譯出錯,具體是什么原因呢?

具體參看鏈接:http://www.cnblogs.com/webcyz/archive/2012/09/16/2688035.html

 

7、在C語言中,多使用類似這樣

#ifndef XXX
#define XXX

#endif

 

8、多個文件編譯成內核模塊

  參看鏈接:http://blog.csdn.net/alex_xhl/article/details/5719230

     類似:

obj-m +=sahuLB.o 
sahuLB-objs:=simpLB.o sahu_lb_tools.o
all:
  make -C /lib/modules/`uname -r`/build M=`pwd`
clean:
  make -C /lib/modules/`uname -r`/build M=`pwd` clean
install:
  /sbin/insmod sahuLB.ko
remove:
  /sbin/rmmod sahuLB

標記紅色部分要相同,而且生成的模塊名不能與任何源文件的相同

 

9、有些硬件芯片不支持多次復位,就如sja1000芯片。如果要寫驅動調用sja1000芯片,則不能用原先的sja1000芯片的驅動程序。

10、掛載在platform總線的硬件,可通過linux提供的函數的request_irq()進行中斷的請求,相當於注冊了一個回調函數,硬件寄存器通過中斷來通知內核。中斷是一種電信號,由硬件設備生成,並送入中斷控制器 的輸入引腳中,中斷控制器會給CPU發送一個電信號,CPU檢測到這個信號,就中斷當 前的工作轉而處理中斷。每個中斷都通過一個唯一的數字標志

         

11、打印字符數組時,char a[]="123"; 不能用printf("%s\n",a);這種方式,因為會導致沒遇到結束符"\0",而不斷的打印數據 

 

12、

模塊編譯的過程:

my_uart_can: Unknown symbol uart_console_device (err 0)

my_uart_can: Unknown symbol platform_device_put (err 0)
my_uart_can: Unknown symbol uart_parse_options (err 0)
my_uart_can: Unknown symbol serial8250_do_shutdown (err 0)
my_uart_can: Unknown symbol serial8250_handle_irq (err 0)
my_uart_can: Unknown symbol platform_driver_unregister (err 0)
my_uart_can: Unknown symbol serial8250_modem_status (err 0)
my_uart_can: Unknown symbol platform_device_unregister (err 0)
my_uart_can: Unknown symbol uart_set_options (err 0)
my_uart_can: Unknown symbol platform_device_add (err 0)
my_uart_can: Unknown symbol platform_device_alloc (err 0)
my_uart_can: Unknown symbol platform_device_del (err 0)
my_uart_can: Unknown symbol __platform_driver_register (err 0)
my_uart_can: Unknown symbol serial8250_tx_chars (err 0)
my_uart_can: Unknown symbol nr_irqs (err 0)
my_uart_can: Unknown symbol uart_console_write (err 0)

解決方法:

加入MODULE_LICENSE("Dual BSD/GPL");以支持模塊引用GPL的符號

 

13、

錯誤:
/home/nfs/drivers/can_uart/8250_core.c:3758: error: redefinition of '__inittest'
/home/nfs/drivers/can_uart/8250_core.c:3298: error: previous definition of '__inittest' was here
/home/nfs/drivers/can_uart/8250_core.c:3758: error: redefinition of 'init_module'
/home/nfs/drivers/can_uart/8250_core.c:3298: error: previous definition of 'init_module' was here
scripts/Makefile.build:263: recipe for target '/home/nfs/drivers/can_uart/8250_core.o' failed

解決方法及原因:

是console_initcall所引起的,
__inittest是由console_initcall所引起的

在串口作為模塊進行加載時,是不能兩個驅動存在,console_initcall() 及 module_init()不能同時存在,不能同時存在這兩個入口函數。

而將串口驅動程序編譯進內核,則可以存在多個入口函數。 console()控制台驅動是為了實現將串口當作控制台實現。

 

14、串口的波特率、停止位、數據位、檢驗位理解

     波特率:即單位時間內振盪的次數,也即單位時間內發送多少bit的數據

     停止位:主要是為了區分上次所發送的數據完畢所加上的位

     數據位:對用戶發送的一個字節,從低位開始取多少位,比如: 十進制值:31, bit位:00011111。 當數據位設為5時,則bit位變為00001111。用戶接收到的十進制值:15。

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM