Linux2.6.32驱动笔记(4)ioctl方法解析及mini2440-led驱动实现

来源:互联网 发布:金山数据大师破解版 编辑:程序博客网 时间:2024/05/17 22:07

摘要: 介绍了字符设备驱动的控制方式——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 2module_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


这篇帖子就总结到这里吧,如有不正确的地方还请指出,大家共同进步!

 

0 0