24 ioctl的自定义命令

来源:互联网 发布:在c语言中拆分英文名 编辑:程序博客网 时间:2024/04/29 16:28

系统调用ioctl函数的作用: 用户进程用于通过相应的设备驱动来获取或者设置硬件状态.

ioctl ---> kernel --->  cdev.fops->unlocked_ioctl(...)

在字符设备驱动里, 其中unlock_ioctl函数原形:

long (*unlocked_ioctl) (struct file *fl, unsigned int cmd, unsigned long arg);

cmd参数需要与应用程序调用ioctl时的参数约定,才可以表示一种功能.

cmd的值不能为2,内核里保留此值.

man 2 ioctl_list //可以查看系统里的ioctl关于cmd的参数值

////////////////////////////////////////
在内核里,有提供帮助生成ioctl的cmd的宏(可用,可不用).

cmd是32位的数, 分成以下四个部分:

 1). 最高两位表示方向: 读/写/读写(输出/输入/输出输入) 2). 第16位至第29位表示ioctl的第三个参数的大小(unlocked_ioctl的arg). 3). 第8位至第15位表示ioctl命令的类型. 4). 最低8位表示ioctl命令类型里的第几个命令

include/asm-generic/ioctl.h:

                 'k'_IOC_DIRBITS << 30 | _IOC_SIZEBITS << 16 | _IOC_TYPEBITS << 8 | _IOC_NRBITS#define _IOC_NRBITS 8    //顺序号   0 --- 7#define _IOC_TYPEBITS   8    //类型  8 --- 15#define _IOC_SIZEBITS   14   //ioctl第三个参数的大小 16 --- 29#define _IOC_DIRBITS    2    //方向, 有没有参数, 读/写  30 --- 31///方向位 ////# define _IOC_NONE  0U# define _IOC_WRITE 1U# define _IOC_READ  2U
//////////用于生成一个ioctl的命令的宏定义///#define _IOC(dir,type,nr,size) \    (((dir)  << _IOC_DIRSHIFT) | \     ((type) << _IOC_TYPESHIFT) | \     ((nr)   << _IOC_NRSHIFT) | \     ((size) << _IOC_SIZESHIFT))如:#define LED_ON _IOC(_IOC_WRITE, 'L', 99, 0);            //方向,     类型, 第99个命令, ioctl的第三个参数大小为0(即没有第三个参数)//定义一个没有指定方向,没有第三个参数,只指定ioctl命令的类型及命令类型里的序号#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)#define _IOC_TYPECHECK(t) \    ((sizeof(t) == sizeof(t[1]) && \      sizeof(t) < (1 << _IOC_SIZEBITS)) ? \      sizeof(t) : __invalid_size_argument_for_IOC)// 定义一个驱动里输出参数值(用户进程读), 指定ioctl命令的类型及命令类型里的序号及第三个参数的大小#define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))#define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
///////用于获取ioctl命令里方向,类型等信息#define _IOC_DIR(nr)        (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)#define _IOC_TYPE(nr)       (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)#define _IOC_NR(nr)     (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)#define _IOC_SIZE(nr)       (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)_IOC_DIR(nr)  //获取nr命令里的方向值_IOC_TYPE(nr) //获取nr命令里的类型_IOC_NR(nr)   //获取nr命令里的顺序号_IOC_SIZE(nr) //获取nr命令里的第三个参数大小

//////////////////////////////////////////////////////
如led控制的例子, test.c:

#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <mach/gpio.h>#include <linux/gpio.h>#include <linux/ioctl.h> //生成ioctl命令的宏定义#define MYMA  1234#define MYMI  3344#define COUNT    1#define LED_IO   GPIOA(15)////自定义的ioctl命令////#define LED_MAGIC  0xEF#define LED_ON   (_IO(LED_MAGIC, 0x1))#define LED_OFF  (_IO(LED_MAGIC, 0x2))dev_t devid; //用于存放设备号struct cdev mycdev; //如有第三个参数,则arg的值为用户进程ioctl调用时传进来的地址long myioctl(struct file *fl, unsigned int cmd, unsigned long arg){    //如果ioctl命令的类型不是LED_MAGIC则退出    if (LED_MAGIC != _IOC_TYPE(cmd))        return -EINVAL;    //根据用户进程ioctl的第二个参数值来设置led灯亮或灭    if (LED_ON == cmd) // led on        gpio_set_value(LED_IO, 1);          else if (LED_OFF == cmd)  // led off        gpio_set_value(LED_IO, 0);    return 0;}struct file_operations fops = {    .owner = THIS_MODULE,    .unlocked_ioctl = myioctl,};static int __init test_init(void){    int ret;    devid = MKDEV(MYMA, MYMI); //生成一个设备号    ret = register_chrdev_region(devid, COUNT, "mydev");    if (ret < 0)        goto err0;    cdev_init(&mycdev, &fops);    mycdev.owner = THIS_MODULE;    ret = cdev_add(&mycdev, devid, COUNT);    if (ret < 0)        goto err1;      gpio_request(LED_IO, "mydev"); //请求gpio口    gpio_direction_output(LED_IO, 0); //配置gpio口为输出,先输出低电平    return 0;err1:    unregister_chrdev_region(devid, COUNT);err0:    return ret;}static void __exit test_exit(void){    unregister_chrdev_region(devid, COUNT);    cdev_del(&mycdev);    gpio_free(LED_IO); //释放gpio}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");

//////////////
app.c:

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <linux/ioctl.h>////自定义的ioctl命令////#define LED_MAGIC  0xEF#define LED_ON   (_IO(LED_MAGIC, 0x1))#define LED_OFF  (_IO(LED_MAGIC, 0x2))int main(void){    int fd;    fd = open("/dev/mydev", O_RDWR);    if (fd < 0)    {        perror("open dev");        return 1;    }    while (1)    {        ioctl(fd, LED_ON); //led灯亮        sleep(1);        ioctl(fd, LED_OFF); // led灯灭        sleep(1);    }    return 0;}

//////////////////////////////////////////////////////////////////////////////////////////
通过ioctl获取烟雾传感器的例子:
test.c

#include <linux/init.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/cdev.h>#include <mach/gpio.h>#include <linux/gpio.h>#include <linux/ioctl.h> //生成ioctl命令的宏定义#define MYMA  1234#define MYMI  3344#define COUNT    1//烟雾传感器接在PA(7), 感应到烟雾时输出低电平,正常高电平#define DETECT_IO   GPIOA(7)////自定义的ioctl命令////#define DETECTOR_MAGIC  0xAF#define DETECT_RET   (_IOR(DETECTOR_MAGIC, 0x1, int))dev_t devid; //用于存放设备号struct cdev mycdev; //如有第三个参数,则arg的值为用户进程ioctl调用时传进来的地址long myioctl(struct file *fl, unsigned int cmd, unsigned long arg){    if (DETECTOR_MAGIC != _IOC_TYPE(cmd))        return -EINVAL;    if (DETECT_RET == cmd)        *(int *)arg = gpio_get_value(DETECT_IO);    return 0; //返回值表示操作是成功与否}struct file_operations fops = {    .owner = THIS_MODULE,    .unlocked_ioctl = myioctl,};static int __init test_init(void){    int ret;    devid = MKDEV(MYMA, MYMI); //生成一个设备号    ret = register_chrdev_region(devid, COUNT, "mydev");    if (ret < 0)        goto err0;    cdev_init(&mycdev, &fops);    mycdev.owner = THIS_MODULE;    ret = cdev_add(&mycdev, devid, COUNT);    if (ret < 0)        goto err1;      gpio_request(DETECT_IO, "mydev"); //请求gpio口    gpio_direction_input(DETECT_IO); //配置gpio口为输入    return 0;err1:    unregister_chrdev_region(devid, COUNT);err0:    return ret;}static void __exit test_exit(void){    unregister_chrdev_region(devid, COUNT);    cdev_del(&mycdev);    gpio_free(DETECT_IO); //释放gpio}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");

///////////
app.c

#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <linux/ioctl.h>////自定义的ioctl命令////#define DETECTOR_MAGIC  0xAF#define DETECT_RET   (_IOR(DETECTOR_MAGIC, 0x1, int))int main(void){    int fd, ret, val;    fd = open("/dev/mydev", O_RDWR);    if (fd < 0)    {        perror("open dev");        return 1;    }    while (1)    {        ret = ioctl(fd, DETECT_RET, &val);        if (ret < 0)            break;        if (!val) //有烟雾感应到了        {            printf("smoke detected ...\n");            break;        }    }    close(fd);    return 0;}
原创粉丝点击