—-头文件—-
#define GLOBALFIFO_SIZE 0x1000 /全局fifo最大4K字节/
/ CDEV字符设备相关***/
int CDRIVER_MAJOR=0;
int CDRIVER_MINOR=0;
int count=1;
#define CDRIVER_NAME “simple_chrdev”
struct cdev *simple_cdev; //字符设备结构体
dev_t simple_dev; //设备
static struct device *dev;
static struct class *simple_class;
struct mhrfifo_dev
{
unsigned int current_len; /fifo有效数据长度/
unsigned char mem[GLOBALFIFO_SIZE]; /全局内存/
struct mutex mutex; /并发控制用的互斥体/
wait_queue_head_t r_wait; /阻塞读用的等待队列头/
wait_queue_head_t w_wait; /阻塞写用的等待队列头/
};
struct mhrfifo_dev *mhrfifo_devp;
static ssize_t mac_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
struct mhrfifo_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){
mutex_unlock(&dev->mutex);
return -EAGAIN;
}
//阻塞访问
//进行进程状态切换,设置当前进程状态为 浅睡眠,并没有真正睡眠
__set_current_state(TASK_INTERRUPTIBLE);
//当前进程切换出去之前释放互斥体 让给写进程
mutex_unlock(&dev->mutex);
schedule(); //调度当前读进程出去 此时读进程进入睡眠状态
if(signal_pending(current))
{
remove_wait_queue(&dev->r_wait, &wait);//从附属的等待队列移除
set_current_state(TASK_RUNNING);
return - ERESTARTSYS;
}
//获取互斥体
mutex_lock(&dev->mutex);
}
//从用户空间拷贝到内核空间
if(count > GLOBALFIFO_SIZE - dev->current_len)
count = dev->current_len;
if(copy_to_user(buffer, dev->mem, count))
{
//读操作失败
mutex_unlock(&dev->mutex);
return - EFAULT;
}
else{
//读操作成功后 进行fifo数据空间移位
memcpy(dev->mem, dev->mem+count, dev->current_len - count); //fifo数据前移
dev->current_len -= count;//有效数据长度减少
printk(KERN_INFO "read %ld bytes(s),current_len:%d\n", count, dev->current_len);
wake_up_interruptible(&dev->w_wait);//唤醒可能阻塞的写进程
}
return 0;
}
static ssize_t mac_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct mhrfifo_dev *dev = filp->private_data;
DECLARE_WAITQUEUE(wait,current);
mutex_lock(&dev->mutex);
add_wait_queue(&dev->w_wait, &wait);
if(dev->current_len == GLOBALFIFO_SIZE){
if(filp->f_flags & O_NONBLOCK)
{
mutex_unlock(&dev->mutex);
return EAGAIN;
}
__set_current_state(TASK_INTERRUPTIBLE);
mutex_unlock(&dev->mutex);
schedule();
if(signal_pending(current))
{
remove_wait_queue(&dev->w_wait,&wait);
set_current_state(TASK_RUNNING);
return - ERESTARTSYS;
}
mutex_lock(&dev->mutex);
}
if(count > GLOBALFIFO_SIZE - dev->current_len)
count = dev->current_len;
if(copy_from_user(dev->mem + dev->current_len, buf, count)){
mutex_lock(&dev->mutex);
return EFAULT;
}
else{
dev->current_len += count;
wake_up_interruptible(&dev->r_wait);
}
return 0;
}
int mac_open(struct inode *inode,struct file *filp)
{
filp->private_data = mhrfifo_devp;
return 0;
}
struct file_operations simple_fops=
{
.owner=THIS_MODULE,
.open=mac_open,
.read=mac_read,
.write = mac_write,
};
/* 本代码自动生成了/dev/simple */
static int init_mycdev(void)
{
int ret;
printk( KERN_DEBUG “Module skeleton init\n” );
/register major and minor/
if(CDRIVER_MAJOR!=0)
{
simple_dev=MKDEV(CDRIVER_MAJOR,CDRIVER_MINOR);
ret=register_chrdev_region(simple_dev,count,CDRIVER_NAME);
}
else
{
/dynamic assign major/
ret=alloc_chrdev_region(&simple_dev,CDRIVER_MINOR,count,CDRIVER_NAME);
CDRIVER_MAJOR=MAJOR(simple_dev);
}
if(ret<0)
{
printk(KERN_ERR”cannot get major %d \n”,CDRIVER_MAJOR);
return -1;
}
/分配一个字符设备结构体/
simple_cdev=cdev_alloc();
if(simple_cdev!=NULL)
{
cdev_init(simple_cdev,&simple_fops);
simple_cdev->ops=&simple_fops;
simple_cdev->owner=THIS_MODULE;
//向系统 添加字符设备
if(cdev_add(simple_cdev,simple_dev,count)!=0)
{
printk(KERN_NOTICE "something wrong when adding simple_cdev!\n");
}
else
{
printk("success adding simple_cdev!\n");
}
}
else
{
printk(KERN_ERR "register simple_dev error!\n");
return -1;
}
simple_class = class_create(THIS_MODULE, "zusaiceshi");
if (IS_ERR(simple_class))
{
printk( KERN_DEBUG "class_create error\n" );
return -1;
}
printk(KERN_ERR "devno is %d \n",simple_dev);
dev=device_create(simple_class, NULL, simple_dev,NULL,"zusaiceshi");
mhrfifo_devp = kzalloc(sizeof(struct mhrfifo_dev), GFP_KERNEL);
mutex_init(&mhrfifo_devp->mutex);
init_waitqueue_head(&mhrfifo_devp->r_wait);
init_waitqueue_head(&mhrfifo_devp->w_wait);
return 0;
}
static void exit_mycdev(void)
{
printk( KERN_DEBUG “Module skeleton exit\n” );
device_destroy(simple_class, simple_dev);
class_destroy(simple_class);
cdev_del(simple_cdev);
unregister_chrdev_region(simple_dev,count);
}
module_init(init_mycdev);
module_exit(exit_mycdev);
MODULE_DESCRIPTION(“a test of char device driver”);
MODULE_AUTHOR(“Jerry”);
MODULE_LICENSE(“GPL”);
用户程序:
int main()
{
int *buffer;
int i;
int fd;
fd = open(“/dev/zusaiceshi”,O_RDWR);
if(fd == -1){
printf(“open device error”);
return 0;
}
buffer = malloc(10*sizeof(int));
for(i = 0;i < 10;i ++){
*(buffer+i) = i;
}
write(fd, buffer,i*sizeof(int));
return 0;
}
int main()
{
unsigned int buffer[100];
int i;
int fd;
fd = open(“/dev/zusaiceshi”,O_RDWR);
if(fd == -1){
printf(“open device error”);
return 0;
}
read(fd,buffer,5);
for(i = 0;i < 5; i ++){
//printf(“buffer[%d] = %d\n”, i, buffer[i]);
printf(“%d\n”,buffer[i]);
}
return 0;
}