1. 程式人生 > >初次動手編寫驅動——LED在linux中的驅動。

初次動手編寫驅動——LED在linux中的驅動。

今天第一次自己嘗試編寫驅動,看了這麼長時間視訊,第一次動手,編寫的是簡單的LED的程式。從簡單到複雜一個一個來。

編寫驅動的順序是先從註冊函式和解除安裝函式起始:

static int led_init()
{
cdev_init(&cdev, &led_fops);
alloc_chrdev_region(&devno, 0, 1,"led");
cdev_add(&cdev, devno, 1);

return 0;
}
static int led_exit()
{cdev_del(&cdev);
unregister_chrdev_region(devno,1);
}
module_init(led_init);
module_exit(led_exit);

先把框架撘起來,然後在填充。在模組init的函式中如定義cdev,定義file_operations,初始化cdev,新增cdev,因為新增cdev要用到裝置編號,所以在新增cdev前要註冊裝置號 devno。在模組解除安裝函式中需要刪除cdev,登出裝置號。

本次LED驅動十分簡單,只用到了open和ioctl函式。建立LED.h 檔案,定義ioctl要用的到命令:

#define LED_MAGIC 'L'       //定義L作為幻數
#define LED_ON _IO(LED_MAGIC,1)     //不需要傳遞引數,所以用_IO來定義兩個命令
#define LED_OFF _IO(LED_MAGIC,0)

然後編寫led_open 函式和led_ioctl函式,完成驅動

原始碼:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include "LED.h"


#define LEDCON 0x56000010 
#define LEDDATA 0x56000014
unsigned int *led_config; 
unsigned int *led_data; 


struct cdev cdev;
 dev_t devno;


static int led_open (struct inode *inode, struct file *filp)
{
led_config=ioremap(LEDCON,4);
iowrite32(0x00015400,led_config);
led_data=ioremap(LEDDATA,4);

return 0;
}
static int led_ioctl(struct inode *inode, struct file *flip, unsigned int cmd, unsigned long arg)
{
switch(cmd){
case LED_ON :
iowrite32(0x00,led_data);
return 0;
case LED_OFF :
iowrite32(0xff,led_data);
return 0;
default :
return -EINVAL;}
}


 struct file_operations led_fops=
{
 .open = led_open,
 .ioctl = led_ioctl,
};

static int led_init()
{
cdev_init(&cdev, &led_fops);
alloc_chrdev_region(&devno, 0, 1,"led");
cdev_add(&cdev, devno, 1);

return 0;
}
static int led_exit()
{cdev_del(&cdev);
unregister_chrdev_region(devno,1);
}
module_init(led_init);
module_exit(led_exit);

其中struct file_operations led_fops的賦值和初始化要放到led_open和led_ioctl的後面,如果放在前面編譯時會提示沒有定義。如下:


關於ioctl:

ioctl命令:

定義命令 定義ioctl命令的正確方法是使用4 個位段,這個列表中介紹的符號定義在中: Type 幻數(型別):表明哪個裝置的命令,在參考了ioctl-number.txt之後選出,8位寬。 Number 序號,表明裝置命令中的第幾個,8位寬。 Direction 資料傳送的方向,可能的值是_IOC_NONE(沒有資料傳輸),_IOC_READ,_IOC_WRITE。資料傳送是從應用程式的觀點來看待的,_IOC_READ意思是從裝置讀。 size 使用者資料的大小。(13/14位寬,視處理器而定) 核心提供了下列巨集來幫助定義命令: _IO(type,nr); 沒有 引數的命令 _IOR(type,nr,datatype) 從驅動中讀取資料 _IOW(type,nr,datatype) 寫資料到驅動 _IOWR(type,nr,datatype) 雙向傳送,type和number成員作為引數被傳遞。點選開啟連結

http://blog.chinaunix.net/uid-25014876-id-59419.html  ioctl的學習

在開發板中執行應用程式時,可能會提示你缺少許可權如圖:

使用chmod 777 led_app 就可以解決了

在應用程式執行的過程中出現了一下錯誤


這種錯誤說是由於記憶體洩露什麼的,在網上百度了幾篇關於Oops的文章,大概看懂了,但是對於新手來說,具體操作還是有點難有興趣的可以看一下這個http://blog.chinaunix.net/uid-14753126-id-2980100.html

由於驅動簡單,我選擇了一個比較笨又好用的方法,因為我的驅動是根據視訊一步一步寫的,所以直接和視訊中的程式對照,果然發現了,我驅動函式中的open函式和模組初始化函式都少了一句return 0; 加上之後問題就解決了。這裡就有疑惑了,為什麼這個return 0 必須要?為什麼模組解除安裝函式裡面不用要呢?沒有百度到結果,先記下來,以後問高手。加上之後