ioctl函数存在的意义
在linux的系统驱动中,内核有意将设备功能的控制选择的读写交给不同的函数完成,既让read和write函数专注于硬件的数据的读写,而设备的功能和实现交给iocti函数来完成,既让read和write函数专注一硬件数据的读写,而设备的功能控制和实现交给ioctl函数来完成,比如,对串口完成控制和完成驱动控制,让iocti完成串口通信的数据,让write通过串口发送数据
#include<sys/ioct1.h>
int ioct(int fd,unsigned long request,....)
功能:进行设备的io和功能控制
参数:
fd :设备文件的文件描述符
request:要实现的功能的功能码
.... 可以写可以不写,是传递给驱动中ioct1方法的一个参数
返回值:成功返回0,失败返回-1
long mycdev_ioct1(struct file *file,unsigned int cmd ,unsigned long arg)
{file:保存当前设备调用ioct1函数时,驱动中的ioct1方法会被自动回调
参数:
file:保存当前设备文件信息的文件指针
cmd:ioct1的功能码,应用程序ioct1第二个参数传递过来
arg:用于接收用户程序中的ioct1函数的函数的第三个参数的数值
return 0;}
一个ioctl的功能码是32位大小,我们需要对ioctl的函数的功能进行编码,编码的规则可以在linux内核编码中查看位置:内核源码顶层目录 /Documentation/userspace-api/ioctl/ioctl-decoding.rst记录了ioctl函数的32位功能码的编码规则
4 IOCTL 函数使用示例,--不传递第三个参数
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/io.h>
#include "led.h"int major;
char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led1;
unsigned int *vir_rcc
int myled_open(struct inode ,struct file *file)
{printk("%s:%s:%d\n",_FILE_,func_,_LINE_);return 0;
}
ssize_t myled_read(struct file* file ,char *ubuf,size_t size ,loff_t *lof)
{
unsigned long ret;
printk("%s ,%s ,%d\n",_FILE_,_func_,_LINE_);
if(size>sizeof(buf));
size=sizeof(kbuf);
ret=copy_to_user(ubf,kbuf,size);
if(ret)
{
printk("copy)to_user filed\n");}}
long mycdev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{switch (cmd)
{case LED_ON://开灯
vir_led1->ODR|=(0X1<<10);
vir_led2->odr |=(0X1<<10);
vir_led3->ODR|=(0X1<<8);
break;
case LED_OFF://关灯
vir_led1->ODR&=(~(0X1<<10));
vir_led2->ODR&=(~(0x1<<10));
vir_led3->ODR&=(~(0X1<<8));
break;}int all_led_init(void )
{
vir_led1=ioremp(PHY_LED1_ADDR,sizeof(gpio_t));if (vir_led1==NULL)
{
printk("iormap filed :%d\n",_LINE_);return ENOMEM;}
vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
if(vir_rcc==NULL)
{
printk("ioremap filed :%d\n",_LINE__);
return ENOMEM;}
printk("物理地址映射成功\n");
(*vir_rcc)|=(3<<4);
vir_led1->MODER &=(~(3<<20));
vir_led1->MODER |=(1<<20);
vir_led1->ODR &=(~(1<<10));
vir_led2->MODER&=(~(3<<20));
vir_led2->MODER|=(1<<20);
vir_led2>ODR &=(~(1<<10));
led3
vir_led3->MODER &=(~(3<<16));
vir_led1->MODER |=(1<<16);
vir_led1->ODR &=(~(1<<8));
printk("寄存器初始化成功");
return 0;
}
}
static int __init myled_init(void )
{major=register_chrdev(0,"mychrdev",&fops);
if(major<0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功:major=%d\n",major);all_led_init();
return 0;
}
static void_exit myled_exit(void)
{
iounmap(vir_led1);
iounmap(vir_led2);
iounmap(vir_rcc);
//注销字符设备设备驱动
unregister_chrdev(major,"mychrdev");
}
module_init(myled_init);
module_init(muled_exit);
MODULE_LICENSE("GPL");
int main(int argc, char const *argv[])
{
char buf[128]={0};
int fd=open("/dev/mychrdev",O_RDWR);
if(fd<0)
{
printf("打开设备文件失败\n");
exit(-1);}
int a;
while(1)
{
printf("请输入要进行的控制\n");
printf(":0(关灯) 1(关灯)");
printf("请输入>");
scanf("%d",&a);
switch(a)
{
case 0:
ioctl(fd,LED_OFF);
break;
case 1:
iocal(fd,LED_ON);
break;}}close(fd);
return 0;}
int major;
char kbuf[128]={0};
gpio_t *vir_led1;
gpio_t *vir_led2;
gpio_t *vir_led3;
unsigned int *vir_rcc;
int myled_open(struct inode*inode,struct file *file){printk("%s:%s :%d\n",__FILE__,__func__,__line__);return 0;
}
ssize_t myled_read(struct file *file ,char *ubuug)
if(size>sizeof(kbuf))
size=sizeof(kbuf);
ret=copy_from_user(kbuf,ubuf,size);
if(ret){
printk("copy_to_user filed\n")
return ret;}
file结构体和inode结构体的讲解分析
只要一个文件存在操作系统中,在操作系统的内核空间就会存在struct inode结构的全部信息
内核空间为了方便管理相同类型的结构,一般会把相同类型的结构构成一个顺序表或者内黑链表
所以在内核中的一定会存在一张内核链表或者顺序表 表中的每一个成员都是struct inode类型,保存了系统中多少文件,这个表中就会有多少成员,而inode编号就是当前文件在表中的索引号,而我们可以根据inode的结构体的对象进而获取文件的信息
struct inode {umode_t i_mode //保存文件的各种属性,权限,硬链接的数量
kuid_t i_uid //文件的用户ID
kgid_t i_gid//文件的用户组id
struct inode_operations *i_op//文件的操作方法结构
unsigned long
dev_t i_rdev//保存当前文件的设备号/*
MKDEV(主设备号,次设备号):根据主设备号和次设备号获取设备号
MAJOR(设备号):根据设备号获取当时设备号的·主设备号
MINOR(设备号):根据设备号获取当前设备号的次设备号}
struct file 结构体
这个结构体息息相关,只要在进程中打开一个文件,内核就会申请一个struct file类型的结构体空间,这个空间中保存了当前被打开的文件的各种信息,包含打开文件的一些属性,当前进程的开开的文件的file 构成一个内核的顺序表,文件对应描述符fd 就是顺序表的数组下标
struct file {struct path f_path;//打开文件得路径 struct inode *f_inode ;//打开前文件得innode编号 const struct file_operations *f_op //文件对应得驱动的操作方法 unsigned int f_flags//打开文件得时候需要添加的一些打开属性 unsigned int f_flags; void *private_data;}
ssize_t myled_lead(struct file*file,char *ubuf,size_t size,loff_t *lof)
{
unsigned long ret;
printk(“%s:%s:%d\n",_FILE_)
}