2012-01-28 28 views
2

我已经多次尝试下面的代码。用于从内核模块写入和读取设备文件的代码?

#include<linux/module.h> 
#include<linux/kernel.h> 
#include<linux/fs.h> 
#include<linux/cdev.h> 
#include<asm/uaccess.h> 
#include<linux/semaphore.h> 

MODULE_LICENSE("DUAL BSD/GPL"); 
static int dev_open(struct inode *,struct file *); 
static int dev_release(struct inode *,struct file *); 
ssize_t dev_read(struct file *,char *, size_t ,loff_t *); 
ssize_t dev_write(struct file *,const char *,size_t ,loff_t *); 

static int major; 
int dev_major = 0; 
int dev_minor = 0; 
struct cdev *cdev; 

struct device { 
    char array[100]; 
    struct semaphore sem; 
}chr_arr; 

struct file_operations dev_ops = { 
    .owner = THIS_MODULE, 
    .read = dev_read, 
    .write = dev_write, 
    .open = dev_open, 
    .release = dev_release 
}; 

ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset) 
{ 
    int i; 
    i=copy_to_user(buf,chr_arr.array,count); 
    printk(KERN_ALERT"buff:%s",buf); 
    return i; 
} 

ssize_t dev_write(struct file *filp,const char *buf,size_t count,loff_t *offset) 
{ 
    //printk(KERN_ALERT"\nsorry,byebye"); 
    int j; 
    //msg_ptr = kmalloc(count,GFP_KERNEL); 
    //for(j=0;j<count;j++) 
    if(count>100) 
     return -1; 
    j = copy_from_user(chr_arr.array,buf,count); 
    //printk(KERN_ALERT"msg_ptr:%s",msg_ptr); 
    return j; 
} 

static int dev_open(struct inode *inode,struct file *filp) 
{ 
    filp->private_data = inode->i_cdev; 
    if(down_interruptible(&chr_arr.sem)) 
    { 
     printk(KERN_INFO " could not hold semaphore"); 
     return -1; 
    } 
    //printk(KERN_ALERT"ah ha the device is open !now we can go further"); 
    return 0; 
} 

static int dev_release(struct inode *inode,struct file *filp) 
{ 
    up(&chr_arr.sem); 
    //module_put(THIS_MODULE); 
    return 0; 
} 

static int init_device(void) 
{ 
    int result; 
    dev_t dev_no,dev; 
    result = alloc_chrdev_region(&dev_no,0,1,"chr_dev"); 
    if(result < 0) 
    { 
     printk("sorry no major number left"); 
     return result; 
    } 
    major = MAJOR(dev_no); 
    dev = MKDEV(major,0); 
    cdev = cdev_alloc(); 
    cdev->ops = &dev_ops; 
    sema_init(&chr_arr.sem,1); 
    printk("the major number allocated is %d\n",major); 
    result = cdev_add(cdev,dev,1); 
    if(result < 0) 
    { 
     printk(KERN_INFO "Unable to allocate cdev"); 
     return result; 
    } 
    return 0; 
} 

static void clean_device(void) 
{ 
    cdev_del(cdev); 
    unregister_chrdev_region(major,1); 
} 

module_init(init_device); 
module_exit(clean_device); 

但它给了我下面的警告。

CC [M] /home/karan/practice/scrw/scrw1.o 
In file included from /usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess.h:571:0, 
      from /home/karan/practice/scrw/scrw1.c:4: 
In function ‘copy_from_user’,inlined from ‘write’ at /home/karan/practice/scrw/scrw1.c:43:6: 
/usr/src/linux-2.6.34.10-0.6/arch/x86/include/asm/uaccess_32.h:212:26: warning: call to ‘copy_from_user_overflow’ declared with attribute warning: copy_from_user() buffer size is not provably correct 
Building modules, stage 2. 
MODPOST 1 modules 
CC  /home/karan/practice/scrw/scrw1.mod.o 
LD [M] /home/karan/practice/scrw/scrw1.ko 

然后当我尝试写回显hi>/dev/my_dev时,屏幕在30秒左右后会冻结。

+2

不应该测试计数<100吗? – ypnos 2012-01-28 19:37:30

+0

@ypnos多数民众赞成可以,但它不工作,只要我把回声命令挂了几秒钟后...... – karan421 2012-01-28 20:01:12

+0

这个问题可能在别的地方。你能展示更多的代码吗?您也可以尝试使用启用了调试选项的方式重新编译内核,这样您可以在发生冻结时获得堆栈跟踪。 – ldx 2012-01-29 10:44:40

回答

6

问题是,如果一切顺利,您应该返回读取/写入方法中读取/写入的字节数,copy_ {from,to} _user()的返回值为0。例如返回在你写的方法计算,如果复制成功:

unsigned long ret; 
printk(KERN_INFO "Inside write \n"); 
if (count > sizeof(char_arr.array) - 1) 
    return -EINVAL; 
ret = copy_from_user(char_arr.array, buff, count); 
if (ret) 
    return -EFAULT; 
char_arr.array[count] = '\0'; 
return count; 

你也应该确保终止“\ 0”,当你复制到缓冲区(如果你想只用字符串处理)字符追加。如果它是您处理的二进制数据,则将其长度存储在您的结构中。

一个例子读取方法:

ssize_t dev_read(struct file *filp,char *buf,size_t count,loff_t *offset) 
{ 
    int len = count >= strlen(chr_arr.array) ? strlen(chr_arr.array) : count; 

    if (*offset >= strlen(chr_arr.array)) 
     return 0; 

    if (copy_to_user(buf,chr_arr.array,len)) 
     return -EFAULT; 

    return len; 
} 

编辑:弄乱了示例代码,将其固定。

Edit2:示例读取方法。

+0

现在写功能工作正常,但阅读功能不是...每当我使用猫/ dev/my_dev它无限期地读取我已经尝试与返回计数dwithout它也......请帮助 – karan421 2012-01-30 06:54:42

+0

这是因为你应该返回0一旦用户到达设备的尽头。您可以使用偏移来存储当前位置。 – ldx 2012-01-30 12:28:21

+0

我认为当任何用户在设备文件中写入hi(echo hi>/dev/my_dev)时,它将不会进入设备文件的末尾(如果我错了,请纠正我)....我如何使用偏移量你能告诉我代码....真的非常感谢你的热情和兴趣...... – karan421 2012-01-31 06:57:21