RK3568平台(基础篇)ioctl接口传参

一. ioctl基本原理

ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数来控制设备的I/O通道。

在驱动程序中实现的ioctl函数体内,实际上是有一个switch{case}结构,每一个case对应一个命令码,做出一些相应的操作。怎么实现这些操作,这是每一个程序员自己的事情。因为设备都是特定的,这里也没法说。关键在于怎样组织命令码,因为在ioctl中命令码是唯一联系用户程序命令和驱动程序支持的途径。命令码的组织是有一些讲究的,因为我们一定要做到命令和设备是一一对应的,这样才不会将正确的命令发给错误的设备,或者是把错误的命令发给正确的设备,或者是把错误的命令发给错误的设备。

二.ioctl地址传参实验

应用层程序:

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

#define CMD_TEST0 _IOW('L',0,int)

struct args{//定义要传递的结构体
  int a;
  int b;
  int c;
};

int main(int argc,char *argv[])
{

   int fd;//定义 int 类型文件描述符

   struct args test;//定义 args 类型的结构体变量 test
   test.a = 1;
   test.b = 2;
   test.c = 3;

   fd = open("/dev/test",O_RDWR,0777);//打开/dev/test 设备
   if(fd < 0){
     printf("file open error \n");
   }

   ioctl(fd,CMD_TEST0,&test);//使用 ioctl 函数传递结构体变量 test 地址
   close(fd);
}

驱动层程序:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/uaccess.h>

#define CMD_TEST0 _IOW('L',0,int)

struct args{
  int a;
  int b;
  int c;
};

struct device_test{
  dev_t dev_num; //设备号
  int major ; //主设备号
  int minor ; //次设备号
  struct cdev cdev_test; // cdev
  struct class *class; //类
  struct device *device; //设备
};

static struct device_test dev1;
static long cdev_test_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
  struct args test;
  switch(cmd){
    case CMD_TEST0:
    if(copy_from_user(&test,(int *)arg,sizeof(test)) != 0) //将用户空间传递来的 arg 赋值给 test
    {
      printk("copy_from_user error\n");
    }
    printk("a = %d\n",test.a);//对传递的值进行打印验证
    printk("b = %d\n",test.b);
    printk("c = %d\n",test.c);
     break;
    default:
     break;
    }
    return 0;
}

/*设备操作函数*/
struct file_operations cdev_test_fops = {
.owner = THIS_MODULE, //将 owner 字段指向本模块,可以避免在模块的操作正在被使用时卸载该模
块
.unlocked_ioctl = cdev_test_ioctl, 
};

static int __init timer_dev_init(void) //驱动入口函数
{
/*注册字符设备驱动*/
   int ret;

/*1 创建设备号*/
   ret = alloc_chrdev_region(&dev1.dev_num, 0, 1, "alloc_name"); //动态分配设备号
   if (ret < 0)
   {
     goto err_chrdev;
   }
   printk("alloc_chrdev_region is ok\n");
   dev1.major = MAJOR(dev1.dev_num); //获取主设备号
   dev1.minor = MINOR(dev1.dev_num); //获取次设备号
   printk("major is %d \r\n", dev1.major); //打印主设备号
   printk("minor is %d \r\n", dev1.minor); //打印次设备号

/*2 初始化 cdev*/
   dev1.cdev_test.owner = THIS_MODULE;
   cdev_init(&dev1.cdev_test, &cdev_test_fops);

/*3 添加一个 cdev,完成字符设备注册到内核*/
   ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
   if(ret<0)
   {
     goto err_chr_add;
   }

/*4 创建类*/
   dev1. class = class_create(THIS_MODULE, "test");
   if(IS_ERR(dev1.class))
   {
     ret=PTR_ERR(dev1.class);
     goto err_class_create;
   }

/*5 创建设备*/
   dev1.device = device_create(dev1.class, NULL, dev1.dev_num, NULL, "test");
   if(IS_ERR(dev1.device))
   {
     ret=PTR_ERR(dev1.device);
     goto err_device_create;
    }
    return 0;

err_device_create:
   class_destroy(dev1.class); //删除类
err_class_create:
   cdev_del(&dev1.cdev_test); //删除 cdev
err_chr_add:
   unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
err_chrdev:
   return ret;
}

static void __exit timer_dev_exit(void) //驱动出口函数
{
/*注销字符设备*/
   unregister_chrdev_region(dev1.dev_num, 1); //注销设备号
   cdev_del(&dev1.cdev_test); //删除 cdev
   device_destroy(dev1.class, dev1.dev_num); //删除设备
   class_destroy(dev1.class); //删除类
}

module_init(timer_dev_init);
module_exit(timer_dev_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("topeet");

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式_笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值