在mini6410中,LED驱动程序是第一个操作硬件相关的驱动程序。对于以后的嵌入式linux驱动程序起到一定的引导作用
在操作所用到的mini6410的I/O口之前,就需要设置他们用到的寄存器。
我们需要调用一些现成的函数或者宏,在此用到的是 readl 和 writel,它们将直接对相应的寄存器执行读取和写入的操作。相关的寄存器如下
除此之外,还需要调用一些和设备驱动密切相关的基本函数,如注册设备misc_register,填写驱动函数结构file_operations,以及module_init 和 module_exit 函数等。
misc为混杂设备驱动,什么是混杂设备驱动呢?
在LInux系统中,存在一类字符设备,它们共享一个人主设备号(10),但次设备号不同,我们称这类设备为混杂设备。所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的miscdevice设备。
不像2440一样,2440在操作GPIO口的时候直接调用相关封装好的函数即可进行GPIO的配置、置位,复位操作。mini6410的GPIO需要对寄存器进行配置。
相关的led驱动程序代码如下:
#include
#include
#include
//#include
#include
#include
#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"
//
static long sbc2440_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_GPKDAT);
tmp &= ~(1 << (4 + arg));
tmp |= ( (!cmd) << (4 + arg) );
//设置寄存器的值
writel(tmp, S3C64XX_GPKDAT);
//printk (DEVICE_NAME": %d %d
", arg, cmd);
return 0;
default:
return -EINVAL;
}
}
//文件操作设备机构体 file_operations
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = sbc2440_leds_ioctl,
};
//注册led驱动为MISC设备
static struct miscdevice misc = {
//动态设备号 混杂设备主设备号为10
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME, //设备名
.fops = &dev_fops,
};
static int __init dev_init(void) //设备初始化
{
int ret;
{
unsigned tmp;
tmp = readl(S3C64XX_GPKCON); //将四个LED端口寄存器设置为输出
tmp = (tmp & ~(0xffffU<<16))|(0x1111U<<16);
writel(tmp, S3C64XX_GPKCON);
tmp = readl(S3C64XX_GPKDAT); //设置四个led端口寄存器设置为高电平输出,在模块加载后,四个LED不发光
tmp |= (0xF << 4);
writel(tmp, S3C64XX_GPKDAT);
}
ret = misc_register(&misc); // 注册混杂设备,驱动加载后会在/dev目录自动生成设备文件/dev/DEVICE_NAME(混杂设备的一个特点,主设备号为10,次设备号自动动态分配)
printk (DEVICE_NAME" initialized
");打印初始化信息
return ret;
}
//模块退出
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("silence_Z");
以上为LED的驱动程序,如果按模块安装的话,需要编写MakeFile
MakeFile代码如下:
ifneq ($(KERNELRELEASE),)
obj-m := leds.o
else
KDIR := /home/zhangbin/mini6410/linux-2.6.38
all:
make -C $(KDIR) M=$(PWD)
clean:
rm -f *.ko *.o *.mod.c *.symvers *.order
endif
之后通过执行make nfs文件系统可以在mini6410开发板上进行模块的安装并且测试
root@xxx:inmod leds.ko
root@xxx:lsmod
为了对LED驱动程序进行测试,要编写应用程序:
#include
#include
#include
#include
int main(int argc,char **argv)
{
int on;
int led_no;
int fd;
if(argc !=3 || sscanf(argv[1],"%d",&led_no) != 1
|| sscanf(argv[2],"%d",&on) != 1 || on < 0 || on > 1 || led_no < 0
|| led_no > 3)
{
fprintf(stderr,"Usage:leds led_no 0|1
");
exit(1);
}
fd = open("/dev/leds",0);
if(fd < 0)
{
perror("open device leds");
exit(1);
}
ioctl(fd,on,led_no);
close(fd);
return 0;
}
相信大家都能看懂LED应用程序,就是一些简单的open操作和判断
之后 进行交叉编译:
root@xxx:arm-linux-gcc -static -o ledsapp ledapp.c
一定要加-static,不然在mini6410上无法执行
LED驱动程序的设计和LED应用程序的设计就到此结束了!!!