两个字符驱动实例second 及 globalfifo
来源:互联网 发布:影楼相册制作软件 编辑:程序博客网 时间:2024/06/03 19:44
second_dri.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_MUTEXstatic 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 modulesobj-m += second.oobj-m += second_test.o#obj-m += second_mutex.oobj-m += second_dri.oobj-m += second_dev.obuild: kernel_moduleskernel_modules: make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modulesuser_test: gcc test.c -o testclean: 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 235static 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");
阅读全文
0 0
- 两个字符驱动实例second 及 globalfifo
- globalfifo驱动实例(poll机制)
- globalfifo驱动实例(等待队列)
- globalfifo 驱动实例(工作队列)
- globalfifo驱动实例(tasklet中断底半部机制)
- globalfifo(管道)驱动
- 支持异步通知的globalfifo驱动
- 字符设备驱动实例
- 试验宋宝华驱动第十章中的second秒字符设备
- 使用内核定时器的second字符设备驱动
- Linux字符设备驱动实例
- Linux字符设备驱动实例
- linux字符设备驱动实例
- Linux 字符设备驱动实例
- 设备驱动实例--字符设备驱动
- 8--2支持阻塞操作的globalfifo设备驱动
- 8--4支持轮询操作的globalfifo驱动
- 9--2支持异步通知的globalfifo驱动
- es6学习记录 set/ iterators
- Java高级特性之枚举学习总结
- 基于maven发送邮件系列(3)---maven自带的quartz实现定时发送邮件
- UVA 116 Unidirectional TSP
- 分治 C题
- 两个字符驱动实例second 及 globalfifo
- Convert Oracle Restart to Cluster
- 关闭端口脚本.bat
- 解决cxf2.2.3客户端动态调用与jdk1.7不兼容问题
- Android Studio建立jni开发环境
- 基于ajaxupload的多文件上传
- CentOS配置SDK环境变量
- 判断一个文件夹是远程还是本地
- 问题汇总