嵌入式Linux驱动笔记(一)------第一个LED驱动程序
来源:互联网 发布:黑暗之光披风升阶数据 编辑:程序博客网 时间:2024/05/21 18:40
你好!这里是风筝的博客,
欢迎和我一起交流。
//应用程序:#include <syspes.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>/* leddrvtest on * leddrvtest off */int main(int argc, char **argv){int fd;int val = 1;fd = open("/dev/led", 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;}/*如果输入了leddrvtest on*/if (strcmp(argv[1], "on") == 0)val = 1;elseval = 0;/*写val*/write(fd, &val, 4);return 0;}
当我们打开一个文件的时候,需要获得文件的文件描述符,其实就是文件数组下标,一般是通过函数open函数来完成.
fd=open(文件名,打开方式);
例如:fd = open("/dev/led", O_RDWR | O_NONBLOCK);
用来打开一个设备,他返回的是一个整型变量,如果这个值等于-1,说明打开文件出现错误,如果为大于0的值,那么这个值代表的就是文件描述符。
其中:
O_RDONLY 以只读方式打开文件。
O_WRONLY 以只读方式打开文件。
O_RDWR 以只读方式打开文件。
上面三个参数只能选择一个,下面的可以合理的任意组合:
O_APPEND 强制每次写(write)时都加到文件的尾端。
O_CREAT 打开文件,若此文件不存在则创建它。使用此选择项时,需同时说明第三个参数mode,用其说明该新文件的存取许可权位。
O_EXCL 如果同时指定了O_CREAT,而且文件已经存在,则强制open()失败。这可测试一个文件是否存在,如果不存在则创建此文件成为一个原子操作。
O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。
O_NOCTTY 如果p a t h n a m e指的是终端设备,则不将此设备分配作为此进程的控制终端。
O_NONBLOCK 如果p a t h n a m e指的是一个F I F O、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I / O操作(open\read\write)设置非阻塞方式。
O_SYNC 使每次w r i t e都等到物理I / O操作完成。
//驱动程序:#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>#include <linux/of.h>#include <linux/of_address.h>#include <linux/of_device.h>#include <linux/of_platform.h>static struct class *leddrv_class;static struct class_device*leddrv_class_dev;volatile unsigned long *gpfcon = NULL;volatile unsigned long *gpfdat = NULL;static int led_drv_open(struct inode *inode, struct file *file){/* 配置GPF4,5,6为输出 */*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2)));*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));return 0;}static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){int val;copy_from_user(&val, buf, count); //copy_to_user();if (val == 1){// 点灯*gpfdat &= ~((1<<4) | (1<<5) | (1<<6));}else{// 灭灯*gpfdat |= (1<<4) | (1<<5) | (1<<6);}return 0;}static struct file_operations led_drv_fops = {.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */.open = led_drv_open, .write=led_drv_write, };int major;/*insmod时调用*/static int led_drv_init(void){major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核leddrv_class = class_create(THIS_MODULE, "leddrv");leddrv_class_dev = device_create(leddrv_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);gpfdat = gpfcon + 1;return 0;}/*rmmod时调用*/static void led_drv_exit(void){unregister_chrdev(major, "led_drv"); // 卸载device_destroy(leddrv_class,MKDEV(major, 0));class_destroy(leddrv_class);iounmap(gpfcon);}module_init(led_drv_init);module_exit(led_drv_exit);MODULE_LICENSE("GPL");
其中:
major = register_chrdev(0, "led_drv", &led_drv_fops);
向内核注册了一个字符设备。
第一个参数是主设备号,0代表内核会动态分配。第二个参数是设备的名字,第三个参数是文件操作指针。
完成注册后,在/proc/devices中可以看到我们的设备。
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。
Ioremap函数中,0x56000050为要映射的起始的IO地址;16为要映射空间的大小;这些都视自己芯片手册而定。
MODULE_LICENSE("GPL");
模块的许可证声明。
从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染 “kernel tainted” 的警告。
copy_from_user(&val, buf, count);
从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0。
由于内核空间与用户空间的内存不能直接互访,因此借助函数copy_to_user()完成用户空间到内核空间的复制,函数copy_from_user()完成内核空间到用户空间的复制。
makefile:
KERN_DIR = /work/system/linux-4.8.17
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += led_drv.o
make编译后即可生成.ko文件.
这样,insmod led.ko驱动后,输入 lsmod 就会看到刚刚加载上的驱动了。
major = register_chrdev(0, "led_drv", &led_drv_fops);
向内核注册了一个字符设备。
第一个参数是主设备号,0代表内核会动态分配。第二个参数是设备的名字,第三个参数是文件操作指针。
完成注册后,在/proc/devices中可以看到我们的设备。
gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问。
Ioremap函数中,0x56000050为要映射的起始的IO地址;16为要映射空间的大小;这些都视自己芯片手册而定。
MODULE_LICENSE("GPL");
模块的许可证声明。
从2.4.10版本内核开始,模块必须通过MODULE_LICENSE宏声明此模块的许可证,否则在加载此模块时,会收到内核被污染 “kernel tainted” 的警告。
copy_from_user(&val, buf, count);
从用户空间拷贝数据到内核空间,失败返回没有被拷贝的字节数,成功返回0。
由于内核空间与用户空间的内存不能直接互访,因此借助函数copy_to_user()完成用户空间到内核空间的复制,函数copy_from_user()完成内核空间到用户空间的复制。
makefile:
KERN_DIR = /work/system/linux-4.8.17
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += led_drv.o
make编译后即可生成.ko文件.
这样,insmod led.ko驱动后,输入 lsmod 就会看到刚刚加载上的驱动了。
在应用程序里,输入./leddrvtest on后,就会调用write函数,操作led灯了。
阅读全文
0 0
- 嵌入式Linux驱动笔记(一)------第一个LED驱动程序
- 嵌入式Linux驱动学习笔记(一)------第一个LED驱动程序
- 第一个驱动程序-led驱动
- 第一个嵌入式linux驱动程序——LED
- 【Linux驱动】第一个驱动程序
- 嵌入式驱动编写-第一个驱动程序
- 我的第一个嵌入式linux驱动(基于韦东山led驱动)
- 我的第一个嵌入式linux驱动(基于韦东山led驱动)2_完善1
- 我的第一个嵌入式linux驱动(基于韦东山led驱动)3_完善2
- linux设备驱动程序学习笔记--第一个有用的驱动
- 第一个嵌入式Linux的驱动程序
- 【嵌入式linux】(第六步):使用eclipse集成开发环境开发第一个嵌入式Linux程序,并测试LED驱动
- 嵌入式Linux驱动笔记(三)------LCD驱动程序
- TQ2440 第一个驱动程序:LED驱动程序
- 我的嵌入式学习之路(一) linux 跑的第一个程序 LED灯
- 【Linux驱动】TQ2440 LED驱动程序
- OK6410 linux第一个字符型设备驱动:LED驱动
- 嵌入式驱动编写-点亮LED驱动程序
- pycharm Non-ASCII character '\xe5'中文编码错误
- 解决:eclipse报错:target runtime com.genuitec.runtime.generic.java is not defined
- [LintCode 382]给定一个整数数组,在该数组中,寻找三个数,分别代表三角形三条边的长度,问,可以寻找到多少组这样的三个数来组成三角形?
- 如何在Hbuilder中创建一个web项目?
- 浏览器的跨域问题以及解决方案
- 嵌入式Linux驱动笔记(一)------第一个LED驱动程序
- spring boot热部署
- JSON
- ConcurrentHashMap详细分析
- 反射:使用反射调用构造器创建对象
- 使用 svm+hog 训练,检测手写数字
- JAVA学习中的心得和小程序
- 小白学分布式程序开发3-分布式系统的数据一致性问题
- SpringBoot学习:使用spring-boot-devtools进行热部署