下面是目录的文件视图:
├── driver
│ └── globalfifo
│ ├── globalfifo.c
│ ├── Makefile
│ └── Makefile-old
├── Makefile
├── readme
└── test
├── main.c
└── Makefile
下面是驱动目录下的驱动文件和makefile文件:
#include <linux/module.h>//support module load and unload #include <linux/types.h>//special type definition,like dev_t off_t defined by typedef #include <linux/fs.h>//struct file_operations #include <linux/errno.h>//return value #include <linux/mm.h>//memory mannage ,include kmalloc.kfree and so on #include <linux/sched.h>//process schedule #include <linux/init.h>// #include <linux/cdev.h>//char device structure definition #include <linux/io.h>//io operation function ,like ioremap,iowrite #include <linux/poll.h> #define KERNEL_OLD 1 MODULE_AUTHOR("wk") ; MODULE_LICENSE("Dual BSD/GPL") ; #define GLOBALFIFO_SIZE 0x1000 //1M #define CLEAR_ALL 0x01 //clear fifo #define GLOBALFIFO_MAJOR 243//major device No static int globalfifo_major = GLOBALFIFO_MAJOR ; /*define globalfifo structure*/ struct globalfifo_dev { struct cdev dev ; 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 = NULL; 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 ; } #if KERNEL_OLD static int globalfifo_ioctl(struct inode *inode, struct file *filp, int cmd, unsigned long arg) { struct globalfifo_dev *dev = filp->private_data ; switch (cmd) { case CLEAR_ALL: /*note:down_intterruptible is more suitable,why?*/ down_interruptible(&dev->sem) ; dev->current_len = 0 ; memset(dev->mem,0,GLOBALFIFO_SIZE) ; up(&dev->sem) ; printk(KERN_INFO "clear globalfifo successfully!\n") ; break ; default: printk(KERN_INFO "invalid command!\n") ; return -EINVAL ; } } #else #endif static unsigned int globalfifo_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0 ; struct globalfifo_dev *dev = filp->private_data ; down_interruptible(&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< GLOBALFIFO_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 ; struct globalfifo_dev *dev = filp->private_data ; DECLARE_WAITQUEUE(wait,current) ; down_interruptible(&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_interruptible(&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) ; 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 = -1 ; DECLARE_WAITQUEUE(wait,current) ; down_interruptible(&dev->sem) ; add_wait_queue(&dev->w_wait,&wait) ; if(dev->current_len == GLOBALFIFO_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_interruptible(&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),cuurent_len:%d", 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 ; } static const struct file_operations globalfifo_fops = { .owner = THIS_MODULE , .open = globalfifo_open , .read = globalfifo_read , .write = globalfifo_write , .ioctl = globalfifo_ioctl , .poll = globalfifo_poll , .release = globalfifo_release , } ; int __init 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){ printk(KERN_INFO "apply for device No failed! major:%d,minor:%d\n",MAJOR(devno),MINOR(devno)) ; 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)) ; cdev_init(&globalfifo_devp->dev, &globalfifo_fops) ; globalfifo_devp->dev.owner = THIS_MODULE ; globalfifo_devp->dev.ops = &globalfifo_fops ; if(cdev_add(&globalfifo_devp->dev, devno,1)) { printk(KERN_NOTICE "add cdev failed!\n") ; } init_MUTEX(&globalfifo_devp->sem) ; init_waitqueue_head(&globalfifo_devp->r_wait) ; init_waitqueue_head(&globalfifo_devp->w_wait) ; printk(KERN_INFO "init globalfifo device successfully!\n" ) ; return 0 ; fail_malloc: unregister_chrdev_region(devno,1) ; return ret ; } void __exit globalfifo_exit(void) { if(globalfifo_devp != NULL ){ cdev_del(&globalfifo_devp->dev) ; kfree(globalfifo_devp) ; unregister_chrdev_region(MKDEV(globalfifo_major,0),1) ; } printk(KERN_INFO "unload globalfifo device successfully!\n") ; } //module_param(globalfifo_major, int , S_IRUGO) ; module_init(globalfifo_init) ; module_exit(globalfifo_exit) ;
Makefile文件:
ifneq ($(KERNELRELEASE),) obj-m := globalfifo.o else KDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) -C $(KDIR) M=$(PWD) modules endif clean: rm -rf *.o *~ .depend *.ko *.order *.symvers *.mod.c 下面是测试文件
#include <stdio.h> #include <sys/select.h> #include <fcntl.h> #define BUF_SIZE 16 int main() { printf("hello world!\n") ; int fd ; char buf[BUF_SIZE] ; int count =-1 ; fd_set rfds,wfds ; if((fd=open("/dev/globalfifo",O_RDONLY | O_NONBLOCK))<0){ printf("%s:open globalfifo failed!\n",__func__) ; return -1 ; } while(1){ FD_ZERO(&rfds) ; FD_ZERO(&wfds) ; FD_SET(fd,&rfds) ; //FD_SET(fd,&wfds) ; select(fd+1,&rfds,&wfds,NULL,NULL) ; //select(fd,&rfds,NULL,NULL,NULL) ; if(FD_ISSET(fd,&rfds)){ printf("%s:globalfifo have data to read!\n",__func__) ; printf("read.......\n") ; if((count=read(fd,buf,BUF_SIZE))>0){ printf("read:%s:\n",buf) ; } } /* if(FD_ISSET(fd,&wfds)){ printf("%s:globalfifo have space to write!\n",__func__) ; } */ } return 0 ; }
Makefile文件如下:
OBJS=main.o CC=gcc CFLAGS=-Wall -g -O main:$(OBJS) $(CC) $(OBJS) -o main $(OBJS):%o:%c $(CC) -c $(CFLAGS) $< -o $@ clean: rm -fr *.o *.symvers *.mod.c main
最上层目录的Makefile文件:
SUBDIRS := driver/globalfifo test .PHONY :all all: @for dir in $(SUBDIRS) ;\ do make -C $${dir} ;\ done .PHONY:clean clean: @for dir in $(SUBDIRS);\ do make clean -C $${dir};\ done .PHONY:execute execute: ./test/main