Linux字符设备驱动.docx
《Linux字符设备驱动.docx》由会员分享,可在线阅读,更多相关《Linux字符设备驱动.docx(6页珍藏版)》请在冰豆网上搜索。
![Linux字符设备驱动.docx](https://file1.bdocx.com/fileroot1/2023-3/30/622a8779-4df4-41fa-a3fb-c77f7cd67f04/622a8779-4df4-41fa-a3fb-c77f7cd67f041.gif)
Linux字符设备驱动
实验二:
Linux字符设备驱动
一.字符设备驱动实现的方法包括Write,Read,Poll,Icotl,Mmap,Llseek等。
二.字符设备驱动的主要内容:
并发控制,阻塞与非阻塞,异步通知。
三.字符设备驱动的主要文件:
globalfifo.cMakefileglobalfifo_test,globalfifo.c。
四.驱动程序如下:
#include
#include#include#include
#include
#include
#include
#include
#include#include#include
#include#include/*device_create()*/
#defineGLOBALFIFO_SIZE24/*全局fifo最大4K字节*/
#defineFIFO_CLEAR0x1/*清0全局内存的长度*/
#defineGLOBALFIFO_MAJOR249/*预设的globalfifo的主设备号*/staticintglobalfifo_major=GLOBALFIFO_MAJOR;/*globalfifo设备结构体*/structglobalfifo_dev{structcdevcdev;/*cdev结构体*/unsignedintcurrent_len;/*fifo有效数据长度*/unsignedcharmem[GLOBALFIFO_SIZE];/*全局内存*/structsemaphoresem;/*并发控制用的信号量*/wait_queue_head_tr_wait;/*阻塞读用的等待队列头*/wait_queue_head_tw_wait;/*阻塞写用的等待队列头*/};structglobalfifo_dev*globalfifo_devp;/*设备结构体指针*//*文件打开函数*/intglobalfifo_open(structinode*inode,structfile*filp){/*将设备结构体指针赋值给文件私有数据指针*/filp->private_data=globalfifo_devp;return0;}/*文件释放函数*/
intglobalfifo_release(structinode*inode,structfile*filp){return0;}/*ioctl设备控制函数*/staticintglobalfifo_ioctl(structinode*inodep,structfile*filp,unsignedintcmd,unsignedlongarg){structglobalfifo_dev*dev=filp->private_data;/*获得设备结构体指针*/
switch(cmd){caseFIFO_CLEAR:
down(&dev->sem);/*获得信号量*/dev->current_len=0;memset(dev->mem,0,GLOBALFIFO_SIZE);
up(&dev->sem);/*释放信号量*/
printk(KERN_INFO"globalfifoissettozero\n");
break;default:
return-EINVAL;}return0;}staticunsignedintglobalfifo_poll(structfile*filp,poll_table*wait){
unsignedintmask=0;
structglobalfifo_dev*dev=filp->private_data;/*获得设备结构体指针*/down(&dev->sem);poll_wait(filp,&dev->r_wait,wait);/*把读等待队列添加到poll_table*/poll_wait(filp,&dev->w_wait,wait);/*把写等待队列添加到poll_table*//*fifo非空表示可读*/if(dev->current_len!
=0){mask|=POLLIN|POLLRDNORM;/*标示数据可获得*/}/*fifo非满表示可写*/if(dev->current_len!
=GLOBALFIFO_SIZE){mask|=POLLOUT|POLLWRNORM;/*标示数据可写入*/}
up(&dev->sem);returnmask;}/*globalfifo读函数*/staticssize_tglobalfifo_read(structfile*filp,char__user*buf,size_tcount,loff_t*ppos){intret;
structglobalfifo_dev*dev=filp->private_data;DECLARE_WAITQUEUE(wait,current);down(&dev->sem);/*获得信号量*/add_wait_queue(&dev->r_wait,&wait);/*进入读等待队列头*//*等待FIFO非空*/if(dev->current_len==0){if(filp->f_flags&O_NONBLOCK){
ret=-EAGAIN;
gotoout;}__set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*/
up(&dev->sem);schedule();/*调度其他进程执行*/if(signal_pending(current)){/*如果是因为信号唤醒*/ret=-ERESTARTSYS;gotoout2;}down(&dev->sem);}/*拷贝到用户空间*/if(count>dev->current_len)
count=dev->current_len;
if(copy_to_user(buf,dev->mem,count)){
ret=-EFAULT;
gotoout;
}else{memcpy(dev->mem,dev->mem+count,dev->current_len-count);/*fifo数据前移*/dev->current_len-=count;/*有效数据长度减少*/printk(KERN_INFO"read%dbytes(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);returnret;}/*globalfifo写操作*/staticssize_tglobalfifo_write(structfile*filp,constchar__user*buf,size_tcount,loff_t*ppos){structglobalfifo_dev*dev=filp->private_data;
intret;DECLARE_WAITQUEUE(wait,current);
down(&dev->sem);add_wait_queue(&dev->w_wait,&wait);/*等待FIFO非满*/if(dev->current_len==GLOBALFIFO_SIZE){
if(filp->f_flags&O_NONBLOCK){ret=-EAGAIN;
gotoout;
}
__set_current_state(TASK_INTERRUPTIBLE);/*改变进程状态为睡眠*/up(&dev->sem);schedule();/*调度其他进程执行*/if(signal_pending(current)){/*如果是因为信号唤醒*/ret=-ERESTARTSYS;gotoout2;}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;gotoout;}else{dev->current_len+=count;printk(KERN_INFO"written%dbytes(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);returnret;}staticintmemdev_mmap(structfile*filp,structvm_area_struct*vma){structmem_dev*dev=filp->private_data;/*获得设备结构体指针*/vma->vm_flags|=VM_IO;vma->vm_flags|=VM_RESERVED
if(remap_pfn_range(vma,vma->vm_start,virt_to_phys(dev->data)>>PAGE_SHIFT,vma->vm_end-vma->vm_start,vma->vm_page_prot))
return-EAGAIN;
return0;
}
/*文件操作结构体*/
staticconststructfile_operationsglobalfifo_fops={
.owner=THIS_MODULE,
.read=globalfifo_read,
.write=globalfifo_write,
.ioctl=globalfifo_ioctl,
.poll=globalfifo_poll,
.open=globalfifo_open,
.release=globalfifo_release,
.mmap=memdev_mmap,
};
/*初始化并注册cdev*/
staticvoidglobalfifo_setup_cdev(structglobalfifo_dev*dev,intindex){interr,devno=MKDEV(globalfifo_major,index);
cdev_init(&dev->cdev,&globalfifo_fops);
dev->cdev.owner=THIS_MODULE;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE"Error%daddingLED%d",err,index);
}
/*设备驱动模块加载函数*/
intglobalfifo_init(void)
{
structclass*myclass;
intret;
dev_tdevno=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)
returnret;
/*动态申请设备结构体的内存*/
globalfifo_devp=kmalloc(sizeof(structglobalfifo_dev),GFP_KERNEL);
if(!
globalfifo_devp){
ret=-ENOMEM;
gotofail_malloc;
}memset(globalfifo_devp,0,sizeof(structglobalfifo_dev));
globalfifo_setup_cdev(globalfifo_devp,0);
/*自动创建设备文件*/
myclass=class_create(THIS_MODULE,"test_char");/*在sys下创建类目录/sys/class/test_char*/
device_create(myclass,NULL,MKDEV(globalfifo_major,0),NULL,"memdev0");
init_MUTEX(&globalfifo_devp->sem);/*初始化信号量*/init_waitqueue_head(&globalfifo_devp->r_wait);/*初始化读等待队列头*/
init_waitqueue_head(&globalfifo_devp->w_wait);/*初始化写等待队列头*/
return0;
fail_malloc:
unregister_chrdev_region(devno,1);
returnret;
}
/*模块卸载函数*/
voidglobalfifo_exit(void)
{
cdev_del(&globalfifo_devp->cdev);/*注销cdev*/
kfree(globalfifo_devp);/*释放设备结构体内存*/
unregister_chrdev_region(MKDEV(globalfifo_major,0),1);/*释放设备号*/
}
MODULE_AUTHOR("SongBaohua");
MODULE_LICENSE("DualBSD/GPL");
module_param(globalfifo_major,int,S_IRUGO);
module_init(globalfifo_init);
module_exit(globalfifo_exit);
五.
(1)驱动程序的Makefile:
obj-$(CONFIG_GLOBALFIFO)+=GLOBALFIFO.o
(2)驱动程序的Kconfig为:
configGLOBALFIFO
tristate"zifushebeiqudong"
(3)进入控制界面如图:
(4)驱动模块的产生:
总结:
通过对字符设备驱动的操作,在实验过程中,遇到了很多困难,感觉有好多知识很生疏,学到的知识也不能很好的运用到实践中,在编写字符设备驱动程序时,比如在测试写阻塞,就会遇见写阻塞通过不了的问题,经过老师的讲解。
才知道对于内存分配不合理,在其他地方也会出现很多错误,但是,经过慢慢摸索,我也学到了很多知道,加强了这方面的一些不足,感觉自己在字符设备驱动方面有了很大提高。