六、【ioctl】应用程序和驱动程序中的ioctl

1、接口函数介绍

很多设备除了读和写之外,还需要驱动提供其它操作能力,例如:获取LCD尺寸、修改串口波特率

(应用层)函数原型:

#include <sys/ioctl.h>
 int ioctl(int fd, unsigned long request, ...);

(driver)提供接口函数

struct file_operations {
	.....
	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
	......
	}
	

2.6.36之后的内核版本只支持unlocked_ioctl,之前的一些过渡版本两者都支持,更早的版本只支持compat_ioctl

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

参数:

  • filp:指向打开的文件信息结构体。
  • cmd:驱动提供给应用程序的命令字。
  • arg:应用程序与驱动之间传递的参数。

2、命令字的组成

(1)bit解释

  • bit[31:30]:参数传递的方向。应用--->驱动、驱动--->应用、应用<--->驱动、不需要参数.
  • bit[29:16]:参数的大小,用数据类型表示大小char int struct xxx。
  • bit[15:8]:魔数/幻数,用于区分不同驱动的命令字,一般设置为某个字符的ASCII码。
  • bit[7:0]:命令字的序号。

(2)内核中提供的生成命令字的宏

#define _IO(type,nr)		_IOC(_IOC_NONE,(type),(nr),0)
#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)))
_IO---生成没有参数传递的命令字。 _IOR--生成应用从驱动获取参数的命令字。 _IOW--生成应用给驱动传递参数的命令字。 _IOWR--生成双向传参的命令字。 

参数:

  • type:魔数/幻数,用于区分不同驱动的命令字,一般设置为某个字符的ASCII码
  • nr:命令字的序号
  • size:参数的大小,用数据类型表示大小char int struct xxx

例如: 

#define BEEP_ON _IO('B',0)
#define BEEP_OFF _IO('B',1)

#define LED_ON _IOW('L',0,unsigned int)
#define LED_OFF _IOW('L',1,unsigned int)

3、例程(实现beep)

beep_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/uaccess.h>  
#include <linux/types.h>
#include <linux/ioctl.h>
static struct cdev beep;
static dev_t dev;
static struct class *beep_cls=NULL;
static struct device * beep_dev=NULL;
static struct resource *beep_res  = NULL;
static void __iomem *GPIOCBASE = NULL;
static void __iomem *GPIOCOUT = NULL;
static void __iomem *GPIOCOUTENB= NULL;
static void __iomem *GPIOCALTFN0 = NULL;
static void __iomem *GPIOCALTFN1 = NULL;

#define BEEP_ON  _IO('B',0)
#define BEEP_OFF   _IO('B',1)

static  int beep_open(struct inode* inode,struct file *filp)
{
    printk(KERN_INFO"beep_open\n");
    return 0;
}

static  int beep_close(struct inode* inode,struct file *filp)
{
    printk(KERN_INFO"beep_close\n");
    return 0;
}

static ssize_t beep_write(struct file *filp, const char __user *user, size_t  size, loff_t *oft)
{

    printk(KERN_INFO"beep_write\n");
     return size;
}

static long beep_ioctl (struct file *filp, unsigned int cmd, unsigned long  arg)
{
      switch(cmd)
      {
      		case BEEP_ON:
				writel(readl(GPIOCOUT)|((0x01<<14)),GPIOCOUT);
				break;
		case BEEP_OFF:
				writel(readl(GPIOCOUT)&(~(0x01<<14)),GPIOCOUT);
		default:
			return -ENOIOCTLCMD;			
      }
	 return 0; 
}
struct file_operations fops=
{
	.open = beep_open,
	.release = beep_close,
	.write = beep_write,
	.unlocked_ioctl = beep_ioctl,
};

static int __init  beep_init(void)
{
      int ret;
       printk(KERN_INFO"beep_init\n");
	ret = alloc_chrdev_region(&dev, 0, 1,"beep_chrdev");
	if(ret!=0)
	{
		printk(KERN_INFO"register char dev failed\n");
		goto alloc_chrdev_region_err;
	}
	beep.owner = THIS_MODULE;
	cdev_init(&beep,&fops);
	ret=cdev_add(&beep, dev, 1);
	if(ret!=0)
	{
		printk(KERN_INFO"add char device failed\n");
		goto cdev_add_err;
	}
	beep_cls = class_create(THIS_MODULE, "beep_class");
	if(IS_ERR(beep_cls))
	{
		printk(KERN_INFO"class create failed\n");
		ret = -EBUSY;
		goto class_create_err;
	}
	beep_dev= device_create(beep_cls, NULL,dev, NULL, "beep_dev");
	if(IS_ERR(beep_dev))
	{
		printk(KERN_INFO"device create failed\n");
		ret = -ENOMEM;
		goto device_create_err;
	}
	beep_res = request_mem_region(0xc001c000,0x68,"beep_iomem");
	if(beep_res==NULL)
	{
		printk(KERN_INFO"request memory region failed\n");
		ret = -EBUSY;
		goto request_mem_region_err;
	}
	GPIOCBASE = ioremap(0xc001c000,0x68);
	if(GPIOCBASE==NULL)
	{
		printk(KERN_INFO"ioremap failed");
		ret = -EBUSY;
		goto ioremap_err;
	}
	GPIOCOUT = GPIOCBASE+0x00;
	GPIOCOUTENB = GPIOCBASE+0x04;
	GPIOCALTFN0 = GPIOCBASE+0x20;
	GPIOCALTFN1 = GPIOCBASE+0x24;
	//beep
	writel(readl(GPIOCOUTENB)|(0x01<<14),GPIOCOUTENB);
	writel(readl(GPIOCALTFN0) &(~(0x03<<28)),GPIOCALTFN0);
	writel(readl(GPIOCALTFN0) |(1<<28),GPIOCALTFN0);
	writel(readl(GPIOCOUT)&(~(0x01<<14)),GPIOCOUT);


	return 0;
ioremap_err:
	   release_mem_region(0xc001c000,0x68);
request_mem_region_err:
	device_destroy(beep_cls , dev);
device_create_err:
	class_destroy(beep_cls);
class_create_err:
	cdev_del(&beep);
cdev_add_err:
	unregister_chrdev_region(dev,1);
alloc_chrdev_region_err:
		return 0;
}

static void __exit beep_exit(void)
{
    printk(KERN_INFO"xxxx__exit\n");
       //取锟斤拷映锟斤拷
    iounmap(GPIOCBASE);
    //锟酵凤拷IO锟节达拷
    release_mem_region(0xc001c000,0x68);
    device_destroy(beep_cls , dev);
    class_destroy(beep_cls);
    cdev_del(&beep); 
    unregister_chrdev_region(dev, 1);
}
module_init(beep_init);
module_exit(beep_exit);
MODULE_AUTHOR("yqf");
MODULE_DESCRIPTION("beep driver program");
MODULE_LICENSE("GPL");

main.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>

#define BEEP_ON _IO('B',0)
#define BEEP_OFF _IO('B',1)

int main()
{
    int fd;
    char buff[2]={0};
    fd = open("/dev/beep_dev",O_RDWR);
    if(fd<0)
    {
        perror("open bepp dev error!");        
    }
    while(1)
    {
        ioctl(fd,BEEP_ON);
        sleep(1);
        ioctl(fd,BEEP_OFF);
         sleep(1);
    }
    
     close(fd);
}

  

  

  

 

 

    

  

 

posted @ 2021-12-11 17:55  轻轻的吻  阅读(460)  评论(0编辑  收藏  举报