两个字符驱动实例second 及 globalfifo
2017-08-15 10:54
218 查看
second_dri.c
second_dev.c
Makefile
驱动与设备分开, 此驱动还有缺陷 当 通过echo 0 >/sys/class/second/second/trigger , 会一直进行这个重复操作,原因待查。
globalfifo.c
globalfifo-dev.c
#include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/of_device.h> #include <linux/delay.h> #define SECOND_MAJOR 237 #define USE_MUTEX static int second_major = SECOND_MAJOR; module_param(second_major, int, S_IRUGO); static struct class *second_class; struct second_dev *second_devp; struct second_dev { struct cdev cdev; #ifndef USE_MUTEX atomic_t counter; #else int counter; #endif unsigned long state; // 1 start timer, 0 timer stop struct mutex mutex; struct timer_list s_timer; struct device *dev; struct miscdevice miscdev; const struct attribute_group **groups; struct work_struct mywork; }; //static struct second_dev *second_devp_; static void second_timer_handler(unsigned long arg) { struct second_dev *dev = (void *) arg; mod_timer(&dev->s_timer, jiffies + HZ); #ifndef USE_MUTEX atomic_inc(&dev->counter); #else printk(KERN_INFO "%s mutex lock\n", __func__); mutex_lock(&dev->mutex); dev->counter++; mutex_unlock(&dev->mutex); #endif // printk(KERN_INFO "current jiffies is %ld\n", jiffies); } static void second_timer_ctl(struct work_struct *ws) { struct second_dev *dev = container_of(ws, struct second_dev, mywork); int ret = 0; printk(KERN_INFO "%s trigger_store test\n", __func__); msleep(500); return; } static int second_open(struct inode *inode, struct file *filp) { /* init_timer(&second_devp->s_timer); second_devp->s_timer.function = &second_timer_handler; second_devp->s_timer.expires = jiffies + HZ; add_timer(&second_devp->s_timer); */ // struct second_dev *second_devp = container_of(filp->private_data, // struct second_dev, miscdev); // struct second_dev *second_devp = container_of(inode->i_cdev, struct second_dev, cdev); mutex_lock(&second_devp->mutex); if(second_devp->state == 0) { setup_timer(&second_devp->s_timer, second_timer_handler, (unsigned long)second_devp); add_timer(&second_devp->s_timer); second_devp->state = 1; } mutex_unlock(&second_devp->mutex); // filp->private_data = second_devp; printk(KERN_INFO "%s-open 1\n", __func__); return 0; } static int second_release(struct inode *inode, struct file *filp) { return 0; } static ssize_t second_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) { int counter; // struct second_dev *second_devp = filp->private_data; // struct second_dev *second_devp = container_of(filp->private_data, // struct second_dev, miscdev); #ifndef USE_MUTEX counter = atomic_read(&second_devp->counter); #else printk(KERN_INFO "%s mutex lock\n", __func__); mutex_lock(&second_devp->mutex); counter = second_devp->counter; mutex_unlock(&second_devp->mutex); #endif if(put_user(counter, (int *)buf)) return -EFAULT; else return sizeof(unsigned int); } static ssize_t second_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { return 0; } ssize_t trigger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct second_dev *sdev = dev_get_drvdata(dev); unsigned long state; ssize_t ret = 0; printk(KERN_INFO "%s: 0 -state \n", __func__); return 0; #ifdef USE_MUTEX mutex_lock(&sdev->mutex); ret = kstrtoul(buf, 10, &state); if (ret) goto unlock; printk(KERN_INFO "%s: 0 - mutex lock, state = %ld\n", __func__, state); schedule_work(&sdev->mywork); goto unlock; if (state == 1) { printk(KERN_INFO "%s: 1 - mutex lock, state = %ld\n", __func__, state); if (sdev->state == 0) { setup_timer(&second_devp->s_timer, second_timer_handler, (unsigned long)second_devp); add_timer(&sdev->s_timer); sdev->state = 1; } } else { printk(KERN_INFO "%s: 2 - mutex lock, state = %ld\n", __func__, state); if(sdev->state == 1) { del_timer(&sdev->s_timer); sdev->state = 0; } } printk(KERN_INFO "%s: 3 - mutex lock, state = %ld\n", __func__, state); unlock: mutex_unlock(&dev->mutex); #endif return ret; } ssize_t trigger_show(struct device *dev, struct device_attribute *attr, char *buf) { int cnt = -1; struct second_dev *sdev = dev_get_drvdata(dev); // int *counter = dev_get_drvdata(dev); //printk(KERN_INFO "counter_addr=%p", counter); #ifndef USE_MUTEX cnt = atomic_read(&sdev->counter); #else printk(KERN_INFO "%s mutex lock\n", __func__); mutex_lock(&sdev->mutex); // mutex_lock_interruptible(&second_devp->mutex); cnt = sdev->counter; mutex_unlock(&sdev->mutex); #endif return sprintf(buf, "second_trigger_show: count =%d\n", cnt); // return sprintf(buf, "second_trigger_show: count = %d, counter_addr=%p\n", *counter, counter); } //static DEVICE_ATTR_RW(trigger); static DEVICE_ATTR(trigger, 0644, trigger_show, trigger_store); static struct attribute *second_trigger_attrs[] = { &dev_attr_trigger.attr, NULL, }; static const struct attribute_group second_trigger_group = { .attrs = second_trigger_attrs, }; static const struct attribute_group *second_groups[] = { &second_trigger_group, }; static const struct file_operations second_fops = { .owner = THIS_MODULE, .open = second_open, .release= second_release, .read = second_read, .write = second_write, }; static int second_probe(struct platform_device *pdev) { int ret, err; struct device *dev = &pdev->dev; dev_t devno = MKDEV(SECOND_MAJOR, 0); if(SECOND_MAJOR) { ret = register_chrdev_region(devno, 1, "second"); } else { ret = alloc_chrdev_region(&devno, 0, 1, "second"); second_major = MAJOR(devno); } if(ret < 0) return ret; second_devp = devm_kzalloc(dev, sizeof(*second_devp), GFP_KERNEL); if(!second_devp) { dev_info(&pdev->dev, "second_devp devm_kzalloc failed\n"); return -ENOMEM; } #ifndef USE_MUTEX atomic_set(&second_devp->counter, 0); #else printk(KERN_INFO "%s mutex lock\n", __func__); mutex_init(&second_devp->mutex); mutex_lock(&second_devp->mutex); second_devp->counter = 0; second_devp->state = 0; mutex_unlock(&second_devp->mutex); #endif INIT_WORK(&second_devp->mywork, second_timer_ctl); cdev_init(&second_devp->cdev, &second_fops); second_devp->cdev.owner = THIS_MODULE; err = cdev_add(&second_devp->cdev, devno, 1); if(err) { printk(KERN_DEBUG "Error %d adding second\n", err); goto fail_malloc; } second_devp->dev = device_create(second_class, dev, MKDEV(SECOND_MAJOR, 0), second_devp, "second"); // platform_set_drvdata(pdev, second_devp); dev_info(&pdev->dev, "second_dev drv proded\n"); return 0; fail_malloc: printk(KERN_INFO "6 - probe failed\n"); unregister_chrdev_region( MKDEV(SECOND_MAJOR, 0), 1); return ret; } static int second_remove(struct platform_device *pdev) { return 0; } static struct platform_driver second_driver = { .driver = { .name = "second_dev", .owner = THIS_MODULE, }, .probe = second_probe, .remove = second_remove, }; static int __init second_init(void) { int ret; second_class = class_create(THIS_MODULE, "second"); if (IS_ERR(second_class)) return PTR_ERR(second_class); second_class->dev_groups = second_groups; ret = platform_driver_register(&second_driver); if (ret) printk(KERN_ERR "second: probe failed: %d\n", ret); return ret; } module_init(second_init); static void __exit second_exit(void) { if(second_devp) { cdev_del(&second_devp->cdev); del_timer(&second_devp->s_timer); } device_destroy(second_class, MKDEV(SECOND_MAJOR, 0)); class_destroy(second_class); unregister_chrdev_region(MKDEV(SECOND_MAJOR, 0), 1); platform_driver_unregister(&second_driver); printk(KERN_INFO "second: exit\n"); } module_exit(second_exit); //module_platform_driver(second_driver); MODULE_AUTHOR("Bao hua"); MODULE_LICENSE("GPL v2");
second_dev.c
#include <linux/module.h> #include <linux/of_device.h> static struct platform_device *second_pdev; static int __init seconddev_init(void) { int ret; second_pdev = platform_device_alloc("second_dev", -1); if(!second_pdev) return -ENOMEM; ret = platform_device_add(second_pdev); if(ret) { platform_device_put(second_pdev); return ret; } return 0; } module_init(seconddev_init); static void __exit seconddev_exit(void) { platform_device_unregister(second_pdev); } module_exit(seconddev_exit); MODULE_AUTHOR("Bao hua"); MODULE_LICENSE("GPL v2");
Makefile
KVERS = $(shell uname -r) #Kernel modules obj-m += second.o obj-m += second_test.o #obj-m += second_mutex.o obj-m += second_dri.o obj-m += second_dev.o build: kernel_modules kernel_modules: make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules user_test: gcc test.c -o test clean: make -c /lib/modules/$(KVERS)/build M=$(CURDIR) clean
驱动与设备分开, 此驱动还有缺陷 当 通过echo 0 >/sys/class/second/second/trigger , 会一直进行这个重复操作,原因待查。
globalfifo.c
/* * a simple char device driver: globalfifo * * Copyright (C) 2014 Barry Song (baohua@kernel.org) * * Licensed under GPLv2 or later. */ #include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/slab.h> #include <linux/uaccess.h> #include <linux/mutex.h> #include <linux/slab.h> #include <linux/poll.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/of_device.h> #define GLOBALFIFO_SIZE 0x1000 #define FIFO_CLEAR 0x1 #define GLOBALFIFO_MAJOR 235 static int globalfifo_major = GLOBALFIFO_MAJOR; module_param(globalfifo_major, int, S_IRUGO); static struct class *globalfifo_class; struct globalfifo_dev { struct cdev cdev; unsigned int current_len; unsigned char mem[GLOBALFIFO_SIZE]; struct mutex mutex; wait_queue_head_t r_wait; wait_queue_head_t w_wait; struct device *dev; struct fasync_struct *async_queue; }; struct globalfifo_dev *globalfifo_devp; static int globalfifo_fasync(int fd, struct file *filp, int mode) { struct globalfifo_dev *dev = filp->private_data; return fasync_helper(fd, filp, mode, &dev->async_queue); } static int globalfifo_open(struct inode *inode, struct file *filp) { filp->private_data = globalfifo_devp; return 0; } static int globalfifo_release(struct inode *inode, struct file *filp) { globalfifo_fasync(-1, filp, 0); return 0; } static long globalfifo_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct globalfifo_dev *dev = filp->private_data; switch (cmd) { case FIFO_CLEAR: mutex_lock(&dev->mutex); dev->current_len = 0; memset(dev->mem, 0, GLOBALFIFO_SIZE); mutex_unlock(&dev->mutex); printk(KERN_INFO "globalfifo is set to zero\n"); break; default: return -EINVAL; } return 0; } static unsigned int globalfifo_poll(struct file *filp, poll_table * wait) { unsigned int mask = 0; struct globalfifo_dev *dev = filp->private_data; mutex_lock(&dev->mutex); poll_wait(filp, &dev->r_wait, wait); poll_wait(filp, &dev->w_wait, wait); if (dev->current_len != 0) { mask |= POLLIN | POLLRDNORM; } if (dev->current_len != GLOBALFIFO_SIZE) { mask |= POLLOUT | POLLWRNORM; } mutex_unlock(&dev->mutex); return mask; } static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { int ret; struct globalfifo_dev *dev = filp->private_data; DECLARE_WAITQUEUE(wait, current); mutex_lock(&dev->mutex); add_wait_queue(&dev->r_wait, &wait); while (dev->current_len == 0) { if (filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto out; } __set_current_state(TASK_INTERRUPTIBLE); mutex_unlock(&dev->mutex); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; goto out2; } mutex_lock(&dev->mutex); } if (count > dev->current_len) count = dev->current_len; if (copy_to_user(buf, dev->mem, count)) { ret = -EFAULT; goto out; } else { memcpy(dev->mem, dev->mem + count, dev->current_len - count); dev->current_len -= count; printk(KERN_INFO "read %d bytes(s),current_len:%d\n", count, dev->current_len); wake_up_interruptible(&dev->w_wait); ret = count; } out: mutex_unlock(&dev->mutex); out2: remove_wait_queue(&dev->w_wait, &wait); set_current_state(TASK_RUNNING); return ret; } static ssize_t globalfifo_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct globalfifo_dev *dev = filp->private_data; int ret; DECLARE_WAITQUEUE(wait, current); mutex_lock(&dev->mutex); add_wait_queue(&dev->w_wait, &wait); while (dev->current_len == GLOBALFIFO_SIZE) { if (filp->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto out; } __set_current_state(TASK_INTERRUPTIBLE); mutex_unlock(&dev->mutex); schedule(); if (signal_pending(current)) { ret = -ERESTARTSYS; goto out2; } mutex_lock(&dev->mutex); } if (count > GLOBALFIFO_SIZE - dev->current_len) count = GLOBALFIFO_SIZE - dev->current_len; if (copy_from_user(dev->mem + dev->current_len, buf, count)) { ret = -EFAULT; goto out; } else { dev->current_len += count; printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, dev->current_len); wake_up_interruptible(&dev->r_wait); if (dev->async_queue) { kill_fasync(&dev->async_queue, SIGIO, POLL_IN); printk(KERN_DEBUG "%s kill SIGIO\n", __func__); } ret = count; } out: mutex_unlock(&dev->mutex); out2: remove_wait_queue(&dev->w_wait, &wait); set_current_state(TASK_RUNNING); return ret; } ssize_t globalfifo_trigger_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int cnt = -1; struct globalfifo_dev *gdev = dev_get_drvdata(dev); mutex_lock(&gdev->mutex); // count = gdev->current_len; printk(KERN_INFO "%s - buf=%s, len=%d\n", __func__, buf, count); // cnt = copy_from_user(gdev->mem + gdev->current_len, buf, count); count = snprintf(gdev->mem + gdev->current_len, GLOBALFIFO_SIZE, "%s", buf); gdev->current_len += count; mutex_unlock(&gdev->mutex); return count; } ssize_t globalfifo_trigger_show(struct device *dev, struct device_attribute *attr, char *buf) { int count; struct globalfifo_dev *gdev = dev_get_drvdata(dev); mutex_lock(&gdev->mutex); count = gdev->current_len; if(count == 0 ) { count = sprintf(buf, "NO data put in. current_len=0\n"); } else { count = sprintf(buf, "current_len=%d, data=%s\n", count, gdev->mem); buf[count] = 0; } mutex_unlock(&gdev->mutex); return count; // return sprintf(buf, "globalfifo_trigger_show: count = %d, counter_addr=%p\n", *counter, counter); } static DEVICE_ATTR(trigger, 0644, globalfifo_trigger_show, globalfifo_trigger_store); static struct attribute *globalfifo_trigger_attrs[] = { &dev_attr_trigger.attr, NULL, }; static const struct attribute_group globalfifo_trigger_group = { .attrs = globalfifo_trigger_attrs, }; static const struct attribute_group *globalfifo_groups[] = { &globalfifo_trigger_group, }; static const struct file_operations globalfifo_fops = { .owner = THIS_MODULE, .read = globalfifo_read, .write = globalfifo_write, .unlocked_ioctl = globalfifo_ioctl, .poll = globalfifo_poll, .fasync = globalfifo_fasync, .open = globalfifo_open, .release = globalfifo_release, }; static int globalfifo_prove(struct platform_device *pdev) { // struct globalfifo_dev *gl; int ret; dev_t devno = MKDEV(GLOBALFIFO_MAJOR, 0); printk(KERN_INFO "0 %s - probe failed\n", __func__); if(GLOBALFIFO_MAJOR) { printk(KERN_INFO "00 %s - probe failed\n", __func__); ret = register_chrdev_region(devno, 1, "gblobalfifo"); printk(KERN_INFO "000 %s - probe failed\n", __func__); } else { printk(KERN_INFO "01 %s - probe failed\n", __func__); ret = alloc_chrdev_region(&devno, 0, 1, "gblobalfifo"); globalfifo_major = MAJOR(devno); } if(ret < 0) return ret; printk(KERN_INFO "1 %s - probe failed\n", __func__); globalfifo_devp = devm_kzalloc(&pdev->dev, sizeof(*globalfifo_devp), GFP_KERNEL); if(!globalfifo_devp) { ret = -ENOMEM; goto fail_malloc; } printk(KERN_INFO "2 %s - probe failed\n", __func__); cdev_init(&globalfifo_devp->cdev, &globalfifo_fops); globalfifo_devp->cdev.owner = THIS_MODULE; ret = cdev_add(&globalfifo_devp->cdev, devno, 1); if(ret < 0) { printk(KERN_INFO "Error %d adding globalfifo\n", ret); goto fail_malloc; } printk(KERN_INFO "5 %s - probe failed\n", __func__); mutex_init(&globalfifo_devp->mutex); init_waitqueue_head(&globalfifo_devp->r_wait); init_waitqueue_head(&globalfifo_devp->w_wait); globalfifo_devp->dev = device_create(globalfifo_class, &pdev->dev, MKDEV(GLOBALFIFO_MAJOR, 0), globalfifo_devp, "globalfifo"); dev_info(&pdev->dev, "globalfifo drv proded\n"); return 0; fail_malloc: printk(KERN_INFO "6 - probe failed\n"); unregister_chrdev_region(devno, 1); return ret; } static int globalfifo_remove(struct platform_device *pdev) { return 0; } static struct platform_driver globalfifo_driver = { .driver = { .name = "globalfifo", .owner = THIS_MODULE, }, .probe = globalfifo_prove, .remove = globalfifo_remove, }; static int __init globalfifo_init(void) { int ret; globalfifo_class = class_create(THIS_MODULE, "globalfifo"); if (IS_ERR(globalfifo_class)) return PTR_ERR(globalfifo_class); globalfifo_class->dev_groups = globalfifo_groups; ret = platform_driver_register(&globalfifo_driver); if (ret) printk(KERN_ERR "globalfifo: probe failed: %d\n", ret); return ret; } module_init(globalfifo_init); static void __exit globalfifo_exit(void) { if(globalfifo_devp) cdev_del(&globalfifo_devp->cdev); device_destroy(globalfifo_class, MKDEV(GLOBALFIFO_MAJOR, 0)); unregister_chrdev_region(MKDEV(GLOBALFIFO_MAJOR, 0), 1); class_destroy(globalfifo_class); platform_driver_unregister(&globalfifo_driver); printk(KERN_INFO "globalfifo: exit\n"); } module_exit(globalfifo_exit); MODULE_AUTHOR("Barry Song <baohua@kernel.org>"); MODULE_LICENSE("GPL v2");
globalfifo-dev.c
#include <linux/module.h> #include <linux/of_device.h> static struct platform_device *globalfifo_pdev; static int __init globalfifodev_init(void) { int ret; globalfifo_pdev = platform_device_alloc("globalfifo", -1); if(!globalfifo_pdev) return -ENOMEM; ret = platform_device_add(globalfifo_pdev); if(ret) { platform_device_put(globalfifo_pdev); return ret; } return 0; } module_init(globalfifodev_init); static void __exit globalfifodev_exit(void) { platform_device_unregister(globalfifo_pdev); } module_exit(globalfifodev_exit); MODULE_AUTHOR("Bao hua"); MODULE_LICENSE("GPL v2");
相关文章推荐
- Android中字符设备驱动和应用实例(一) 驱动部分
- Linux 字符设备驱动实例笔记
- Android中字符设备驱动和应用实例(二) 应用部分
- [Linux驱动]字符设备驱动学习笔记(二)———实例
- 基于mini6410的linux驱动学习总结(五 字符设备驱动程序实例分析(虚拟设备驱动))
- 字符设备驱动(四)-led实例
- 使用内核定时器的second字符设备驱动及测试代码
- Hasen的linux设备驱动开发学习之旅--简单字符驱动实例globalmem
- Linux字符设备驱动实例
- Linux字符设备驱动实例
- linux设备驱动开发学习之旅--简单字符驱动实例globalmem
- Linux_2.6字符设备驱动实例
- linux高级字符设备驱动以及实例(TQ2440)
- 字符设备驱动实例
- [Linux驱动]字符设备驱动学习笔记(二)———实例
- Android中字符设备驱动和应用实例(一)——驱动部分
- Linux 驱动学习笔记3 -- 字符设备驱动实例(driver+client)
- JS判断输入字符串长度实例代码(汉字算两个字符,字母数字算一个)
- Linux_2.6字符设备驱动实例
- Linux 2.6驱动开发--字符设备驱动实例