您的位置:首页 > 运维架构 > Linux

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如下

<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

这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: