Linux2.6.32驱动笔记(4)ioctl方法解析及mini2440-led驱动实现
2015-09-18 18:26
666 查看
摘要: 介绍了字符设备驱动的控制方式——ioctl,同时利用该方式在mini2440上实现led驱动。
驱动中,除了read,write,open,close之外,还有很多的访问方式,其中对于设备的控制,ioctl是一种重要的方式。
一、ioctl函数
int ioctl(int fd,unsigned long cmd,…)
fd:要控制的设备文件描述符
cmd:发送给设备的控制命令
…:可选参数,依赖于第二个cmd参数
当应用程序使用ioctl的时候,驱动程序将由如下驱动函数来响应:
2.6.36内核以前:
long(*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned longarg)
2.6.36内核以后:
long(*unlock_ioctl)( struct file *filp,unsigned int cmd,unsigned long arg)
二、控制实现步骤
1.定义命令
命令其实是一个整数,但是为了可读性更好,分为四个段,分别是:类型(幻数)8位,序号8位,传送方向2位,参数大小14位。
type(类型/幻数):表明这是属于哪个设备的命令;
number(序号):用来区分同一个设备的不同命令;
direction:参数传递方向,可能的值是没有传输方向,读或者写;
size:参数长度。
命令宏,Linux提供了一组宏来帮助定义命令:
_IO(type,nr):不带参数的命令;
_IOR(type,nr,datatype):从设备中读参数的命令;
_IOW(type,nr,datatype):向设备写入参数的命令;
_IOWR(type,nr,datatype):双向传输。
其中命令的type 和size是通过datatype中取对应位得来。
2.实现操作
这个模式就是switch case,我们给进去定义的命令,然后让switch去匹配,匹配到哪个就执行相应的操作,都没有匹配到就返回-EINVAL。
switchcmd
case命令A:
//执行A对应的操作
case命令B:
//执行B对应的操作
default:
//return–EINVAL
三、LED字符驱动实现
首先,mini2440上和四个led相连接的gpio口分别是PORTB的5,6,7,8四个端口。那么就需要定义寄存器的基地址,并且使用ioremap把它映射到用户空间给我们使用。
led.c如下:
led_app.c如下:
led.h如下:
Makefile如下:
虚拟机下按照以下步骤:
#make
#chmod 777 led.ko
#cp led.ko /opt/rootfs
#arm-linux-gcc –static ledapp.c –oledapp
#chmod 777 ledapp
#cp ledapp /opt/rootfs
开发板上电:
#boot
#insmod led.ko
#cat proc/devices
#mknod /dev/myled c 251 0
#./ledapp 1
#./ledapp 0
#rmmod led
这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!
驱动中,除了read,write,open,close之外,还有很多的访问方式,其中对于设备的控制,ioctl是一种重要的方式。
一、ioctl函数
int ioctl(int fd,unsigned long cmd,…)
fd:要控制的设备文件描述符
cmd:发送给设备的控制命令
…:可选参数,依赖于第二个cmd参数
当应用程序使用ioctl的时候,驱动程序将由如下驱动函数来响应:
2.6.36内核以前:
long(*ioctl)(struct inode *inode,struct file *filp,unsigned int cmd,unsigned longarg)
2.6.36内核以后:
long(*unlock_ioctl)( struct file *filp,unsigned int cmd,unsigned long arg)
二、控制实现步骤
1.定义命令
命令其实是一个整数,但是为了可读性更好,分为四个段,分别是:类型(幻数)8位,序号8位,传送方向2位,参数大小14位。
type(类型/幻数):表明这是属于哪个设备的命令;
number(序号):用来区分同一个设备的不同命令;
direction:参数传递方向,可能的值是没有传输方向,读或者写;
size:参数长度。
命令宏,Linux提供了一组宏来帮助定义命令:
_IO(type,nr):不带参数的命令;
_IOR(type,nr,datatype):从设备中读参数的命令;
_IOW(type,nr,datatype):向设备写入参数的命令;
_IOWR(type,nr,datatype):双向传输。
其中命令的type 和size是通过datatype中取对应位得来。
2.实现操作
这个模式就是switch case,我们给进去定义的命令,然后让switch去匹配,匹配到哪个就执行相应的操作,都没有匹配到就返回-EINVAL。
switchcmd
case命令A:
//执行A对应的操作
case命令B:
//执行B对应的操作
default:
//return–EINVAL
三、LED字符驱动实现
首先,mini2440上和四个led相连接的gpio口分别是PORTB的5,6,7,8四个端口。那么就需要定义寄存器的基地址,并且使用ioremap把它映射到用户空间给我们使用。
led.c如下:
<span style="font-size:18px;">#include <linux/module.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/fs.h> #include <linux/io.h> //#include <mach/gpio-bank-k.h> #include "led.h"//step 1一些列需要的头文件 #define LEDCON 0x56000010 #define LEDDAT 0x56000014//GPB5,6,7,8,控制寄存器基地址,和数据寄存器基地址,一个用来设置端口模式,一个用来给数据 unsigned int *led_config; unsigned int *led_data;//ioremap之后得到的虚拟地址赋给他们 struct cdev cdev;//定义设备的结构体 dev_t devno;//定义设备号 int led_open(struct inode *inode,structfile *filep)//setp 6 { led_config= ioremap(LEDCON,4);//把LEDCON控制寄存器物理地址映射到用户空间,映射4个字节 writel(0x155555,led_config);//01对应输出模式,这里把所有i/o口配置成输出模式 led_data= ioremap(LEDDAT,4);//数据寄存器的映射 return0; } long led_ioctl(struct file *filep,unsignedint cmd,unsigned long arg) //step 7 { switch(cmd) { caseLED_ON: writel(0x1ff,led_data);//具体命令实现处,给LED点灯 return0; caseLED_OFF: writel(0x000,led_data);//关灯 return0; default: return-EINVAL; } } static struct file_operations led_fops= //step 5 对应的对led的操作实现都在这里,一个打开,一个ioctl,所以下面我们就要去写实现函数 { .open= led_open, .unlocked_ioctl= led_ioctl, }; static int led_init(void)//step 3 { cdev_init(&cdev,&led_fops);//字符设备初始化函数,将cdev和f_ops绑定起来 alloc_chrdev_region(&devno,0,1,"myled");//次设备号为0,一个设备,设备名称为myled,把动态分配得到的设备号给devno cdev_add(&cdev,devno,1);//注册设备,devno为主设备号,设备数为1 return0; } static void led_exit(void)//step 4 { cdev_del(&cdev);//删除驱动cdev unregister_chrdev_region(devno,1);//释放设备号 } module_init(led_init);//step 2 module_exit(led_exit); </span>
led_app.c如下:
<span style="font-size:18px;">#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include "led.h" //open需要的一系列的头文件以及led.h int main(int argc,char *argv[])//主函数,argc保存主函数的参数个数,后面存放具体的参数 { intfd;//文件句柄 intcmd;//定义cmd if(argc<2) { printf("please enter the secondpara!\n"); return0; }//这里判断小于2是因为我们输入的时候要输入进来是0还是1,使用方法是./ledapp 0或者./ledapp 1,需要第二个参数 cmd= atoi(argv[1]);//atoi用来把字符串转换成整形数,因为我们的cmd其实都是一个整形数 fd= open("/dev/myled",O_RDWR);//打开文件 if(cmd==1) ioctl(fd,LED_ON); else ioctl(fd,LED_OFF); //具体ioctl操作,开关灯 return0; } </span>
led.h如下:
<span style="font-size:18px;">#define LED_MAGIC 'L' #define LED_ON _IO(LED_MAGIC,0) #define LED_OFF _IO(LED_MAGIC,1)</span>
Makefile如下:
<span style="font-size:18px;">obj-m := led.o KDIR :=/home/passionbird/project/test/linux-2.6.32.2 all: make-C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm-f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order</span>
虚拟机下按照以下步骤:
#make
#chmod 777 led.ko
#cp led.ko /opt/rootfs
#arm-linux-gcc –static ledapp.c –oledapp
#chmod 777 ledapp
#cp ledapp /opt/rootfs
开发板上电:
#boot
#insmod led.ko
#cat proc/devices
#mknod /dev/myled c 251 0
#./ledapp 1
#./ledapp 0
#rmmod led
这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!
相关文章推荐
- 【linux学习笔记一】目录处理命令
- linux screen 命令详解
- centos 删除默认路由
- Linux进程管理之
- linux学习笔记(1)-Vim编辑器
- 组建自己的Linux-02命令移植
- (Linux)sphinx检索Coreseek中文全文检索引擎安装和使用
- Linux下统计当前文件夹下的文件个数、目录个数
- linux tail -f catalina.out查看控制台失败
- gcc 和 arm-linux-gcc 编译器的默认搜索头文件路径
- QT5.5.0 VS2013/CentOS 7自编译
- linux下编译安装ffmpeg
- linux下分卷压缩,合并解压的3种方法
- Linux的启动过程
- iptables 的防火墙正常运行时间和安全性 使用此高效应用程序设置并维护 Linux 防火墙
- linux c 使用正则表达式
- Linux永久关闭防火墙 vsftp 开机自启动
- Linux chattr和lsattr
- MySQL学习5_CentOS下Mysql数据库(不使用yum命令)的安装与配置
- linux中某个端口拒绝远程主机连接原因及解决方法