udev動態申請裝置號
轉載自:http://blog.csdn.net/yongan1006/article/details/6632480#comments
|
上面的內容說的很有用。
此前,我按照《linux裝置驅動開發詳解》的例程學習,發現驅動並不能正常工作。鄙人實在是太菜了,甚至沒想過用手工去建立裝置節點,所以常常為裝置節點的事苦惱。
下面,我結合自己的實踐,分享下我的實驗成果:
驅動原始碼:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#define MAJOR_NUM 251
/*此處要根據自己的/proc/device/目錄下的情況,選一下不重複的主裝置號就好*/
#define DEVSIZE 0X1000
MODULE_LICENSE("GPL");
/*定義裝置結構體,其中包括分配cdev*/
struct globalvar_dev{
struct cdev cdev;
unsigned char mem[DEVSIZE];
};
struct globalvar_dev dev;
struct class *myclass;
static ssize_t globalvar_read(struct file *filp,char*buf,size_t count,loff_t *ppos)
{
unsigned long p=*ppos;
int ret=0;
/*分析和獲取有效的讀長度*/
if(p>=DEVSIZE)//要讀的位元組數太大
return 0;
if(count>DEVSIZE-p)//要求的位元組數太大
count=DEVSIZE-p;
if(copy_to_user(buf,(void *)(dev.mem+p),count)){
ret=-EFAULT;
}
else{
*ppos +=count;
ret = count;
printk(KERN_INFO "read %d bytes from %ld\n",count,p);
}
return ret;
}
static ssize_t globalvar_write(struct file *filp,const char*buf,size_t count,loff_t *ppos)
{
unsigned long p = *ppos;
int ret = 0;
/*分析和獲取有效的讀長度*/
if(p>=DEVSIZE)//要讀的位元組數太大
return 0;
if(count>DEVSIZE-p)//要求的位元組數太大
count=DEVSIZE-p;
if(copy_from_user(dev.mem+p,buf,count))
ret = -EFAULT;
else{
*ppos += count;
ret = count;
printk(KERN_INFO "written %d byte from %ld\n",count,p);
}
return ret;
}
static loff_t globalvar_llseek(struct file *filp,loff_t offset,int orig)
{
loff_t ret;
switch(orig)
{
case 0:
if (offset<0){
ret=-EINVAL;
break;
}
if((unsigned int)offset >DEVSIZE){
ret=-EINVAL;
break;
}
filp->f_pos=(unsigned int)offset;
ret=filp->f_pos;
break;
case 1:
if (filp->f_pos+offset<0){
ret=-EINVAL;
break;
}
if(filp->f_pos+(unsigned int)offset >DEVSIZE){
ret=-EINVAL;
break;
}
filp->f_pos+=(unsigned int)offset;
ret=filp->f_pos;
break;
case 2:
if (DEVSIZE-1+offset<0){
ret=-EINVAL;
break;
}
if(DEVSIZE-1+(unsigned int)offset >DEVSIZE){
ret=-EINVAL;
break;
}
filp->f_pos=DEVSIZE-1+(unsigned int)offset;
ret=filp->f_pos;
break;
default:
ret = -EINVAL;
}
return ret;
}
struct file_operations globalvar_fops=
{
.owner=THIS_MODULE,
.write=globalvar_write,
.read=globalvar_read,
.llseek=globalvar_llseek,
};
static int __init globalvar_init(void)
{
int err;
int result;
//第一步:取得裝置號
dev_t devno = MKDEV(MAJOR_NUM,0);/*主,次裝置號*/
if(MAJOR_NUM)
/*register_chrdev_region(裝置號指標,裝置號數目,裝置名)*/
result=register_chrdev_region(devno,1,"globalvar");
else
{
/*alloc_chrdev_region(分配到的裝置號指標,起始次裝置號,
需要分配的裝置號數目,裝置名稱)*/
result = alloc_chrdev_region(&devno,0,1,"globalvar");
//MAJOR_NUM=MAJOR(devno);
}
/*第二步:初始化cdev*/
cdev_init(&dev.cdev,&globalvar_fops);/*建立cdev和file_operations之間的連線*/
dev.cdev.owner=THIS_MODULE;
dev.cdev.ops=&globalvar_fops;
/*第三步:註冊字元裝置*/
/*cdev_add(cdev結構指標,裝置號,裝置數目)*/
err=cdev_add(&dev.cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding globalvar",err);
/*增加對udev的支援*/
myclass = class_create(THIS_MODULE, "globalvar");
device_create(myclass, NULL, MKDEV(MAJOR_NUM, 0), NULL, "globalvar");
printk("globalvar installs success");
return 0;
}
static void __exit globalvar_exit(void)
{
class_destroy(myclass);
device_destroy(myclass,MKDEV(MAJOR_NUM,0));
cdev_del(&dev.cdev);/*登出cdev結構*/
unregister_chrdev_region(MKDEV(MAJOR_NUM,0),1);/*登出裝置號*/
printk("globalvar exits success");
}
module_init(globalvar_init);
module_exit(globalvar_exit);
上面引用的文章已經說的很清楚,如果你手工建立節點,就不需要紅色字型的內容。加上紅色字型內容後,如果你的平臺已經有了udev ,那麼它就會自動建立裝置節點。
測試原始碼:
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
void main()
{
FILE *fp0 =NULL;
char Buf[4096];
strcpy(Buf,"globalvar is char dev!");
printf("BUF:%s\n",Buf);
fp0=fopen("/dev/globalvar","r+");
if(fp0==NULL){
printf("Open globalvar Error!\n");
return -1;
}
fwrite(Buf,sizeof(Buf),1,fp0);
fseek(fp0,0,SEEK_SET);
strcpy(Buf,"Buf is NULL!");
printf("BUF:%s\n",Buf);
fread(Buf,sizeof(Buf),1,fp0);
printf("BUF: %s\n",Buf);
return 0;
}
以上原始碼,我已測試通過。只是還有一點不毛病:
看到了嗎?本來就是
BUF:glogalvar is char dev!
Read 4096 bytes from
……
我不知道怎麼搞的,它們混到一塊兒了,不過,這個問題應該和驅動沒有關係。如果哪們仁兄知道怎麼回事,還請告訴我一下。好了,基本上就這樣了。