您的位置:首页 > 其它

两个字符驱动实例second 及 globalfifo

2017-08-15 10:54 218 查看
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");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: