两个字符驱动实例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");
原创粉丝点击