概念就不用多说了。。。还是直接上代码吧
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<sys/ioctl.h>
#include<errno.h>
#include"hello.h"
int main(int argc ,char* argv[]) {
int n,retval=0;
int fd;
fd = open("/dev/hc_dev0",O_RDWR);
switch(argv[1][0]) {
case '0':
ioctl(fd, HC_IOC_RESET);
printf("reset hc\n");
break;
case '1':
ioctl(fd, HC_IOCP_GET_LENS,&n);
printf("get lens pointer, %d\n",n);
break;
case '2':
n = ioctl(fd, HC_IOCV_GET_LENS);
printf("get lens value, %d\n",n);
break;
case '3':
n = argv[2][0]-'0';
retval = ioctl(fd, HC_IOCP_SET_LENS, &n);
printf("set lens value, %d %s\n",n,strerror(errno));
break;
case '4':
n = argv[2][0]-'0';
retval = ioctl(fd, HC_IOCV_SET_LENS,n);
printf("set lens value, %d %s\n",n,strerror(errno));
break;
}
close(fd);
return 0;
}
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<linux/uaccess.h>
#include<linux/sched.h>
#include "hello.h"
#define HELLO_MAJOR 0
#define HELLO_NR_DEVS 2
int hello_major = HELLO_MAJOR;
int hello_minor = 0;
/*高12位是主设备号,低20位是次设备号*/
dev_t devt;
int hello_nr_devs = HELLO_NR_DEVS;
module_param(hello_major, int, S_IRUGO);
module_param(hello_minor, int, S_IRUGO);
module_param(hello_nr_devs, int, S_IRUGO);
/*实际的字符设备驱动*/
struct hello_char_dev {
struct cdev cdev; /*类似继承,继承设备的属性*/
char *c;/*字符指针*/
int n; /*可以理解为当前指针对起始指针的偏移量*/
};
struct hello_char_dev *hc_devp;
struct class *hc_cls;
int hc_open(struct inode *inode, struct file *filp) {
struct hello_char_dev *hc_dev;
printk(KERN_INFO "%s open \n", current->comm);
/*获取设备结构体的地址*/
hc_dev = container_of(inode->i_cdev, struct hello_char_dev, cdev);
/*将设备结构地址放到文件描述符结构的私有数据中,方便后面操作*/
filp->private_data = hc_dev;
return 0;
}
ssize_t hc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
ssize_t retval = 0;
struct hello_char_dev *hc_dev = filp->private_data;
/*判断读的网址是否超出范围*/
if(*f_pos >= hc_dev->n)
goto out;
/*如果当前读的起始字节加上要读取的字节数成功范围,
那么要读取的字节数改为最多可以读取的字节数*/
if(*f_pos + count > hc_dev->n)
count = hc_dev->n - *f_pos;
/*将设备的数据拷贝到用户空间*/
if(copy_to_user(buf, hc_dev->c, count)) {
retval = -EFAULT;
goto out;
}
/*当前位置调整*/
*f_pos += count;
return count;
out:
return retval;
}
ssize_t hc_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) {
struct hello_char_dev *hc_dev = filp->private_data;
int retval = -ENOMEM;
kfree(hc_dev->c);
hc_dev->c = NULL;
hc_dev->n = 0;
hc_dev->c = kzalloc(count,GFP_KERNEL);
if(!hc_dev->c)
goto out;
if(copy_from_user(hc_dev->c, buf, count)) {
retval = -EFAULT;
goto fail_copy;
}
hc_dev->n = count;
return count;
fail_copy:
kfree(hc_dev->c);
out:
return retval;
}
int hc_release(struct inode *inode, struct file *filp) {
printk(KERN_INFO "%s release\n",current->comm);
return 0;
}
long hc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
struct hello_char_dev *hc_dev = filp->private_data;
long retval = 0;
int tmp, err=0;
/*下面几步是固定套路*/
if (_IOC_TYPE(cmd) != HC_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > HC_IOC_MAXNR)
return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok((void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
switch(cmd) {
case HC_IOC_RESET:
printk(KERN_INFO "ioctl reset\n");
kfree(hc_dev->c);
hc_dev->n=0;
break;
case HC_IOCP_GET_LENS:
printk(KERN_INFO "ioctl get lens through pointer\n");
retval = __put_user(hc_dev->n,(int __user *)arg);
break;
case HC_IOCV_GET_LENS:
printk(KERN_INFO "ioctl get lens through value\n");
return hc_dev->n;
break;
case HC_IOCP_SET_LENS:
/*要赋予进程一些权限, 执行需要加sudo*/
printk(KERN_INFO "ioctl set lens through pointer");
if (!capable (CAP_SYS_ADMIN))
return -EPERM;
retval = get_user(tmp,(int __user *)arg);
if(hc_dev->n > tmp)
hc_dev->n = tmp;
printk(KERN_INFO " %d\n",hc_dev->n);
break;
case HC_IOCV_SET_LENS:
/*要赋予进程一些权限, 执行需要加sudo*/
printk(KERN_INFO "ioctl set lens through value");
if (!capable (CAP_SYS_ADMIN))
return -EPERM;
hc_dev->n = min(hc_dev->n, (int)arg);
printk(KERN_INFO " %d\n", hc_dev->n);
break;
default:
break;
}
return retval;
}
/*字符设备的操作函数*/
struct file_operations hc_fops = {
.owner = THIS_MODULE,
.read = hc_read,
.write = hc_write,
.open = hc_open,
.release = hc_release,
/*让应用层和驱动直接通信*/
.unlocked_ioctl = hc_ioctl,
};
static int __init hello_init(void) {
int ret = 0, i = 0;
/*使用相关api分配设备号*/
if(hello_major) {
/*静态分配,指定主次设备号*/
devt = MKDEV(hello_major, hello_minor);
ret = register_chrdev_region(devt, hello_nr_devs, "hello_chr");
}
else{
ret = alloc_chrdev_region(&devt,hello_minor, hello_nr_devs, "hello_chr");
hello_major = MAJOR(devt);
}
/*判断分配是否成功*/
if (ret < 0) {
printk(KERN_WARNING "hello: can't get major %d\n", hello_major);
goto fail;
}
/*给字符设备分配空间*/
hc_devp = kzalloc(sizeof(struct hello_char_dev)*hello_nr_devs, GFP_KERNEL);
if(!hc_devp) {
printk(KERN_WARNING "alloc mem failed");
ret = -ENOMEM;
goto failure_kzalloc;
}
for(i=0; i<hello_nr_devs; i++) {
/*初始化字符设备结构*/
cdev_init(&hc_devp[i].cdev, &hc_fops);
hc_devp[i].cdev.owner = THIS_MODULE;
ret = cdev_add(&hc_devp[i].cdev, MKDEV(hello_major,hello_minor+i), 1);
if(ret) {
printk(KERN_WARNING"fail add hc_dev%d",i);
}
}
hc_cls = class_create(THIS_MODULE, "hc_dev");
if(!hc_cls) {
printk(KERN_WARNING"fail create class");
ret = PTR_ERR(hc_cls);
goto failure_class;
}
for(i=0; i<hello_nr_devs; i++) {
device_create(hc_cls, NULL, MKDEV(hello_major,hello_minor+i), NULL, "hc_dev%d", i);
}
return 0;
failure_class:
kfree(hc_devp);
failure_kzalloc:
unregister_chrdev_region(devt, hello_nr_devs);
fail:
return ret;
}
static void __exit hello_exit(void) {
int i;
for(i = 0; i<hello_nr_devs; i++) {
device_destroy(hc_cls, MKDEV(hello_major, hello_minor + i));
}
class_destroy(hc_cls);
for(i=0; i<hello_nr_devs; i++) {
kfree(hc_devp[i].c);
cdev_del(&hc_devp[i].cdev);
}
kfree(hc_devp);
/*移除模块时释放设备号*/
unregister_chrdev_region(devt, hello_nr_devs);
}
/*模块入出口函数*/
module_init(hello_init);
module_exit(hello_exit);
/*模块描述*/
MODULE_LICENSE("BSD");
MODULE_AUTHOR("XXX");
MODULE_VERSION("V1");
#ifndef _HELLO_CHR_LOCKED_H_
#define _HELLO_CHR_LOCKED_H_
#define HC_IOC_MAGIC 0x81 //Documentation/userspace-api/ioctl/ioctl-number.rst
#define HC_IOC_RESET _IO(HC_IOC_MAGIC,0)
#define HC_IOCP_GET_LENS _IOR(HC_IOC_MAGIC,1,int) //通过指针返回
#define HC_IOCV_GET_LENS _IO(HC_IOC_MAGIC,2) //通过返回值返回
#define HC_IOCP_SET_LENS _IOW(HC_IOC_MAGIC,3,int) //通过指针设置
#define HC_IOCV_SET_LENS _IO(HC_IOC_MAGIC,4) //通过值设置
#define HC_IOC_MAXNR 4
#endif