原創作品轉載請注明出處
http://blog.csdn.net/cediy2088long?viewmode=contents
學習嵌入式linux程式設計,我們接觸到的大多是linux裝置驅動程式的程式設計。今天我就給大家簡單的分析一下飛淩的led驅動程式,有了我們前面led的裸機的程式的基礎,這個led的驅動也就簡單多了。
大家最好是看一下linux裝置驅動程式一書的前六章,這樣不會對linux中的led中的一些函數太陌生。首先要對linux的字元裝置驅動架構有一個大概的了解。
打開linux的源碼目錄,找到drivers/char/s3c6410-led.c
打開看一下源碼。裡邊的函數都不難。
主要的函數實作就是下面這個函數,我們在使用者空間調用的時候也是最終調用到這個函數
#define DEVICE_NAME "leds"
static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
unsigned tmp;
case 0:
case 1:
if (arg > 4)
{
return -EINVAL;
}
tmp = readl(S3C64XX_GPMDAT);
if(cmd==0) //close light
{
tmp &= (~(1<<arg));
}
else //open light
{
tmp |= (1<<arg);
}
writel(tmp,S3C64XX_GPMDAT);
printk (DEVICE_NAME": %d %d\n", arg, cmd);
return 0;
default:
return -EINVAL;
}
}
那麼是如何映射到使用者空間的呢?
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = s3c6410_leds_ioctl,
};
原來在這裡。
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
unsigned tmp;
//gpm0-3 pull up
tmp = readl(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xaa;
writel(tmp,S3C64XX_GPMPUD);
//gpm0-3 output mode
tmp =readl(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
writel(tmp,S3C64XX_GPMCON);
//gpm0-3 output 0
tmp = __raw_readl(S3C64XX_GPMDAT);
tmp |= 0x10;
writel(tmp,S3C64XX_GPMDAT);
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);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FORLINX Inc.");
上面是初始化部分和注冊裝置。代碼很簡單,就不多說了。
如何把這個編譯進入核心呢?
還有再給大家說一下怎麼來把led驅動加到核心中呢,linux的編譯用的是makefile管理的,初學者對于makefile的基本結構要知道一些,不用把整個makefile的文檔都看一遍,但也要把知道大概, makefile的格式規則是這樣的
target : prerequisites
command
我們打開char目錄下的makefie看一下,
這一行是把led的驅動加入核心的關鍵,而我們在編譯的時候要配置是加入核心還是編譯成子產品呢,我們運作make menuconfig的時候是怎麼出現的配置的呢?這個要看我們的Kconfig檔案
這個就是我們在make menuconfig 的時候的配置選項。
進入到Device DriversàCharacter devices找到LedS driver forlinx6410
我們選上這一項就是編譯進核心,如果是M,就是要編譯成子產品,可以動态加載,如果是空就是不編譯。Makemenuconfig的時候就是如何剪裁作業系統了,我們可以把不需要的或者沒有必要的驅動不選上,重新編譯,就可以得到自己剪裁過的核心了
這樣就會在dev目錄下生成一個led裝置了。這樣驅動部分就好了。我們如何測試我們的led能用呢?
寫個流水燈吧
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<unistd.h>
sleeps(int j){
int i=0,m=0;
for(i=0;i<j;i++){
for(m=0;m<100000;m++){
}
}
}
int main(void){
int i,fd;
fd=open("/dev/leds",O_RDWR);
if(fd == -1)
exit(1);
for(i=0;i<4;i++){
ioctl(fd,0,i);
sleeps(100);
ioctl(fd,1,i);
if(i == 3)
i=0;
}
}
編譯一下這個程式,
arm-linux-gcc -o ledtest ledtest.c -static
就可以生成ledtest,注意如果把arm-linux-gcc的路徑加到PATH環境變量中去,否則會出現找到不指令的錯誤。
把ledtest通過序列槽發到開發闆中,因為沒有執行權限,先運作chmod 777 ledtest
然後再./ledtest
就可以看到流水燈閃動了。