两个字符驱动实例second 及 globalfifo

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_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");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值