嵌入式学习-驱动开发-lesson2-LED字符设备驱动
来源:互联网 发布:ubuntu 14.04 apt 源 编辑:程序博客网 时间:2024/04/29 13:33
一、设备控制
1)设备控制应用函数
在用户空间,主要是使用ioctl系统调用来控制设备。
int ioctl(int fd,unsigned long cmd,…)
fd: 要控制的设备文件描述符
cmd: 发送给设备的控制命令
…: 第3个参数是可选的参数,存在与否是依赖于控制命令(第 2 个参数 )。
2)设备控制驱动函数
应用程序使用ioctl系统调用时,驱动程序会响应ioctl系统调用,主要通过下面的函数:
2.6.36 之前的内核
long (*ioctl) (struct inode* node ,struct file* filp, unsigned int cmd,unsigned long arg)
2.6.36之后的内核
long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg)
参数cmd:便是通过ioctl系统调用传递下来的命令
3)设备控制实现
ioctl系统调用的cmd命令从其实质而言就是一个整数, 但为了让这个整数具备更好的可读性,我们通常会把这个整数分为几个段:类型(8位),序号,参数传送方向,参数长度。
Type(类型/幻数): 表明这是属于哪个设备的命令,在使用的时候可以详细的了解一下,防止和内核冲突,下文有介绍。
Number(序号),用来区分同一设备的不同命令
Direction:参数传送的方向,可能的值是 _IOC_NONE(没有数据传输), _IOC_READ, _IOC_WRITE(向设备写入参数)
Size: 参数长度
Linux系统提供了下面的宏来帮助定义命令:
_IO(type,nr):不带参数的命令_IOR(type,nr,datatype):从设备中读参数的命令_IOW(type,nr,datatype):向设备写入参数的命令
例:
#define MEM_MAGIC ‘m’ //定义幻数 8位#define MEM_SET _IOW(MEM_MAGIC, 0, int)
MEM_MAGIC 命令的类型
0 命令的序号 第一个命令
int 传输的参数的类型
关于ioctl系统调用和幻数更详细的情况,请参考:
1.ioctl的实现
2.构造IOCTL命令的学习心得—–_IO, _IOR, _IOW, _IOWR 幻数的理解
二、led字符驱动编写
LED字符驱动的编写完全适用于上一课中中的字符驱动模型,因此按照上一课的模型进行代码的编写。
1)分配cdev结构
//静态分配cdev结构struct cdev mdev;
2)初始化cdev结构
//初始化cdev cdev_init(&mdev,&led_ops);
led_ops为我们定义的操作函数集
3)操作函数集的定义与使用
在本次中设计中主要在操作函数集中实现了两个函数,一个函数对led进行初始化操作,另外一个函数则对ioctl系统调用进行响应。
1.操作函数集原型
//操作函数集const struct file_operations led_ops ={ .open = led_open, .unlocked_ioctl = led_ctl,};
2.led_open
这个函数的调用是在我们打开设备文件的时候,经过一些的内核之间的XX,而调用的。
这个函数其实就是初始化led,对LED的寄存器进行配置,但是在配置的时候,要注意物理地址与虚拟地址的转换。
//led的物理地址#define GPKCON 0x7F008820#define GPKDATA 0x7F008824//转化后的虚拟地址unsigned int *ledcon;unsigned int *leddata;//openstatic int led_open(struct inode *inode, struct file *file){ //LED控制寄存器 ledcon = ioremap(GPKCON,4); writel(0x1111,ledcon); //LED数据寄存器 leddata = ioremap(GPKDATA,4); return 0; }
3.led_ctl
本函数主要用来对ioctl系统调用进行响应。
如下,所示:
//ioctllong led_ctl (struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { case(LED_OFF): writel(0xff,leddata); return 0; case(LED_ON): writel(0x00,leddata); return 0; default: return -EINVAL; }}
4)注册cdev结构
在注册前,需要分配一个主设备号
//设备号dev_t devno;alloc_chrdev_region(&devno,0,1,"leddev"); //动态分配主设备号
注册
cdev_add(&mdev,devno,1);
5)销毁
cdev_del(&mdev);
贴上代码:
/**********************************************File name :led.c*Author :stone*Date :2016/07/27*Function :led驱动代码*********************************************/#include <linux/init.h>#include <linux/module.h>#include <linux/cdev.h>#include <linux/fs.h>#include<linux/io.h>#include <mach/gpio-bank-k.h>#include <linux/device.h>#include"led.h"//静态分配cdev结构struct cdev mdev;//设备号dev_t devno;//led的物理地址#define GPKCON 0x7F008820#define GPKDATA 0x7F008824//转化后的虚拟地址unsigned int *ledcon;unsigned int *leddata;//自动创建设备文件static struct class *my_class;//openstatic int led_open(struct inode *inode, struct file *file){ //LED控制寄存器 ledcon = ioremap(GPKCON,4); writel(0x1111,ledcon); //LED数据寄存器 leddata = ioremap(GPKDATA,4); return 0; }//ioctllong led_ctl (struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { case(LED_OFF): writel(0xff,leddata); return 0; case(LED_ON): writel(0x00,leddata); return 0; default: return -EINVAL; }}//操作函数集const struct file_operations led_ops ={ .open = led_open, .unlocked_ioctl = led_ctl,};//入口函数int led_init(){ //初始化cdev cdev_init(&mdev,&led_ops); //注册cdev alloc_chrdev_region(&devno,0,1,"leddev"); //动态分配主设备号 cdev_add(&mdev,devno,1); //自动创建设备文件 my_class = class_create(THIS_MODULE, "my_class1"); device_create(my_class, NULL, devno, NULL, "myled" "%d", MINOR(devno)); return 0;}//退出函数void led_exit(){ cdev_del(&mdev); //注销设备号 unregister_chrdev_region(devno,1); device_destroy(my_class, devno); class_destroy(my_class);}module_init(led_init);module_exit(led_exit);MODULE_LICENSE("GPL");
三、应用程序的编写
驱动程序编写之后,需要使用应用程序对其测试,
/**********************************************File name :led_app.c*Author :stone*Date :2016/07/27*Function :对LED驱动尽心测试*********************************************/#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdlib.h>#include <sys/ioctl.h>#include "led.h"int main(int argc,char **argv){ int fd,num; fd = open("/dev/myled0",O_RDWR); num = atoi(argv[1]); if(num == 0) { printf("led off\n"); ioctl(fd,LED_OFF); } if(num == 1) { printf("led on\n"); ioctl(fd,LED_ON); } return 0;}
/**********************************************File name :led.c*Author :stone*Date :2016/07/27*Function :ioctl幻数的定义*********************************************/#define LED_MAGIC 'L'#define LED_ON _IO(LED_MAGIC,0)#define LED_OFF _IO(LED_MAGIC,1)
菜鸟一枚,如有错误,多多指教。。。
- 嵌入式学习-驱动开发-lesson2-LED字符设备驱动
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-LED字符设备驱动
- 嵌入式学习-驱动开发-lesson1-字符设备驱动模型
- 嵌入式Linux字符设备驱动LED驱动编写
- 嵌入式Linux字符设备驱动LED驱动编写
- 嵌入式Linux驱动开发(二)——字符设备驱动之控制LED
- LED字符设备驱动
- led字符设备驱动
- 字符设备驱动---Led
- 字符设备驱动-LED驱动
- 字符设备驱动学习之LED
- Linux学习:LED字符设备驱动
- Linux驱动开发-OK6410-LED字符设备驱动实现过程
- 嵌入式Linux字符设备入门之--LED驱动详解
- 嵌入式Linux字符设备LED驱动-基于树莓派
- 树莓派驱动学习-字符设备驱动(LED)
- 字符设备驱动之LED
- 字符设备驱动点亮led
- HDU1171
- C语言学习之——排序
- CMake使用进阶
- 闭包类 demo
- Linux 设备树(Device Tree)简介
- 嵌入式学习-驱动开发-lesson2-LED字符设备驱动
- Java之面向对象(上)
- opencv随机数发生器RNG
- 普通内部类和静态内部类总结
- 数字转换成大写
- 放眼未来-了解APP开发工具
- 字典树(模板+总结)
- 单例与多例
- 【编程之法】【最长回文子串】Manacher