#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 _IO('L',0)#define CMD_TEST1 _IOW('L',1,int)#define CMD_TEST2 _IOR('L',2,int)structdevice_test{dev_t dev_num; //设备号int major ; //主设备号int minor ; //次设备号structcdevcdev_test;// cdevstructclass *class;//类structdevice *device;//设备char kbuf[32];};staticstructdevice_testdev1;staticlongcdev_test_ioctl(struct file *file, unsignedint cmd, unsignedlong arg){int val;//定义int类型向应用空间传递的变量valswitch(cmd){case CMD_TEST0: printk("this is CMD_TEST0\n");break; case CMD_TEST1: printk("this is CMD_TEST1\n"); printk("arg is %ld\n",arg);//打印应用空间传递来的arg参数break;case CMD_TEST2: val = 1;//将要传递的变量val赋值为1 printk("this is CMD_TEST2\n");if(copy_to_user((int *)arg,&val,sizeof(val)) != 0){//通过copy_to_user向用户空间传递数据 printk("copy_to_user error \n"); }break; default:break; }return0;}/*设备操作函数*/structfile_operationscdev_test_fops = { .owner = THIS_MODULE, //将owner字段指向本模块,可以避免在模块的操作正在被使用时卸载该模块 .unlocked_ioctl = cdev_test_ioctl,};staticint __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; }return0;err_device_create: class_destroy(dev1.class); //删除类err_class_create: cdev_del(&dev1.cdev_test); //删除cdeverr_chr_add: unregister_chrdev_region(dev1.dev_num, 1); //注销设备号err_chrdev:return ret;}staticvoid __exittimer_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");
#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<sys/ioctl.h>#include<string.h>#define CMD_TEST0 _IO('L',0)#define CMD_TEST1 _IOW('L',1,int)#define CMD_TEST2 _IOR('L',2,int)intmain(int argc,char *argv[]){int fd;//定义int类型的文件描述符fdint val;//定义int类型的传递参数val fd = open("/dev/test",O_RDWR);//打开test设备节点if(fd < 0){printf("file open fail\n"); }if(!strcmp(argv[1], "write")){ ioctl(fd,CMD_TEST1,1);//如果第二个参数为write,向内核空间写入1 }elseif(!strcmp(argv[1], "read")){ ioctl(fd,CMD_TEST2,&val);//如果第二个参数为read,则读取内核空间传递向用户空间传递的值printf("val is %d\n",val); } close(fd);}