转载自: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
就可以看到流水灯闪动了。