驱动学习(六)ioctl

驱动学习(六)ioctl


linux内核给用户提供了两类系统调用函数:一类是数据操作函数,比如read、write…。 另外一类函数是非数据操作函数,比如ioctl…,用户程序可以用ioctl给底层设备发送指令。

1. ioctl

ioctl是一个系统调用函数,应用程序可以用它给内核发送指令。

int ioctl(int d, int request, ...);
	d:文件描述符
	request:命令码。
	...:可变参数,可有可无,若有,该参数传送内核驱动
	返回值:成功为0
2. 命令码
2.1 自定义命令码
2.2 标准命令码
标准命令码(u32)
	30-31:数据的控制方向(2bit get/set)
	16-29:数据的大小(14bit)
	8-15:设备类型(8bit)
	0-7:cmd(命令码)(区分命名的顺序序号)
2.2.1 合成标准命令码的宏函数
 #define _IOC(dir,type,nr,size) \
	(((dir)  << _IOC_DIRSHIFT) | \  方向(左移30位)
	((type) << _IOC_TYPESHIFT) | \  设备类型(左移8位)
	((nr)   << _IOC_NRSHIFT) | \    命令码(低8位)
	((size) << _IOC_SIZESHIFT))     数据大小(左移16位)
不同类型的标准命令码合成宏函数
	#define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0)
    #define _IOR(type,nr,size)  _IOC(_IOC_READ,(type),(nr),sizeof(size))
    #define _IOW(type,nr,size)  _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
    #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
3. 测试ioctl

环境 ubuntu 20.04

思路:在test.c中调用ioctl函数发送cmd,在驱动模块中让对应的cmd打印不同的信息

#####ioctl.c

  1 #include <linux/module.h>           //模块驱动的头文件
  2 #include <linux/cdev.h>             //设备信息描述的头文件
  3 #include <linux/fs.h>               //静态申请设备号头文件
  4 #include <linux/kdev_t.h>           //设备号用到的头文件和宏函数
  5 #include <linux/uaccess.h>
  6 #include <linux/device.h>
  7 #include "common.h"
  8 
  9 #define BUF_SIZE 100
 10 
 11 int major = 0;                      //主设备号
 12 int min = 0;                        //次设备号
 13 int deviceNum = 0;                  //完整设备号
 14 struct cdev* pCdev = NULL;          //描述设备信息的结构体
 15 char *deviceName = "ioctl";//设备名
 16 char buff[BUF_SIZE] = "chrdev-test-2022-7-12";
 17 struct class *pClass = NULL;        //设备文件类指针
 18 int devNum = 2;                     //设备文件数量
 19 
 20 int testOpen(struct inode *pNode,struct file *pFile)
 21 {
 22         printk("------into test open------\n");
 23         printk("------leave test open------\n");
 24         return 0;
 25 }
 26 int testClose(struct inode *pNode,struct file *pFile)
 27 {
 28         printk("------into test close------\n");
 29         printk("------leave test close------\n");
 30         return 0;
 31 }
 32 ssize_t testRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset)
 33 {
 34         int res = -1;
 35         printk("------into testRead------\n");
 36         if(count > BUF_SIZE-1)
 37         {
 38                 count = BUF_SIZE - 1;
 39         }
 40         res = copy_to_user(buf,buff,count);
 41         if(res)
 42         {
 43                 printk("copy_to_user error\n");
 44                 return -EFAULT;
 45         }
 46         printk("copy_to_user ok\n");
 47         printk("\t buff = %s\t\n",buff);
 48         printk("------leave testRead------\n");
 49         return count;
 50 }
 51 
 52 ssize_t testWrite(struct file *pFile,const char __user *buf,size_t count,loff_t *pOffset)
 53 {
 54         int res = -1;
 55         printk("------into testWrite------\n");
 56         if(count > BUF_SIZE-1)
 57         {
 58                 count = BUF_SIZE - 1;
 59         }
 60         res = copy_from_user(buff,buf,count);
 61         if(res)
 62         {
 63                 printk("copy_from_user error\n");
 64                 return -EFAULT;
 65         }
 66         printk("copy_from_user ok\n");
 67         printk("\t buff = %s\t\n",buff);
 68         printk("------leave testWrite------\n");
 69         return count;
 70 }
 71 
 72 long testIoctl(struct file *pFile,unsigned int cmd,unsigned long arg)
 73 {
 74         switch(cmd)
 75         {
 76                 case TEST_CMD:
 77                         {
 78                                 printk("test cmd-------arg = %ld \n",arg);
 79                         }
 80                         break;
 81                 case TEST_CMD1:
 82                         {
 83                                 printk("test cmd1-------arg = %ld \n",arg);
 84                         }
 85                         break;
 86                 case TEST_CMD2:
 87                         {
 88                                 printk("test cmd2-------arg = %ld \n",arg);
 89                         }
 90                         break;
 91                 default:
 92                         printk("error cmd \n");
 93         }
 94         return 0;
 95 }
 96 
 97 struct file_operations fp_arr =
 98 {
 99         .owner = THIS_MODULE,
100         .open = testOpen,
101         .read = testRead,
102         .write = testWrite,
103         .release = testClose,
104         .unlocked_ioctl = testIoctl
105 };
106 
107 int driverr_init(void)               //模块初始化函数
108 {
109         int res = 0;
110         int i = 0;
111         struct device *pDevTmp = NULL;
112         printk("*********into driver init\n");
113         //动态申请设备号
114         res = alloc_chrdev_region(&deviceNum,min,devNum,deviceName);
115         if(res)
116         {
117                 printk("alloc_chrdev_region error\n");
118                 return res;
119         }
120         printk("alloc_chrdev_region OK!\n");
121         printk("major = %d minor = %d \n",MAJOR(deviceNum),MINOR(deviceNum));
122         major = MAJOR(deviceNum);
123         //创建设备
124         pCdev = cdev_alloc();
125         if(NULL == pCdev)
126         {
127                 printk("cdev_alloc error\n");
128                 unregister_chrdev_region(deviceNum,devNum);
129                 return -1;
130         }
131         printk("cdev_alloc ok\n");
132         //设备初始化
133         cdev_init(pCdev,&fp_arr);
134         printk("cdev_init ok\n");
135         //设备与设备号关联
136         res = cdev_add(pCdev,deviceNum,devNum);
137         if(res)
138         {
139                 printk("cdev_add error\n");
140                 cdev_del(pCdev);
141         }
142         printk("cdev_add ok\n");
143         //创建设备文件类
144         pClass = class_create(THIS_MODULE,"ioctl");
145         if(NULL == pClass)
146         {
147                 printk("class_create error\n");
148                 cdev_del(pCdev);
149         }
150         printk("class_create ok\n");
151         //创建设备文件
152         for(;i < devNum;i++)
153         {
154                 pDevTmp = device_create(pClass,NULL,MKDEV(major,i),NULL,"ioctl%d",i);
155                 if(IS_ERR(pDevTmp))
156                 {
157                         printk("device_create error\n");
158                         for(i = 0;i < devNum;i++)
159                         {
160                                 device_destroy(pClass,MKDEV(major,i));
161                         }
162                         class_destroy(pClass);
163                         return -2;
164                 }
165         }
166         printk("device_create ok\n");
167         printk("*********leave driver init\n");
168         return 0;
169 }
170 
171 void driver_clear(void)             //模块清除函数
172 {
173         int i = 0;
174         printk("*********into driver clear\n");
175         for(;i < devNum; i++)
176         {
177                 device_destroy(pClass,MKDEV(major,i));
178         }
179         class_destroy(pClass);
180         cdev_del(pCdev);
181         unregister_chrdev_region(deviceNum,devNum);
182         printk("*********leave driver clear\n");
183 }
184 
185 module_init(driverr_init);           //模块加载函数
186 module_exit(driver_clear);          //模块卸载函数
187 
188 
189 MODULE_LICENSE("GPL");
190 MODULE_AUTHOR("cfy");
191 MODULE_ALIAS("liangzai");
192 MODULE_DESCRIPTION("2022-7-12");

  #####test.c
  
  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 #include <sys/ioctl.h>
  8 #include "common.h"
  9 #define BUF_SIZE 100
 10 
 11 int main()
 12 {
 13         int fd = open("/dev/ioctl0",O_RDWR);
 14         if(fd < 0)
 15         {
 16                 printf("open ioctl0 err\n");
 17                 return -1;
 18         }
 19         printf("open ioctl0 ok\n");
 20 
 21         ioctl(fd,TEST_CMD);
 22         ioctl(fd,TEST_CMD1,123456);
 23         ioctl(fd,TEST_CMD2);
 24 
 25         close(fd);
 26         return 0;
 27 
 28 
 29 }

编译、查看设备文件、查看内核打印

在这里插入图片描述

添加设备文件权限

sudo chmod 777 /dev/ioctl0 /dev/ioctl1

执行测试程序,查看内核打印信息

在这里插入图片描述

可以看到第一次的cmd没有传参,arg为0;第二次传参了为123456;第三次未传参arg被第二次的赋值为123456,验证完毕。

接下来是驱动互斥

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
·Linux设备驱动程序学习(1)-字符设备驱动程序 ·Linux设备驱动程序学习(0)-设备驱动介绍& Hello, world!模块 ·Linux设备驱动程序学习(2)-调试技术 ·Linux设备驱动程序学习(3)-并发和竞态 ·Linux设备驱动程序学习(4)-高级字符驱动程序操作[(1)ioctl and llseek] ·Linux设备驱动程序学习(5)-高级字符驱动程序操作[(2)阻塞型I/O和休眠] ·Linux设备驱动程序学习(6)-高级字符驱动程序操作[(3)设备文件的访问控制] ·Linux设备驱动程序学习(7)-内核的数据类型 ·Linux设备驱动程序学习(9)-与硬件通信 ·Linux设备驱动程序学习(8)-分配内存 ·Linux设备驱动程序学习(10)-时间、延迟及延缓操作 ·Linux设备驱动程序学习(11)-中断处理 ·Linux设备驱动程序学习(3-补)-Linux中的循环缓冲区 ·Linux设备驱动程序学习(12)-Linux设备模型(底层原理简介) ·Linux设备驱动程序学习(13)-Linux设备模型(总线、设备、驱动程序和类) ·Linux设备驱动程序学习(14)-Linux设备模型(各环节的整合) ·Linux设备驱动程序学习(15)-Linux设备模型(热插拔、mdev 与 firmware) ·Linux设备驱动程序学习(16)-USB 驱动程序(一) ·Linux设备驱动程序学习(17)-USB 驱动程序(二) ·Linux设备驱动程序学习(18)-USB 驱动程序(三) ·Linux设备驱动程序学习(19)-USB 驱动程序(四)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值