【复习】linux之LED驱动的设备树方式
2017-01-05 11:17
225 查看
【前言】感谢陆老师
linux中led驱动(设备树)编程笔记
1.模块三要素
用到的头文件#include <linux/kernel.h> #include <linux/module.h>
1.1 初始化模块
int __init led_init(void) { printk("led_init!!!\n"); return 0; } module_init(led_init);
1.2 退出模块
void __exit led_exit(void) { printk("led_exit!!!\n"); } module_exit(led_exit);
1.3 模块签证
MODULE_LICENSE("GPL"):
2.platform总线的三个步骤
用到的头文件#include <linux/platform_device.h> #include <linux/of.h> //of_match_ptr
2.1 实例化platform_driver结构体
i)实例化回掉函数probe,并为成员.probe赋值ii)实例化回掉函数remove,并为成员.remove赋值
iii)选择一种匹配方式进行匹配(设备树,ACPI,名字,ID四选一)
const struct of_device_id led_dt_table[]={ { .compatible = "dt,led", }, { }, }; struct platform_driver pdev{ .probe = led_probe, .remove = led_remove, .driver = { .name = "led_platform",//名字必须加不然会报段错误(血的教训T_T) .of_match_table = of_match_ptr(led_dt_table), }, };
2.2 注册
//在led_init中注册 platform_driver_register(&pdev);
2.3 注销
//在led_exit中注销 platform_driver_unregister(&pdev);
3.字符设备框架流程(天龙八部)
用到的头文件#include <linux/fs.h> #include <linux/cdev.h>
3.1 申请设备号
#define DEV_MAJOR 500 #define DEV_MINOR 0 #define DEV_NUM 1 #define DEV_NAME "ledx" dev_t devno; devno = MKDEV(DEV_MAJOR,DEV_MINOR);
3.2 注册设备号
ret = register_chrdev_region(devno,DEV_NUM,DEV_NAME); if(ret < 0) { printk("register_chrdev_region fail!!!\n"); ret = alloc_chrdev_region(&devno,DEV_MINOR,DEV_NUM,DEV_NUM); if(ret < 0) { printk("alloc_chrdev_region fail!!!\n"); return -1; } } else printk("register_chrdev_region success!!!\n"); printk("MAJOR=%d MINOR=%d\n",MAJOR(devno),MINOR(devno));
3.3 实例化cdev结构体
struct cdev led_cdev;
3.4 实例化file_operations结构体,并初始化
int led_open(struct inode *inode, struct file *file) { printk("led_open!!!\n"); return 0; } int led_close(struct inode *inode, struct file *file) { printk("led_close!!!\n"); return 0; } long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg) { printk("led_ioctl!!!\n"); return 0; } struct file_operations fops={ .owner = THIS_MODULE, .open = led_open, .release = led_close, .unlocked_ioctl = led_ioctl, };
3.5 初始化cdev结构体
cdev_init(&led_cdev,&fops); led_cdev.owner = THIS_MODULE;
3.6 注册cdev结构体
cdev_add(&led_cdev,devno,DEV_NUM);
3.7 注销cdev结构体
cdev_del(&led_cdev);
3.8 注销设备号
unregister_chrdev_region(devno,DEV_NUM);
4.自动创建设备节点
用到的头文件#include <linux/device.h>
4.1 创建class
#define CLS_NAME "cls_led" struct class *cls; cls = class_create(THIS_MODULE,CLS_NAME); if(IS_ERR(cls)) { printk("class_create fail!!!\n"); return -1; }
4.2 创建设备节点
#define NODE_LED "led" device_create(cls,NULL,devno,NULL,NODE_LED);
4.3 注销设备节点
device_destroy(cls,devno);
4.4 注销class
class_destroy(cls);
5.修改设备树文件
5.1 打开设备树文件
cd linux-3.14.2/arch/arm/boot/dtsvim xxx.dts
5.2 修改设备树文件
在最后面添加led_platform { compatible = "dt,led"; reg = <寄存器地址 字节数 寄存器地址 字节数>; }
6.make编译并测试
Makefileifeq ($(KERNELRELEASE),) KERNELDIR ?= /home/linux/kernel/linux-3.14.2/ 这里是编译好并能正常运行的内核的路径 PWD ?= $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules clean: $(MAKE) -C $(KERNELDIR) M=$(PWD) clean .PHONY: modules clean else obj-m += led_dt.o 模块源码的.o文件 endif
7.led部分程序
驱动的框架搭好了,现在开始LED部分的编程//在全局中 static volatile unsigned int * gpx2con; static volatile unsigned int * gpx1con; static volatile unsigned int * gpf3con; static volatile unsigned int * gpx2dat; static volatile unsigned int * gpx1dat; static volatile unsigned int * gpf3dat; //在led_probe函数中 gpx2con = ioremap(pdev->resource[0].start,pdev->resource[0].end - pdev->resource[0].start); gpx1con = ioremap(pdev->resource[1].start,pdev->resource[1].end - pdev->resource[1].start); gpf3con = ioremap(pdev->resource[2].start,pdev->resource[2].end - pdev->resource[2].start); gpx2dat = gpx2con + 1; gpx1dat = gpx1con + 1; gpf3dat = gpf3con + 1; *gpx2con = (*gpx2con &~ (0xf << 28))|(0x1 << 28); *gpx1con = (*gpx1con &~ (0xf << 0))|(0x1 << 0); *gpf3con = (*gpf3con &~ (0xf << 16))|(0x1 << 16); *gpf3con = (*gpf3con &~ (0xf << 20))|(0x1 << 20); *gpx2dat = (*gpx2dat | (0x1 << 7)); *gpx1dat = (*gpx1dat | (0x1 << 0)); *gpf3dat = (*gpf3dat | (0x1 << 4)); *gpf3dat = (*gpf3dat | (0x1 << 5)); //在led_remove中 iounmap(gpx2con); iounmap(gpx1con); iounmap(gpf3con);
原理图
寄存器设置
相关文章推荐
- s3c2440基于linux的gpio led字符设备驱动实践
- s3c2440基于linux的gpio led字符设备驱动
- TQ2440 LINUX 2.6.30.4 LED驱动感言,从最初的打印字符,到自动分配设备号,到自动创建设备节点,到次设备号分控led
- linux字符设备驱动之LED
- s3c2440基于linux的gpio led字符设备驱动实践
- Linux输入子系统(6):设备驱动层之LED驱动
- TQ2440 LINUX 2.6.30.4 LED驱动感言,从最初的打印字符,到自动分配设备号,到自动创建设备节点,到此设备号分控led
- “手把手教你学linux驱动开发”OK6410系列之03---LED字符设备驱动
- “手把手教你学linux驱动开发”OK6410系列之03---LED字符设备驱动
- s3c2440基于linux的button和led字符设备驱动
- “手把手教你学linux驱动开发”OK6410系列之02---LED字符设备驱动 .
- 嵌入式Linux字符设备入门之--LED驱动详解
- tiny6410 linux混杂设备 led驱动
- Linux驱动程序开发(4) - 字符设备驱动(3)-LED设备驱动和应用程序
- Linux嵌入式驱动初体验(七)--- LED驱动之字符设备篇
- linux设备驱动之led子系统<二>
- linux--LED设备驱动1
- [置顶] linux设备驱动篇之LED驱动(一)
- “手把手教你学linux驱动开发”OK6410系列之03---LED字符设备驱动
- Linux设备驱动程序设计(三)----Linux的特殊字符设备:混杂设备,依旧让LED闪烁起来