/*
* 驱动学习 globalfifo.c
* 内核版本2.6.27之前的创建设备节点的函数是struct class_device class_device_create
* class_device_destory
*/
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/errno.h>
- #include <linux/mm.h>
- #include <linux/sched.h>
- #include <linux/moduleparam.h>
- #include <linux/init.h>
- #include <linux/cdev.h>
- #include <linux/wait.h>
- #include <linux/poll.h>
- #include <linux/device.h>
- #include <asm/io.h>
- #include <asm/system.h>
- #include <asm/uaccess.h>
- #define GLOBALMEM_SIZE 0x1000
- #define MEM_CLEAN 0x01
- #define GLOBALMEM_MAJOR 0
- struct globalfifo_dev
- {
- unsigned int leng;
- struct cdev cdev;
- struct semaphore sem;
- unsigned char mem[GLOBALMEM_SIZE];
- wait_queue_head_t r_wait;
- wait_queue_head_t w_wait;
- struct fasync_struct *async_queue;
- };
- static struct globalfifo_dev *globalfifo_devp;
- static struct class *global_class;
- static struct device *global_device;
- static int globalfifo_major = GLOBALMEM_MAJOR;
- MODULE_AUTHOR("RIVER");
- MODULE_LICENSE("Dual BSD/GPL");
- static ssize_t globalfifo_read(struct file *filp, char __user *buf,size_t size, loff_t *f_ops)
- {
- struct globalfifo_dev *dev = filp->private_data;
- int ret;
- DECLARE_WAITQUEUE(rwait, current);
- down(&dev->sem);
- add_wait_queue(&dev->r_wait, &rwait);
- if(dev->leng == 0)
- {
- if(filp->f_flags & O_NONBLOCK)
- {
- ret = -EAGAIN;
- goto out;
- }
- set_current_state(TASK_INTERRUPTIBLE);
- up(&dev->sem);
- schedule();
- if(signal_pending(current)) //awake by signal
- {
- ret = -ERESTARTSYS;
- goto out1;
- }
- down(&dev->sem);
- }
- if(size > dev->leng)
- size = dev->leng;
-
- if(copy_to_user(buf,(void *)dev->mem, size))
- {
- ret = -EFAULT;
- goto out;
- }
- else
- {
- memcpy(dev->mem, dev->mem + size, dev->leng - size);
- dev->leng -= size;
- printk(KERN_INFO "read %d bytes current leng=%d \n", size, dev->leng);
- wake_up_interruptible(&dev->w_wait);
- ret = size;
- }
- out:
- up(&dev->sem);
- out1:
- remove_wait_queue(&dev->r_wait, &rwait);
- set_current_state(TASK_RUNNING);
- return ret;
- }
- static ssize_t globalfifo_write(struct file *filp,const char __user *buf, size_t size, loff_t *f_ops)
- {
- struct globalfifo_dev *dev = filp->private_data;
- int ret;
- DECLARE_WAITQUEUE(wwait, current);
- down(&dev->sem);
- add_wait_queue(&dev->w_wait, &wwait);
- if(dev->leng == GLOBALMEM_SIZE)
- {
- if(filp->f_flags & O_NONBLOCK)
- {
- ret = -EAGAIN;
- goto out;
- }
-
- __set_current_state(TASK_INTERRUPTIBLE);
- up(&dev->sem); //avoid deadlock
- schedule();
- // interruptible_sleep_on(&dev->w_wait);
- if(signal_pending(current))
- {
- ret = -ERESTARTSYS;
- goto out1;
- }
- down(&dev->sem);
- }
- if(size > GLOBALMEM_SIZE - dev->leng)
- size = GLOBALMEM_SIZE- dev->leng;
- if(copy_from_user(dev->mem,buf,size))
- {
- ret = - EFAULT;
- goto out;
- }
- else
- {
- ret = size;
- dev->leng += size;
- printk(KERN_INFO "written %d bytes leng=%d\n", size, dev->leng);
- wake_up_interruptible(&dev->r_wait);
- if(dev->async_queue) //async read signal
- kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
- }
- out:
- up(&dev->sem);
- out1:
- remove_wait_queue(&dev->w_wait, &wwait);
- set_current_state(TASK_RUNNING);
- return ret;
- }
- 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_CLEAN:
- if(down_interruptible(&dev->sem))
- {
- return -ERESTARTSYS;
- }
-
- memset(dev->mem,0,GLOBALMEM_SIZE);
- printk(KERN_INFO "globalfifo is set to zero %d\n",MEM_CLEAN);
- up(&dev->sem);
-
- break;
- default:
- return - EINVAL;
- }
- return 0;
- }
- static unsigned int globalfifo_poll(struct file *filp, struct poll_table_struct *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->leng != 0)
- mask |= POLLIN | POLLRDNORM;
- if(dev->leng != GLOBALMEM_SIZE)
- mask |= POLLOUT | POLLWRBAND;
- up(&dev->sem);
- return mask;
- }
- 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)
- {
- struct globalfifo_dev *dev;
- dev = container_of(inode->i_cdev,struct globalfifo_dev,cdev);
- filp->private_data = dev;
- return 0;
- }
- static int globalfifo_release(struct inode *inode, struct file *filp)
- {
- globalfifo_fasync(-1, filp, 0);
- return 0;
- }
-
- static struct file_operations globalfifo_fops =
- {
- .owner = THIS_MODULE,
- .read = globalfifo_read,
- .write = globalfifo_write,
- .ioctl = globalfifo_ioctl,
- .poll = globalfifo_poll,
- .open = globalfifo_open,
- .release = globalfifo_release,
- .fasync = globalfifo_fasync,
- };
- static void globalfifo_setup_cdev(struct globalfifo_dev *dev,int index)
- {
- int err;
- dev_t 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 globalfifo %d",err,index);
- init_MUTEX(&dev->sem);
- init_waitqueue_head(&dev->r_wait);
- init_waitqueue_head(&dev->w_wait);
- }
- static int __init globalfifo_init(void)
- {
- int result;
- dev_t devno;
- if(globalfifo_major)
- {
- devno = MKDEV(globalfifo_major,0);
- result = register_chrdev_region(devno,1,"globalfifo");
- }
- else
- {
- result = alloc_chrdev_region(&devno,0,1,"globalfifo");
- globalfifo_major = 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_cdev(globalfifo_devp,0);
- global_class = class_create(THIS_MODULE, "globalfifo");
- if(IS_ERR(global_class))
- {
- result = -EFAULT;
- goto fail_malloc;
- }
- global_device = device_create(global_class, NULL, MKDEV(globalfifo_major,0), NULL, "globalfifo");
- return 0;
- fail_malloc:
- unregister_chrdev_region(devno,1);
- return result;
- }
- static void __exit globalfifo_exit(void)
- {
- cdev_del(&globalfifo_devp->cdev);
- kfree(globalfifo_devp);
- device_destroy(global_class, MKDEV(globalfifo_major, 0));
- class_destroy(global_class);
- unregister_chrdev_region(MKDEV(globalfifo_major,0),1);
- }
- module_param(globalfifo_major,int,S_IRUGO);
- module_init(globalfifo_init);
- module_exit(globalfifo_exit);
/* 驱动Makefile */
KERNELDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install:
insmod globalmem.ko
uninstall:
rmmod globalmem.ko
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
endif
/*
* 驱动验证 global.c
*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #define MAX 512
- int main(void)
- {
- int fd, fd1;
- char str[MAX] = {0}, buf[25] = {0};
- int i = 0;
- pid_t pid;
- struct timeval to;
- fd_set rfds;
-
- pid = fork();
- while(1)
- {
- if(pid < 0)
- {
- printf("ERR in fork\n");
- }
- else if(pid != 0)
- {
- fd1 = open("/dev/globalfifo",O_RDWR);
- if(fd1 < 0)
- {
- printf("the globalfifo can't be open\n");
- continue;
- }
-
- sleep(1);
- snprintf(buf, 10, "hello %d", i++);
- if( i > 3 )
- {
- i = 0;
- sleep(3);
- close(fd1);
- continue;
- }
- write(fd1, buf, strlen(buf));
- memset(buf, 0, 25);
- close(fd1);
- }
- else
- {
- fd = open("/dev/globalfifo", 0);
- if(fd < 0)
- {
- printf("the globalfifo can't open\n");
- continue;
- }
- FD_ZERO(&rfds);
- FD_SET(fd, &rfds);
- to.tv_sec = 3; //timeout 3s
- to.tv_usec = 0;
- select(fd+1, &rfds, NULL, NULL, &to);
- {
- if(FD_ISSET(fd, &rfds))
- {
- read(fd, str, 10);
- str[10] = 0;
- printf("%s\n", str);
- memset(str, 0, 10);
- }
- else
- {
- printf("time out\n");
- }
- }
- close(fd);
- }
- }
- return 0;
- }
运行
#gcc -o fifo global.c
#./fifo
hello0
hello1
hello2
timeout
....
/*
* 异步通知程序
*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <signal.h>
- #define MAX_LEN 30
- int fd = -1;
- void input_handle(int sig)
- {
- char buf[MAX_LEN] = {0};
- int len;
- printf("receive buf from globalfifo, signal = %d\n", sig);
- if(fd > 0)
- {
- len = read(fd, &buf, MAX_LEN);
- buf[len] = 0;
- printf("%s\n", buf);
- close(fd);
- fd = -1;
- }
- }
- int main(void)
- {
- int flag;
- fd = open("/dev/globalfifo", 0);
- if(fd > 0)
- {
- signal(SIGIO, input_handle);
- fcntl(fd, F_SETOWN, getpid());
- flag = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, flag | FASYNC);
- sleep(5);
- }
- else
- {
- perror("open /dev/globalfifo");
- }
- return 0;
- }
运行#./fifo, 再开一个终端#echo 'hello' > /dev/globalfifo
receive buf from globalfifo, signal = 29
hello
阅读(2343) | 评论(1) | 转发(1) |