linux设备驱动开发详解源码,Linux设备驱动开发详解》 源代码整理二  globalfifo.c...

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define GLOBALFIFO_SIZE 0x1000

#define MEM_CLEAR 0x1

#define GLOBALFIFO_MAJOR 234

static int globalfifo_major=GLOBALFIFO_MAJOR;

struct globalfifo_dev

{

struct cdev cdev;

unsigned int current_len;

unsigned char mem[GLOBALFIFO_SIZE];

struct semaphore sem;

wait_queue_head_t r_wait;

wait_queue_head_t w_wait;

};

struct globalfifo_dev *globalfifo_devp;//设备结构体指针

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); //定义等待队列

down(&dev->sem); //获得信号量

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

//进入读等待队列头

if(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))

{

ret=-EFAULT;

goto out;

}

else

{

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

- count);//fifo数据前移

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:up(&dev->sem);

//释放信号量

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); //定义等待队列头

down(&dev->sem); //获得信号量

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

//进入写等待队列头

if(dev->current_len==GLOBALFIFO_SIZE)

{

if(filp->f_pos

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

//唤醒读等待队列

ret=count;

}

out:up(&dev->sem);

//释放信号量

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

//从附属的等待队列头移除

set_current_state(TASK_RUNNING);

return ret;

}

int globalfifo_open(struct inode *inode,struct file

*filp)

{

filp->private_data =

globalfifo_devp;//将设备结构体指针赋值给文件私有数据指针

return 0;

}

int globalfifo_release(struct inode *inode,struct file

*filp)

{

return 0;

}

static int globalfifo_ioctl(struct inode *inode,struct file

*filp,unsigned int cmd,unsigned long arg)

{

struct globalfifo_dev

*dev=filp->private_data;

switch(cmd)

{

case MEM_CLEAR:

if(down_interruptible(&dev->sem))

//获得信号量

{

return - ERESTARTSYS;

}

memset(dev->mem,0,GLOBALFIFO_SIZE);

up(&dev->sem); //释放信号量

printk(KERN_INFO "globalfifo is set to zero\n");

break;

default:

return - EINVAL;

}

return 0;

}

static const struct file_operations globalfifo_fops =

{

.owner = THIS_MODULE,

.read = globalfifo_read,

.write = globalfifo_write,

.release = globalfifo_release,

.open = globalfifo_open,

.ioctl = globalfifo_ioctl,

};

static void globalfifo_setup_cdev(struct globalfifo_dev

*dev,int index)

{

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

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

dev->cdev.owner=THIS_MODULE;

dev->cdev.ops=&globalfifo_fops;

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

if(err)

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

}

int globalfifo_init(void)

{

int ret;

dev_t devno=MKDEV(globalfifo_major,0);

if(globalfifo_major)

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

else

{

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

globalfifo_major=MAJOR(devno);

}

if (ret<0)

return ret;

globalfifo_devp=kmalloc(sizeof(struct

globalfifo_dev),GFP_KERNEL);

if(!globalfifo_devp)

{

ret=-ENOMEM;

goto fail_malloc;

}

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

globalfifo_setup_cdev(globalfifo_devp,0);

init_MUTEX(&globalfifo_devp->sem);

init_waitqueue_head(&globalfifo_devp->r_wait);

init_waitqueue_head(&globalfifo_devp->w_wait);

return 0;

fail_malloc: unregister_chrdev_region(devno,1);

return ret;

}

void globalfifo_exit(void)

{

cdev_del(&globalfifo_devp->cdev);

kfree(globalfifo_devp);//释放结构体内存

unregister_chrdev_region(MKDEV(globalfifo_major,0),1);//释放设备号

}

MODULE_AUTHOR("Cynicholas");

MODULE_LICENSE("Dual BSD/GPL");

module_param(globalfifo_major,int,S_IRUGO);

module_init(globalfifo_init);

module_exit(globalfifo_exit);

//All rights reserved to Song Baohua.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值