前面已经记录学习了LED驱动程序的代码分析,并且成功将驱动模块加载到了开发板,现在就可以进行LED应用程序的测试啦!
测试代码如下:
/*-------LED流水灯测试程序-------*/
#include <stdio.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#define LED_CNT 4
#define DEVNAME_LEN 10
/*定义一个魔数。魔数有着特殊的功能。我们定义了led_on和led_off,但是这个宏定义可能和系统的别的重复,因此我们采用魔数机制,定义一个系统未用的魔数,然后让魔数生成我们定义的led_on和led_off,这样,我们的定义就不会和系统的相同了。*/
#define PLATDRV_MAGIC 0x60
#define LED_OFF _IO (PLATDRV_MAGIC, 0x18)
#define LED_ON _IO (PLATDRV_MAGIC, 0x19)
int main (int argc, char **argv)
{
int i;
int fd[LED_CNT];
char dev_name[DEVNAME_LEN]={0,0,0,0};
for(i=0; i<LED_CNT; i++)
{
snprintf(dev_name, sizeof(dev_name), "/dev/led%d", i);
fd[i] = open(dev_name, O_RDWR, 0755);
if(fd[i] < 0)
goto err;
}
while(1)
{
for(i=0; i<LED_CNT; i++)
{
ioctl(fd[i], LED_ON);
sleep(1);
}
for(i=0; i<LED_CNT; i++)
{
ioctl(fd[i], LED_OFF);
sleep(1);
}
}
for(i=0; i<LED_CNT; i++)
{
close(fd[i]);
}
return 0;
err:
for(i=0; i<LED_CNT; i++)
{
if(fd[i] >= 0)
{
close(fd[i]);
}
}
return -1;
} /* ----- End of main() ----- */
最终开发板上的LED灯从LED0开始到LED3依次亮起,再熄灭。
总结:
1、要理解应用程序、库、内核、驱动程序之间的关系:
2、linux是如何执行一个外设的,以我们的LED程序为例:
(1)应用程序使用库函数open打开LED的设备文件。
(2)库传入的执行软中断SWI指令,引起CPU异常,进入内核。
(3)内核的异常处理函数根据这些参数找到相应的驱动程序,返回一个文件句柄fd给库,进而返回给应用程序。
(4)应用程序获取这个fd,使用库提供的控制函数ioctl或者write发出控制指令。
(5)库根据write或ioctl函数传入的参数执行SWI指令,引起CPU异常,进入内核。
(6)内核的异常处理函数根据这些参数调用驱动程序的相关函数,点亮LED。
3、在开发板/dev目录创建设备节点,再执行./LED_test。
>: mknod /dev/led0 c 250 0
>: mknod /dev/led1 c 250 1
>: mknod /dev/led2 c 250 2
>: mknod /dev/led3 c 250 3
命令中的250是我的LED的设备号,不同情况可能设备号不同,可以用
>: cat /proc/devices
查看一下自己的设备号。