#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <asm/uaccess.h> #include <asm/irq.h> #include <asm/io.h> volatile unsigned long *gpbcon = 0; volatile unsigned long *gpbdat = 0; static int LED_open(struct inode *inode, struct file *file) { /* 配置GPB 5,6,7,8为输出 */ *gpbcon &= ~((0x3<<(5*2)) | (0x3<<(6*2)) | (0x3<<(7*2)) | (0x3<<(8*2))); *gpbcon |= ((0x1<<(5*2)) | (0x1<<(6*2)) | (0x1<<(7*2)) | (0x1<<(8*2))); //打开设备的时候四个灯是亮的 *gpbdat &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8)); return 0; } static ssize_t LED_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos) { int val; copy_from_user(&val, buf, count); if (val == 1) //如果写入 1 就点灯 { *gpbdat &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8)); } else //否则 灭灯 { *gpbdat |= ((1<<5) | (1<<6) | (1<<7) | (1<<8)); } return 0; } static struct file_operations LED_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = LED_open, .write = LED_write, }; int major; static int LED_init(void) { major = register_chrdev(0, "myled", &LED_fops); //参数0表示自动寻找设备号 gpbcon = (volatile unsigned long *)ioremap(0x56000010, 16);//地址重映射 gpbdat = gpbcon + 1; return 0; } static void LED_exit(void) { unregister_chrdev(major, "myled"); // 卸载 iounmap(gpbcon); } module_init(LED_init); module_exit(LED_exit); MODULE_LICENSE("GPL");
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(int argc, char **argv) { int fd; int val = 1; fd = open("/dev/myled", O_RDWR); if (fd < 0) { printf("can't open!\n"); } if (argc != 2) { printf("Usage :\n"); printf("%s <on|off>\n", argv[0]); return 0; } if (strcmp("on", argv[1]) == 0) //如果测试程序输入 on 则,将val的值 1 传入驱动程序 { val = 1; } else { val = 0; } write(fd, &val, sizeof(int)); //sizeof(int) 传给驱动的 count close(fd); return 0; }
关于makefile,只有myled.o和内核地址需要改改,其他copy下就行了。
执行的make用的内核,是用交叉编译链arm-linux-编译出的。(ARCH=arm CROSS_COMPILE=arm-linux-)
ifneq ($(KERNELRELEASE),) obj-m := myled.o else KDIR := /opt/opt/EmbedSky/linux-2.6.30.4 all: make -C $(KDIR) M=$(PWD) modules clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul* endif
编译好模块后得到myled.ko 和 测试程序testled
mknod /dev/myled c 252 0
我来解释下这句话:
mknod 创建节点
/dev/myled 在/dev下创建一个名为myled的节点
c 表示字符设备
252 0 分别表示主设备号和从设备号。252从何而来呢?---->执行命令cat /proc/devices
这是你就看到了与myled这个模块对应的主设备号252 . 0呢?就表示这类设备中的第几个,0是我随便写的,不冲突就好。
这时候你就可以测试了。./testled on ---->表示全亮 参数off就是全灭
另外,如果./testled 运行时,告诉你权限不够的话,执行chmod +x testled
,改变模式后,再运行就好了。