drv.c
#include
#include #include #include #include #include #include #include #include #include #include #include #include #include #include //获取资源结构体 struct resource *res; //中断号 unsigned int irqno; //gpio信息结构体 struct gpio_desc *gpiono; //字符设备驱动对象空间首地址 struct cdev *cdev; char kbuf[128] = {0}; //主设备号 unsigned int major = 0; //次设备号 unsigned int minor = 0; //设备号 dev_t devno; module_param(major,uint,0664); //方便在命令行传递major的值 //用于保存目录信息 struct class *cls; //用于保存设备节点信息 struct device *dev; int number = 0; unsigned int condition = 0; wait_queue_head_t wq_head; //中断处理函数 irqreturn_t key_handler(int irq,void *dev) { gpiod_set_value(gpiono,!(gpiod_get_value(gpiono))); number = !number; condition = 1; wake_up_interruptible(&wq_head); return IRQ_HANDLED; } int mycdev_open(struct inode *inode, struct file *file) { printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); return 0; } ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof) { printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); int ret; //向用户空间读取拷贝 if(size>sizeof(number))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小 size=sizeof(number); //切换进程为休眠态 wait_event_interruptible(wq_head,condition); ret=copy_to_user(ubuf,&number,size); if(ret)//拷贝失败 { printk("copy_to_user filed\n"); return ret; } condition = 0; return 0; } int mycdev_close(struct inode *inode, struct file *file) { printk("%s:%s:%d\n",__FILE__,__func__,__LINE__); return 0; } //定义操作方法结构体变量并赋值 struct file_operations fops={ .open=mycdev_open, .read=mycdev_read, .release=mycdev_close, }; //封装probe函数 int pdrv_probe(struct platform_device *pdev) { int ret; // 为字符设备驱动对象申请空间 cdev = cdev_alloc(); if (cdev == NULL) { printk("字符设备驱动对象申请空间失败\n"); ret = -EFAULT; goto out1; } printk("申请对象空间成功\n"); // 初始化字符设备驱动对象 cdev_init(cdev, &fops); // 申请设备号 if (major > 0) // 静态指定设备号 { ret = register_chrdev_region(MKDEV(major, minor), 3, "myplatform"); if (ret) { printk("静态申请设备号失败\n"); goto out2; } } else if (major == 0) // 动态申请设备号 { ret = alloc_chrdev_region(&devno, minor, 3, "myplatform"); if (ret) { printk("动态申请设备号失败\n"); goto out2; } major = MAJOR(devno); // 获取主设备号 minor = MINOR(devno); // 获取次设备号 } printk("申请设备号成功\n"); // 注册字符设备驱动对象 ret = cdev_add(cdev, MKDEV(major, minor), 3); if (ret) { printk("注册字符设备驱动对象失败\n"); goto out3; } printk("注册字符设备驱动对象成功\n"); // 向上提交目录信息 cls = class_create(THIS_MODULE, "myplatform"); if (IS_ERR(cls)) { printk("向上提交目录失败\n"); ret = -PTR_ERR(cls); goto out4; } printk("向上提交目录成功\n"); // 向上提交设备节点信息 int i; for (i = 0; i < 3; i++) { dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myplatform%d", i); if (IS_ERR(dev)) { printk("向上提交设备节点信息失败\n"); ret = -PTR_ERR(dev); goto out5; } } printk("向上提交设备信息成功\n"); //初始化等待队列头 init_waitqueue_head(&wq_head); //获取MEM类型的资源 res = platform_get_resource(pdev,IORESOURCE_MEM,0); if(res == NULL) { printk("获取MEM类型资源失败\n"); return -ENXIO; } //获取中断类型的资源 irqno = platform_get_irq(pdev,0); if(irqno < 0) { printk("获取中断类型资源失败\n"); return -ENXIO; } //注册中断 int ret1 = request_irq(irqno,key_handler,IRQF_TRIGGER_FALLING,"key_int",NULL); if(ret1<0) { printk("注册按键1中断失败\n"); return ret1; } printk("注册按键1中断成功\n"); printk("mem资源%llx\n",res->start); printk("irq资源%d\n",irqno); printk("%s;%s:%d\n",__FILE__,__func__,__LINE__); //设备树匹配成功后,设备树节点指针可以通过pdev->dev.of_node获取 //基于设备树节点信息获取gpio_desc对象指针 gpiono = gpiod_get_from_of_node(pdev->dev.of_node,"led3-gpio",0,GPIOD_OUT_LOW,NULL); if(IS_ERR(gpiono)) { printk("解析GPIO管脚信息失败\n"); return -ENXIO; } printk("解析GPIO管脚信息成功\n"); return 0; out5: // 释放前一次提交成功的设备信息 for (--i; i >= 0; i--) { device_destroy(cls, MKDEV(major, i)); } class_destroy(cls); // 释放目录 out4: cdev_del(cdev); out3: unregister_chrdev_region(MKDEV(major, minor), 3); out2: kfree(cdev); out1: return ret; } //封装remove函数 int pdrv_remove(struct platform_device *pdev) { //关灯 gpiod_set_value(gpiono,0); //释放GPIO信息 gpiod_put(gpiono); //注销中断 free_irq(irqno,NULL); // 释放节点信息 int i; for (i = 0; i < 3; i++) { device_destroy(cls, MKDEV(major, i)); } // 销毁目录 class_destroy(cls); // 注销驱动对象 cdev_del(cdev); // 释放设备号 unregister_chrdev_region(MKDEV(major, minor), 3); // 释放对象空间 kfree(cdev); printk("%s;%s:%d\n",__FILE__,__func__,__LINE__); return 0; } //构建设备树匹配表 struct of_device_id oftable[] = { { .compatible = "hqyj,myplatform"}, { /* end node */ },//防止数组越界 }; //定义驱动信息对象并初始化 struct platform_driver pdrv = { .probe = pdrv_probe, .remove = pdrv_remove, .driver = { .name = "bbbbb", .of_match_table=oftable,//用于设备树匹配 }, }; //一键注册宏 module_platform_driver(pdrv); MODULE_LICENSE("GPL");
app.c
#include
#include #include #include #include #include #include #include int main(int argc, const char *argv[]) { int buf[128] = {0}; int fd; // 打开设备节点 fd = open("/dev/myplatform0", O_RDWR); if (fd < 0) { printf("设备文件打开失败\n"); exit(-1); } while(1) { read(fd,buf,sizeof(buf)); printf("number=%d\n",buf); } close(fd); return 0; }