linux led驅動詳解【轉】

一 leds的驅動程序

位置:linux 2.6.29/drivers/char/mini2440_leds.c

#include
#include

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


#define DEVICE_NAME "leds" //定義驅動程序的名字爲leds

static unsigned long led_table [] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};                                                   //定義引腳的寄存器數組(無符號長整形,對應於引腳的地址)

static unsigned int led_cfg_table [] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};                                               //定義引腳功能,爲輸出(無符號整形)

static int sbc2440_leds_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
switch(cmd) {
case 0:
case 1:
   if (arg > 4) {                                 //設備節點,文件描述符,LED燈編號,LED燈狀態四個命令參數
    return -EINVAL;
   }
   s3c2410_gpio_setpin(led_table[arg], !cmd);
   return 0;
default:
   return -EINVAL;                           //EINVAL:表示向函數傳遞了無效的參數(errno符號變量)
}
}

//初始化字符設備驅動的file_operations 的結構體

static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.ioctl = sbc2440_leds_ioctl,
};

static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,                    /* 動態設備號 */
.name = DEVICE_NAME,                                  /* 將在/dev目錄生成led設備 */
.fops = &dev_fops,                                            /* 驅動接口 */

};

static int __init dev_init(void)
{
int ret;

int i;

for (i = 0; i < 4; i++) {

/*設置GPIO對應的配置寄存器GPIOCON爲輸出狀態*/
  
   s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

/*設置GPIO對應的數據寄存器GPIODAT爲低電平, 在模塊加載結束後,四個LED應該是全部都是發光狀態*/

s3c2410_gpio_setpin(led_table[i], 0);
}

//註冊設備

ret = misc_register(&misc);

printk (DEVICE_NAME"/tinitialized/n");

return ret;
}

//註銷設備驅動

static void __exit dev_exit(void)
{
misc_deregister(&misc);
}

module_init(dev_init);                                              /*聲明加載模塊初始化函數*/
module_exit(dev_exit);                                           /*聲明卸載模塊清除函數*/
MOUDLE_LICENSE("GPL");                                     /*許可證聲明*/
MODULE_AUTHOR("FriendlyARM Inc.");                /*作者信息*/

1 static 關鍵字的重要性

      全局變量和函數全部用static 進行修飾,則其作用的範圍僅僅限於當前的文件,而不是整個系統。防止編譯器在連接時,會報告命名錯誤的“名字空間污染”的問題。

2 ioctl()函數

static int sbc2440_leds_ioctl(struct inode *inode, struct file *file,   unsigned int cmd, unsigned long arg)

      ioctl函數是文件結構中的一個屬性分量。ioctl是設備驅動程序中對設備的I/O通道進行管理的函數。所謂對I/O通道進行管理,就是對設備的一些特性進行控制,例如串口的傳輸波特率、馬達的轉速等等。
     struct inode *inode,是設備節點號。fd就是用戶程序打開設備時使用open函數返回的文件標示符,cmd就是用戶程序對設備的控制命令,unsigned long arg是控制命令的個數。
      驅動程序提供了對ioctl的支持,用戶就可以在用戶程序中使用ioctl函數控制設備的I/O通道。如果函數返回一個非負值,那麼該值會被返回給調用程 序,表示成功。韓式一般通過switch{case}對設備的一些特性進行控制。switch{case}結構,每一個case對應一個命令碼,做出一些 相應的操作。在本例中的cmd有兩個可選項0和1.0表示燈滅,1表示燈亮。所以case 0,1都要進行操作。由於實際的硬件連接中,是低電平燈亮。所以在對引腳賦值時要取反。 s3c2410_gpio_setpin(led_table[arg], !cmd)

3 static int __init dev_init(void)
_init 宏,定義在include/linux/init.h中。對於非模塊加載的驅動程序,通過_init 宏,會把函數中的代碼放到.text.init段。這個段在系統啓動後會被釋放。這樣函數代碼只有在啓動時執行一次,所以可以釋放它們以節省內存空間,

3初始化字符設備驅動的file_operations 的結構體

結構體file_operations 在頭文件 linux/fs.h 中定義,用來存儲驅動內核模塊提供的對 設備進行各種操作的函數的指針。該結構體的每個域都對應着驅動內核模塊用來處理某個被請求的 事務的函數的地址

4ret = misc_register(&misc);

misc_register()用主編號10調用 register_chrdev(),設備名稱和函數表指針通過miscdevice數據結構獲得。同樣,miscdevice 數據結構還保存設備驅動程序所使用的次要號碼。完成設備的註冊。

5 printk()

利用 printk可以實現內核到Linux 控制檯的格式化輸出。其用法與標準C的printf類似。在調用驅動程序時,依靠printk輸出信息跟蹤程序,是很有效的方法。與標準C的printf 不同的是,printk支持分級輸出。默認爲第四級的輸出KERN_ERR。

二 LED測試程序

/opt/FriendlyARM/mini2440/examples/leds

#include                               /*下面函數要用到的頭文件*/
#include
#include
#include

int main(int argc, char **argv)                 /*運行時參數傳遞,開或關哪個LED*/
{                                              
int on;                                                   /*定義led狀態變量,1表示燈亮,2表示燈滅*/
int led_no;                                           /*定義led變量--哪個led*/
int fd;                                                     /*定義led設備文件描述符的變量*/
if (                         argc != 3 || /             /*判斷命令輸入參數個數*/
        sscanf(argv[1], "%d", &led_no) != 1 || /                   /* 第一個字符串參數表示要操作led*/

sscanf(argv[2],"%d", &on) != 1 || /                                  /*第2個字符串參數作爲LED狀態*/
                       on < 0 || on > 1 || /                                           /*開和關,兩個狀態*/
                led_no < 0 || led_no > 3 ) /                                     /*4個LED*/
{
fprintf(stderr, "Usage: leds led_no 0|1/n");                       /*如果條件不滿足輸出出錯信息*/
exit(1);                                                                               /*退出程序,返回1,表示出現錯誤*/
}
fd = open("/dev/leds0", 0);                   /*爲只讀打開leds0文件,取出文件描述符*/
if (fd < 0) {                                
   fd = open("/dev/leds", 0);                  /*如果打開leds0出錯,再以只讀方式打開leds文件*/
}
if (fd < 0) {
   perror("open device leds");                  /*如果打開led文件出錯,拿不到文件描述符,用perror宏輸出錯原因及信息*/
exit(1);                                                /*出錯退出*/
}
ioctl(fd, on, led_no);                          /*用ioctl()函數控制LED,其中fd--是前面打開的LED文件描述符,on--是開關命令0和1,led_no--是哪個LED*/
close(fd);                                           /*關閉LED描述符,與前面open()對應*/
return 0;                                            /*正常返回*/
}

說 明:sscanf() - 從一個字符串中讀進與指定格式相符的數據. sscanf與scanf類似,都是用於輸入的,只是後者以鍵盤(stdin)爲輸入源,前者以固定字符串爲輸入源。其中的format可以是一個或多個 {%[*] [width] [{h | l | I64 | L}]type | '''' '''' | ''''/t'''' | ''''/n'''' | 非%符號}

sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||

表示從argv[1](argv[2])讀字符,並轉換成整形給led_no(on)。               

三 Makefile

CROSS=arm-linux-                            #定義變量CROSS

all: led

led: led.c                                          #定義led的規則
$(CROSS)gcc -o led led.c              #這句把CROSS變量替換,可以還原成arm-linux-gcc -o led led.c

clean:
@rm -vf led *.o *~                              #rm指令可刪除 -v表示顯示指令執行過程 -f表示強制文件或目錄

參考鏈接

http://hi.baidu.com/wjtao291/blog/item/eed5f8119e001c11b8127b65.html

http://blog.chinaunix.net/u2/88438/showart_1973209.html

http://www.imganquan.org/code/modules/mini2440_leds.c.html

http://baike.baidu.com/view/1364018.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章