您的位置:首页 > 其它

信号量,等待队列,异步通知,驱动例子

2014-03-23 15:40 357 查看
#include <linux/init.h>

#include <linux/module.h>

#include <linux/cdev.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/errno.h>

#include <linux/mm.h>

#include <linux/sched.h>

#include <asm/uaccess.h>

#include <linux/slab.h>

#include <linux/semaphore.h>

#include <linux/poll.h>

#define GLOBALMEM_SIZE 0X1000

#define MEM_CLEAR 0X1

#define GLOBALMEM_MAJOR 250

static int globalfifo_major = GLOBALMEM_MAJOR;

struct globalfifo_dev {

struct cdev cdev;

unsigned int current_len;

unsigned char mem[GLOBALMEM_SIZE];

struct semaphore sem;

wait_queue_head_t r_wait;

wait_queue_head_t w_wait;

struct fasync_struct *async_queue;

};

struct globalfifo_dev *globalfifo_devp = NULL;

int globalfifo_open(struct inode *inode, struct file *filp)

{

filp->private_data = globalfifo_devp;

return 0;

}

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);

}

int globalfifo_release(struct inode *inode, struct file *filp)

{

globalfifo_fasync(-1, filp, 0);

return 0;

}

static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)

{

unsigned int mask = 0;

struct globalfifo_dev *dev = filp->private_data;

down(&dev->sem);

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 != GLOBALMEM_SIZE)

mask |= POLLOUT | POLLWRNORM;

up(&dev->sem);

return mask;

}

static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)

{

/* int ret;

int p = *ppos;

struct globalfifo_dev *dev = filp->private_data;

if(p > GLOBALMEM_SIZE)

return 0;

if(count > GLOBALMEM_SIZE - p)

count = GLOBALMEM_SIZE -p;

if(copy_to_user(buf, (void *)(dev->mem + p), count)){

ret = -EFAULT;

}else{

*ppos += count;

ret = count;

printk(KERN_INFO "read %u bytes form %u\n", count, p);

}

return ret;

*/

int ret = 0;

struct globalfifo_dev *dev = filp->private_data;

DECLARE_WAITQUEUE(wait, current);

down(&dev->sem);

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);

up(&dev->sem);

schedule();

if(signal_pending(current)){

ret = -ERESTARTSYS;

goto out2;

}

down(&dev->sem);

}

if(count > dev->current_len)

count = dev->current_len;

if(copy_to_user(buf, dev->mem, count)){

return -EFAULT;

goto out;

}else{

memcpy(dev->mem, dev->mem + count, dev->current_len - count);

dev->current_len -= count;

printk(KERN_INFO "read %u bytes form %u\n", count, dev->current_len);

}

wake_up_interruptible(&dev->w_wait);

ret = count;

out:

up(&dev->sem);

out2:

remove_wait_queue(&dev->r_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)

{

/* unsigned long p = *ppos;

int ret = 0;

struct globalfifo_dev *dev = filp->private_data;

if(p >= GLOBALMEM_SIZE)

return 0;

if(count > GLOBALMEM_SIZE - p)

count = GLOBALMEM_SIZE -p;

if(copy_from_user(dev->mem + p, buf, count))

ret = -EFAULT;

else{

*ppos += count;

ret = count;

}

return ret;

*/

int ret = 0;

struct globalfifo_dev *dev = filp->private_data;

DECLARE_WAITQUEUE(wait, current);

down(&dev->sem);

add_wait_queue(&dev->w_wait,&wait);

while(dev->current_len == GLOBALMEM_SIZE){

if(filp->f_flags & O_NONBLOCK){

ret = - EAGAIN;

goto out;

}

__set_current_state(TASK_INTERRUPTIBLE);

up(&dev->sem);

schedule();

if(signal_pending(current)){

ret = - ERESTARTSYS;

goto out2;

}

down(&dev->sem);

}

if(count > GLOBALMEM_SIZE - dev->current_len)

count = GLOBALMEM_SIZE -dev->current_len;

if(copy_from_user(dev->mem + dev->current_len, buf, count)){

return - EFAULT;

goto out;

}

else{

dev->current_len += count;

printk(KERN_INFO "writen %u bytes from %u\n", count, dev->current_len);

wake_up_interruptible(&dev->r_wait);

if(dev->async_queue)

kill_fasync(&dev->async_queue, SIGIO, POLL_IN);

ret = count;

}

out:

up(&dev->sem);

out2:

remove_wait_queue(&dev->w_wait, &wait);

set_current_state(TASK_RUNNING);

return ret;

}

static const struct file_operations globalfifo_fops = {

.owner = THIS_MODULE,

.read = globalfifo_read,

.write = globalfifo_write,

.open = globalfifo_open,

.release = globalfifo_release,

.poll = globalfifo_poll,

.fasync = globalfifo_fasync,

};

static void globalfifo_setup(struct globalfifo_dev *dev, int index)

{

int err, devno = MKDEV(globalfifo_major, index);

cdev_init(&dev->cdev, &globalfifo_fops);

dev->cdev.owner = THIS_MODULE;

err = cdev_add(&dev->cdev, devno, 1);

if(err)

printk(KERN_NOTICE "Error %d adding globalfifo %d", err, index);

}

int globalfifo_init(void)

{

int result;

dev_t devno = MKDEV(globalfifo_major, 0);

if(globalfifo_major)

result = register_chrdev_region(devno, 1, "globalfifo");

else{

result = alloc_chrdev_region(&devno, 0, 1, "globalfifo");

globalfifo_major = devno;

}

if(result < 0)

return result;

globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);

if(!globalfifo_devp){

result = -ENOMEM;

goto fail_malloc;

}

memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));

globalfifo_setup(globalfifo_devp, 0);

sema_init(&globalfifo_devp->sem, 1);

init_waitqueue_head(&globalfifo_devp->r_wait);

init_waitqueue_head(&globalfifo_devp->w_wait);

return 0;

fail_malloc:

unregister_chrdev_region(devno, 1);

return result;

}

void globalfifo_exit(void)

{

cdev_del(&globalfifo_devp->cdev);

kfree(globalfifo_devp);

unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);

}

module_init(globalfifo_init);

module_exit(globalfifo_exit);

MODULE_AUTHOR("EMPEROR IS TEST");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("I LOVE YOU");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: