练习:

- #include "head.h"
-
- int major, minor = 0;
- struct cdev *cdev;
- struct class *cls;
- struct device *dev;
- //定义一个指向设备节点的指针
- struct device_node *node;
- struct device_node *node_led;
- struct device_node *node_irq;
- struct property *pr; //属性结构体指针
- int gpiono1;
- struct gpio_desc *desc_led1;
- int irqno;
- int number = 0;
- wait_queue_head_t wq_head; //定义等待对头
- int condition = 0;
- int chdev_open(struct inode *inode, struct file *file)
- {
- return 0;
- }
- int chdev_close(struct inode *inode, struct file *file)
- {
- return 0;
- }
- ssize_t chdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff)
- {
- int ret;
- //阻塞
- ret = wait_event_interruptible(wq_head, condition);
- if (ret)
- {
- printk("接收阻塞休眠\n");
- return ret;
- }
- //把父进程拷贝到内核的数据再拷贝给子进程
- if (size > sizeof(number))
- size = sizeof(number);
- ret = copy_to_user(ubuf, &number, size);
- if (ret)
- {
- printk("数据从内核向用户拷贝失败\n");
- return -EIO;
- }
- condition = 0;
-
- return size;
- }
- ssize_t chdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
- {
- return 0;
- }
- long ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- return 0;
- }
- //中断处理函数
- irqreturn_t irq_handler(int irq, void *dev)
- {
- gpiod_set_value(desc_led1, !gpiod_get_value(desc_led1));
- number ^= 1;
- //唤醒
- condition = 1;
- wake_up_interruptible(&wq_head);
- return IRQ_HANDLED;
- }
- struct file_operations fops = {
- .open = chdev_open,
- .read = chdev_read,
- .write = chdev_write,
- .release = chdev_close,
- .unlocked_ioctl = ioctl,
- };
- int pdrv_probe(struct platform_device *pdr)
- {
- //获取设备信息
- printk("%s:%d\n", __FILE__, __LINE__);
- irqno = platform_get_irq(pdr, 0);
- if (irqno < 0)
- {
- printk("获取资源失败\n");
- return irqno;
- }
- if (request_irq(irqno, irq_handler, IRQF_TRIGGER_FALLING, NULL, NULL))
- {
- printk("注册中断失败\n");
- return -1;
- }
- //获取GPIO编号
- desc_led1 = gpiod_get_from_of_node(pdr->dev.of_node, "led1", 0, GPIOD_OUT_LOW, NULL);
- if (IS_ERR(desc_led1))
- {
- printk("获取GPIO编号失败\n");
- return PTR_ERR(desc_led1);
- }
- return 0;
- }
- int pdrv_remove(struct platform_device *pdr)
- {
- printk("%s:%d\n", __FILE__, __LINE__);
- return 0;
- }
- //定义compatible表
- struct of_device_id oftable[] = {
- {.compatible = "hqyj,myplatform"},
- {},
- };
- //定义并初始化对象
- struct platform_driver pdrv = {
- .probe = pdrv_probe,
- .remove = pdrv_remove,
- .driver = {
- .name = "test",
- .of_match_table = oftable, //设备树匹配
- },
- };
- static int __init mycdev_init(void)
- {
- int ret;
- dev_t devno;
- cdev = cdev_alloc();
- if (NULL == cdev)
- {
- printk("初始化驱动设备对象失败\n");
- ret = -ENOMEM;
- goto ERR1;
- }
- cdev_init(cdev, &fops);
- ret = alloc_chrdev_region(&devno, minor, 1, "my_led");
- if (ret)
- {
- printk("申请设备号失败\n");
- goto ERR2;
- }
- major = MAJOR(devno);
- minor = MINOR(devno);
- ret = cdev_add(cdev, MKDEV(major, minor), 1);
- if (ret)
- {
- printk("字符设备驱动注册失败\n");
- goto ERR3;
- }
- cls = class_create(THIS_MODULE, "chdev_led");
- if (IS_ERR(cls))
- {
- printk("向上提交节点失败\n");
- goto ERR4;
- }
- dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "led");
- if (IS_ERR(dev))
- {
- printk("创建逻辑节点失败\n");
- ret = PTR_ERR(dev);
- goto ERR5;
- }
- //注册对象
- platform_driver_register(&pdrv);
- //初始化队列头
- init_waitqueue_head(&wq_head);
- return 0;
- ERR5:
- device_destroy(cls, MKDEV(major, 0));
- class_destroy(cls);
- ERR4:
- cdev_del(cdev);
- ERR3:
- unregister_chrdev_region(MKDEV(major, minor), 1);
- ERR2:
- kfree(cdev);
- ERR1:
- return ret;
- }
- static void __exit mycdev_exit(void)
- {
- //销毁设备节点
- device_destroy(cls, MKDEV(major, 0));
- class_destroy(cls);
- // 注销字符设备驱动
- cdev_del(cdev);
- // 释放设备号
- unregister_chrdev_region(MKDEV(major, minor), 1);
- // 释放动态申请的空间
- kfree(cdev);
-
- gpiod_set_value(desc_led1, 0);
- gpiod_put(desc_led1);
-
- //注销中断
- free_irq(irqno, NULL);
- //注销对象
- platform_driver_unregister(&pdrv);
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- MODULE_LICENSE("GPL");
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/wait.h>
- #include <sys/ioctl.h>
- #include <sys/select.h>
- #include <sys/time.h>
-
- int main(int argc, char const *argv[])
- {
- int fd;
- int number;
- char buf[128] = {};
- int which;
- fd = open("/dev/led", O_RDWR);
- if (fd < 0)
- {
- printf("打开文件失败\n");
- exit(-1);
- }
- while (1)
- {
- read(fd, &number, sizeof(number));
- printf("number = %d\n", number);
- }
-
- close(fd);
- return 0;
- }
