分类: LINUX
2010-08-31 16:01:17
//fifo.c
//先进先出队列
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVNAME "GLOBAL_FIFO_DEV"//驱动名称
#define SIZE 2000//缓冲区大小
int major;//主设备号
//设备结构体
struct FIFO_DEV
{
struct cdev cdev;//字符设备结构体
unsigned int current_len;//当前缓冲区中字节数
unsigned char mem[SIZE];//内存缓冲区
struct semaphore sem;//信号量
wait_queue_head_t r_wait;//读等待队列头
wait_queue_head_t w_wait;//写等待队列头
struct fasync_struct *async_queue;//异步结构体指针
};
struct FIFO_DEV *fifo_dev;
//异步通知函数
static int fifo_fasync(int fd,struct file *filp,int mode)
{
struct FIFO_DEV *fifo_dev=filp->private_da
return fasync_helper(fd,filp,mode,&fifo_dev->async_queue);
}
static int fifo_open(struct inode *inode,struct file *filp)
{
filp->private_da
return 0;
}
static int fifo_release(struct inode *inode,struct file *filp)
{
struct FIFO_DEV *fifo_dev=filp->private_da
fifo_fasync(-1, filp, 0);//将文件从异步操作中删除
return 0;
}
static ssize_t fifo_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos )
{
int ret=0;
struct FIFO_DEV *fifo_dev=filp->private_da
DECLARE_WAITQUEUE(wait,current);//定义等待队列
down(&fifo_dev->sem);//获取信息量
add_wait_queue(&fifo_dev->r_wait,&wait);//将等待队列加入写等待队列头
if(fifo_dev->current_len==0)
{
if(filp->f_flags &O_NONBLOCK)
{
ret=-EAGAIN;
goto out;
}
else
{
__set_current_state(TASK_INTERRUPTIBLE);//阻塞当前进程
up(&fifo_dev->sem);//释放信息量
schedule();//调度其它进程
if(signal_pending(current))
{
ret=-ERESTARTSYS;
goto out2;
}
down(&fifo_dev->sem);
}
}
if(count>fifo_dev->current_len)
{
count=fifo_dev->current_len;
}
if(copy_to_user(buf,fifo_dev->mem,count))//读取数据到用户缓冲区
{
ret= -EFAULT;
goto out;
}
else
{
memcpy(fifo_dev->mem,fifo_dev->mem+count,fifo_dev->current_len-count);//数据提前
fifo_dev->current_len-=count;
wake_up_interruptible(&fifo_dev->w_wait);//唤醒写等待队列
ret=count;
}
out:up(&fifo_dev->sem);
out2:remove_wait_queue(&fifo_dev->r_wait,&wait);
set_current_state(TASK_RUNNING);
return ret;
}
static ssize_t fifo_write(struct file *filp,char __user *buf,size_t count,loff_t *ppos )
{
int ret;
struct FIFO_DEV *fifo_dev=filp->private_da
DECLARE_WAITQUEUE(wait,current);
down(&fifo_dev->sem);
add_wait_queue(&fifo_dev->w_wait,&wait);
if(fifo_dev->current_len==SIZE)
{
if(filp->f_flags &O_NONBLOCK)
{
ret=-EAGAIN;
goto out;
}
else
{
__set_current_state(TASK_INTERRUPTIBLE);
up(&fifo_dev->sem);
schedule();
if(signal_pending(current))
{
ret=-ERESTARTSYS;
goto out2;
}
down(&fifo_dev->sem);
}
}
if(count>SIZE-fifo_dev->current_len)
{
count=SIZE-fifo_dev->current_len;
}
if(copy_from_user(fifo_dev->mem+fifo_dev->current_len,buf,count))
{
ret= -EFAULT;
goto out;
}
else
{
fifo_dev->current_len+=count;
wake_up_interruptible(&fifo_dev->r_wait);
//释放异步读通知道信号
if(fifo_dev->async_queue)
{
kill_fasync(&fifo_dev->async_queue,SIGIO,POLL_IN);
}
ret=count;
}
out:up(&fifo_dev->sem);
out2:remove_wait_queue(&fifo_dev->w_wait,&wait);
set_current_state(TASK_RUNNING);
return ret;
}
static unsigned int fifo_poll(struct file * filp,struct poll_table *wait)
{
int mask=0;
struct FIFO_DEV *fifo_dev=filp->private_da
down(&fifo_dev->sem);
poll_wait(filp,&fifo_dev->r_wait,wait);
poll_wait(filp,&fifo_dev->w_wait,wait);
if(fifo_dev->current_len!=0)
{
mask|=POLLIN | POLLRDNORM;
}
if(fifo_dev->current_len!=SIZE)
{
mask|=POLLOUT|POLLRDNORM;
}
up(&fifo_dev->sem);
return mask;
}
static const struct file_operations fifo_ops=
{
.owner=THIS_MODULE,
.open=fifo_open,
.release=fifo_release,
.read=fifo_read,
.write=fifo_write,
.poll=fifo_poll,
.fasync=fifo_fasync,
};
int __init fifo_init(void)
{
int ret;
dev_t devno=MKDEV(major,0);
if(major)
{
ret=register_chrdev_region(devno,1,DEVNAME);
}
else
{
ret=alloc_chrdev_region(&devno,0,1,DEVNAME);
major=MAJOR(devno);
}
if(ret<0)
{
return ret;
}
fifo_dev=kmalloc(sizeof(struct FIFO_DEV),GFP_KERNEL);
if(!fifo_dev)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(fifo_dev,0,sizeof(struct FIFO_DEV));
cdev_init(&fifo_dev->cdev,&fifo_ops);
fifo_dev->cdev.ops=&fifo_ops;
cdev_add(&fifo_dev->cdev,devno,1);
fifo_dev->cdev.owner=THIS_MODULE;
init_MUTEX(&fifo_dev->sem);
init_waitqueue_head(&fifo_dev->r_wait);
init_waitqueue_head(&fifo_dev->w_wait);
fifo_dev->current_len=0;
return 0;
fail_malloc:unregister_chrdev_region(devno,1);
return ret;
}
int __exit fifo_exit(void)
{
cdev_del(&fifo_dev->cdev);
kfree(fifo_dev);
unregister_chrdev_region(MKDEV(major,0),1);
return 0;
}
module_init(fifo_init);
module_exit(fifo_exit);
secondtimer.c:定时器驱动
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVNAME "SECONDTIMER_DEV"
#define SECONDTIMER_MAJOR 255
int secondtimer_major=SECONDTIMER_MAJOR;
struct SECONDTIMER_DEV
{
struct cdev cdev;
struct timer_list timerlist;
atomic_t totleCount;
};
struct SECONDTIMER_DEV *secondtimer_dev;
static void secondtimer_handler(unsigned args)
{
mod_timer(&secondtimer_dev->timerlist,jiffies+HZ);
atomic_inc(&secondtimer_dev->totleCount);
printk("kernel current fiffies equ %ld\n",jiffies);
}
static int secondtimer_open(struct inode *inode,struct file *filp)
{
filp->private_da
init_timer(&secondtimer_dev->timerlist);
secondtimer_dev->timerlist.function=&secondtimer_handler;
secondtimer_dev->timerlist.expires=jiffies+HZ;
add_timer(&secondtimer_dev->timerlist);
atomic_set(&secondtimer_dev->totleCount,0);
return 0;
}
static int secondtimer_release(struct inode *inode,struct file *filp)
{
del_timer(&secondtimer_dev->timerlist);
return 0;
}
static ssize_t secondtimer_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
int counts=0;
struct SECONDTIMER_DEV *secondtimer_dev=filp->private_da
counts=atomic_read(&secondtimer_dev->totleCount);
if(put_user(counts,(int *)buf))
{
return -EFAULT;
}
else
{
return sizeof(unsigned int);
}
}
static const struct file_operations secondtimer_ops=
{
.owner=THIS_MODULE,
.open=secondtimer_open,
.release=secondtimer_release,
.read=secondtimer_read,
};
int __init secondtimer_init(void)
{
int ret;
dev_t devno=MKDEV(secondtimer_major,0);
if(secondtimer_major)
{
ret=register_chrdev_region(devno,1,DEVNAME);
}
else
{
ret=alloc_chrdev_region(&devno,0,1,DEVNAME);
secondtimer_major=MAJOR(devno);
}
if(ret<0)
{
return ret;
}
secondtimer_dev=kmalloc(sizeof(struct SECONDTIMER_DEV),GFP_KERNEL);
if(!secondtimer_dev)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(secondtimer_dev,0,sizeof(struct SECONDTIMER_DEV));
cdev_init(&secondtimer_dev->cdev,&secondtimer_ops);
secondtimer_dev->cdev.ops=&secondtimer_ops;
cdev_add(&secondtimer_dev->cdev,devno,1);
secondtimer_dev->cdev.owner=THIS_MODULE;
return 0;
fail_malloc:unregister_chrdev_region(devno,1);
return ret;
}
int __exit secondtimer_exit(void)
{
cdev_del(&secondtimer_dev->cdev);
kfree(secondtimer_dev);
unregister_chrdev_region(MKDEV(secondtimer_major,0),1);
return 0;
}
module_init(secondtimer_init);
module_exit(secondtimer_exit);
makefile内容如下:
obj-m:= fifo.o
obj-m:= secondtimer.o
KERNELDIR:=/lib/modules/$(shell uname -r)/build
default:
make -C $(KERNELDIR) M=$(shell pwd) modules
install:
insmod fifo.ko
mknod /dev/fifo c 248 0
chmod 777 /dev/fifo
insmod secondtimer.ko
mknod /dev/secondtimer c 255 0
chmod 777 /dev/secondtimer
uninstall:
rmmod fifo.ko
rm -f /dev/fifo
rmmod secondtimer.ko
rm -f /dev/secondtimer
clean:
make -C $(KERNELDIR) M=$(shell pwd) clean
2.测试代码
pollTest.c:轮询操作测试
#include
#include
#include
#include
#include
#define FIFO_CLEAR 0x1
#define FIFO_LEN 20
main()
{
int fd,num;
char mem_char[FIFO_LEN];
fd_set rfds,wfds;
*mem_char="abc";
fd=open("/dev/fifo",O_RDWR|O_NONBLOCK);
if(fd!=-1)
{
while(1)
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(fd,&rfds);
FD_SET(fd,&wfds);
select(fd+1,&rfds,&wfds,NULL,NULL);
if(FD_ISSET(fd,&wfds))
{
num=write(fd,"123",FIFO_LEN);
printf("Poll write!\n");
}
if(FD_ISSET(fd,&rfds))
{
num=read(fd,mem_char,FIFO_LEN);
printf("Poll read!\n");
puts(mem_char);
printf("%s\n",mem_char);
}
sleep(2);
}
}
else
{
printf("File open failure!\n");
}
}
//fasynctest.c,异步信号通知测试
#include
#include
#include
#include
#include
#include
#include
#include
void input_handler(int signum)
{
printf("receive a signal from fifo,signum %d\n",signum);
sleep(3);
}
main()
{
int fd,oflags;
fd=open("/dev/fifo",O_RDWR,S_IRUSR|S_IWUSR);
if(fd!=-1)
{
signal(SIGIO,input_handler);
fcntl(fd,F_SETOWN,getpid());
oflags=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,oflags|FASYNC);
while(1)
{
sleep(2);
}
}
else
{
printf("File open failure!\n");
}
}
secondtimerTest.c:定时器驱动测试
#include
#include
#include
#include
#include
#include
#include
#include
main()
{
int fd,counter=0,old_counter=0;
fd=open("/dev/secondtimer",O_RDONLY);
if(fd!=-1)
{
while(1)
{
read(fd,&counter,sizeof(int));
if(counter!=old_counter)
{
printf("current counter is %d\n",counter);
old_counter=counter;
}
sleep(2);
}
}
else
{
printf("File open failure!\n");
}
}
chinaunix网友2010-09-02 08:18:39
Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com