旅游网站名字,邵东微网站建设,儿童 网站模板,自建电商平台方案一、ioctl操作实现
ioctl#xff08;Input/Output Control#xff09;是一个在 Unix-like 操作系统中的系统调用#xff0c;用于控制设备或文件的各种操作。它允许用户空间程序与内核空间进行交互#xff0c;执行一些特定的设备控制、状态查询或其他操作#xff0c;而不必…一、ioctl操作实现
ioctlInput/Output Control是一个在 Unix-like 操作系统中的系统调用用于控制设备或文件的各种操作。它允许用户空间程序与内核空间进行交互执行一些特定的设备控制、状态查询或其他操作而不必读写设备文件本身。
已知成员的地址获得所在结构体变量的地址container_of(成员地址,结构体类型名成员在结构体中的名称)
long xxx_ioctl (struct file *filp, unsigned int cmd, unsigned long arg);
功能对相应设备做指定的控制操作各种属性的设置获取等等
参数filp指向open产生的struct file类型的对象表示本次ioctl对应的那次opencmd用来表示做的是哪一个操作arg和cmd配合用的参数
返回值成功为0失败-1cmd组成 dirdirectionioctl 命令访问模式属性数据传输方向占据 2 bit可以为 _IOC_NONE、_IOC_READ、_IOC_WRITE、_IOC_READ | _IOC_WRITE分别指示了四种访问模式无数据、读数据、写数据、读写数据typedevice type设备类型占据 8 bit在一些文献中翻译为 “幻数” 或者 “魔数”可以为任意 char 型字符例如 ‘a’、’b’、’c’ 等等其主要作用是使 ioctl 命令有唯一的设备标识nrnumber命令编号/序数占据 8 bit可以为任意 unsigned char 型数据取值范围 0~255如果定义了多个 ioctl 命令通常从 0 开始编号递增size涉及到 ioctl 函数 第三个参数 arg 占据 13bit 或者 14bit体系相关arm 架构一般为 14 位指定了 arg 的数据类型及长度如果在驱动的 ioctl 实现中不检查通常可以忽略该参数
#define _IOC(dir,type,nr,size) (((dir)_IOC_DIRSHIFT)| \((type)_IOC_TYPESHIFT)| \((nr)_IOC_NRSHIFT)| \((size)_IOC_SIZESHIFT))
/* used to create numbers */// 定义不带参数的 ioctl 命令
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)//定义带读参数的ioctl命令copy_to_user size为类型名
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))//定义带写参数的 ioctl 命令copy_from_user size为类型名
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))//定义带读写参数的 ioctl 命令 size为类型名
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))/* used to decode ioctl numbers */
#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)示例 mychar.h
#ifndef MY_CHAR_H
#define MY_CHAR_H#include asm/ioctl.h#define MY_CHAR_MAGIC c#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC, 1, int *)
#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC, 2, int *)#endif mychar.c
#include linux/module.h
#include linux/kernel.h
#include linux/fs.h
#include linux/cdev.h
#include linux/wait.h
#include linux/sched.h
#include asm/uaccess.h
#include asm/ioctl.h#include mychar.h#define BUF_LEN 100int major 11; //主设备号
int minor 0; //次设备号
int char_num 1; //设备号数量struct mychar_dev
{struct cdev mydev;char mydev_buf[BUF_LEN];int curlen;
};
struct mychar_dev gmydev;int mychar_open (struct inode *pnode, struct file *pfile)//打开设备
{pfile-private_data (void *) (container_of(pnode-i_cdev, struct mychar_dev, mydev));printk(open\n);return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)//关闭设备
{printk(close\n);return 0;
}ssize_t mychar_read (struct file *pfile, char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;// 确定要读取的数据长度如果请求大于设备当前数据长度则读取全部可用数据if (count pmydev-curlen) {size pmydev-curlen;}else {size count;}// 将设备数据复制到用户空间缓冲区ret copy_to_user(puser, pmydev-mydev_buf, size);if(ret) {printk(copy_to_user failed\n);return -1;}// 移动设备内部缓冲区去除已读取的数据memcpy(pmydev-mydev_buf, pmydev-mydev_buf size, pmydev-curlen - size);pmydev-curlen - size;// 返回实际读取的字节数return size;
}ssize_t mychar_write (struct file *pfile, const char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;// 确定要写入的数据长度如果请求大于设备缓冲区剩余空间则写入剩余空间大小if (count BUF_LEN - pmydev-curlen) {size BUF_LEN - pmydev-curlen;}else {size count;}// 从用户空间复制数据到设备缓冲区ret copy_from_user(pmydev-mydev_buf pmydev-curlen, puser, size);if(ret) {printk(copy_from_user failed\n);return -1;}// 更新设备缓冲区中的数据长度pmydev-curlen size;// 返回实际写入的字节数return size;
}long mychar_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int __user *pret (int *)arg;int maxlen BUF_LEN;int ret 0;switch(cmd) {case MYCHAR_IOCTL_GET_MAXLEN:ret copy_to_user(pret, maxlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret copy_to_user(pret, pmydev-curlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;default:printk(The is a know\n);return -1;}return 0;
}struct file_operations myops {.owner THIS_MODULE,.open mychar_open,.read mychar_read,.write mychar_write,
};int __init mychar_init(void)
{int ret 0;dev_t devno MKDEV(major, minor);/* 手动申请设备号 */ret register_chrdev_region(devno, char_num, mychar);if (ret) {/* 动态申请设备号 */ret alloc_chrdev_region(devno, minor, char_num, mychar);if(ret){printk(get devno failed\n);return -1;}/*申请成功 更新设备号*/major MAJOR(devno);}/* 给struct cdev对象指定操作函数集 */cdev_init(gmydev.mydev, myops);/* 将struct cdev对象添加到内核对应的数据结构中 */gmydev.mydev.owner THIS_MODULE;cdev_add(gmydev.mydev, devno, char_num);return 0;
}void __exit mychar_exit(void)
{dev_t devno MKDEV(major, minor);printk(exit %d\n, devno);/* 从内核中移除一个字符设备 */cdev_del(gmydev.mydev);/* 回收设备号 */unregister_chrdev_region(devno, char_num);}MODULE_LICENSE(GPL);
module_init(mychar_init);
module_exit(mychar_exit);testmychar_app.c
#include stdio.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include sys/ioctl.h#include mychar.h
int main(int argc, char *argv[])
{int fd -1;char buf[32] ;int max 0;int cur 0;if(argc 2) {printf(The argument is too few\n);return -1;}fd open(argv[1], O_RDWR);if(fd 0) {perror(open);return -1;}ioctl(fd, MYCHAR_IOCTL_GET_MAXLEN, max);printf(max len is %d\n, max);write(fd, hello, 6);ioctl(fd, MYCHAR_IOCTL_GET_CURLEN, cur);read(fd, buf, 32);printf(cur len is %d\n, cur);printf(buf %s\n, buf);close(fd);fd -1;return 0;
}运行结果
二、printk
//日志级别
#define KERN_EMERG 0 /* system is unusable */
#define KERN_ALERT 1 /* action must be taken immediately */
#define KERN_CRIT 2 /* critical conditions */
#define KERN_ERR 3 /* error conditions */#define KERN_WARNING 4 /* warning conditions */#define KERN_NOTICE 5 /* normal but significant condition */
#define KERN_INFO 6 /* informational */
#define KERN_DEBUG 7 /* debug-level messages */用法printk(KERN_INFO....,....)printk(KERN_INFOHello World); printk(6Hello World) printk(6Hello World)
dmesg --levelemerg,alert,crit,err,warn,notice,info,debug
#define HELLO_DEBUG
#undef PDEBUG
#ifdef HELLO_DEBUG
#define PDEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args)
#else
#define PDEBUG(fmt, args...)
#endif
三、多个次设备的支持
每一个具体设备次设备不一样的设备必须有一个struct cdev来代表它
cdev_init
cdev.owner赋值
cdev_add
以上三个操作对每个具体设备都要进行
示例
#include linux/module.h
#include linux/kernel.h
#include linux/fs.h
#include linux/cdev.h
#include asm/uaccess.h
#include asm/ioctl.h#include mychar.h#define BUF_LEN 100
#define MYCHAR_DEV_CNT 3int major 11; //主设备号
int minor 0; //次设备号
int char_num MYCHAR_DEV_CNT; //设备号数量struct mychar_dev
{struct cdev mydev;char mydev_buf[BUF_LEN];int curlen;
};
struct mychar_dev gmydev[MYCHAR_DEV_CNT];int mychar_open (struct inode *pnode, struct file *pfile)//打开设备
{pfile-private_data (void *) (container_of(pnode-i_cdev, struct mychar_dev, mydev));printk(open\n);return 0;
}int mychar_close(struct inode *pnode, struct file *pfile)//关闭设备
{printk(close\n);return 0;
}ssize_t mychar_read (struct file *pfile, char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;// 确定要读取的数据长度如果请求大于设备当前数据长度则读取全部可用数据if (count pmydev-curlen) {size pmydev-curlen;}else {size count;}// 将设备数据复制到用户空间缓冲区ret copy_to_user(puser, pmydev-mydev_buf, size);if(ret) {printk(copy_to_user failed\n);return -1;}// 移动设备内部缓冲区去除已读取的数据memcpy(pmydev-mydev_buf, pmydev-mydev_buf size, pmydev-curlen - size);pmydev-curlen - size;// 返回实际读取的字节数return size;
}ssize_t mychar_write (struct file *pfile, const char __user *puser, size_t count, loff_t *p_pos) {struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int size 0;int ret 0;// 确定要写入的数据长度如果请求大于设备缓冲区剩余空间则写入剩余空间大小if (count BUF_LEN - pmydev-curlen) {size BUF_LEN - pmydev-curlen;}else {size count;}// 从用户空间复制数据到设备缓冲区ret copy_from_user(pmydev-mydev_buf pmydev-curlen, puser, size);if(ret) {printk(copy_from_user failed\n);return -1;}// 更新设备缓冲区中的数据长度pmydev-curlen size;// 返回实际写入的字节数return size;
}long mychar_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg)
{struct mychar_dev *pmydev (struct mychar_dev *)pfile-private_data;int __user *pret (int *)arg;int maxlen BUF_LEN;int ret 0;switch(cmd) {case MYCHAR_IOCTL_GET_MAXLEN:ret copy_to_user(pret, maxlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;case MYCHAR_IOCTL_GET_CURLEN:ret copy_to_user(pret, pmydev-curlen, sizeof(int));if(ret) {printk(copy_from_user failed\n);return -1;}break;default:printk(The is a know\n);return -1;}return 0;
}struct file_operations myops {.owner THIS_MODULE,.open mychar_open,.read mychar_read,.write mychar_write,.unlocked_ioctl mychar_ioctl,
};int __init mychar_init(void)
{int ret 0;int i;dev_t devno MKDEV(major, minor);/* 手动申请设备号 */ret register_chrdev_region(devno, char_num, mychar);if (ret) {/* 动态申请设备号 */ret alloc_chrdev_region(devno, minor, char_num, mychar);if(ret){printk(get devno failed\n);return -1;}/*申请成功 更新设备号*/major MAJOR(devno);}for(i 0; i MYCHAR_DEV_CNT; i) {devno MKDEV(major, minor i);cdev_init(gmydev[i].mydev, myops);gmydev[i].mydev.owner THIS_MODULE;cdev_add(gmydev[i].mydev, devno, 1);}return 0;
}void __exit mychar_exit(void)
{int i;dev_t devno MKDEV(major, minor);printk(exit %d\n, devno);for(i 0; i MYCHAR_DEV_CNT; i) {/* 从内核中移除一个字符设备 */cdev_del(gmydev[i].mydev);}/* 回收设备号 */unregister_chrdev_region(devno, char_num);}MODULE_LICENSE(GPL);
module_init(mychar_init);
module_exit(mychar_exit);