2015-05-09 52 views
6

我學習設備驅動程序編程,我已經創造了在那裏我是從一個用戶空間應用程序再從另一個傳遞數據並將其存儲在內核空間循環緩衝區,然後讀這個循環緩衝區的簡單字符驅動程序用戶空間應用。字符驅動程序與循環緩衝區

我使用的Linux內核版本3.3.6

我的驅動程序代碼是:

/* A simple character driver program to pass some data from user space and storing that on kernel circular buffer and reading back it on user space */ 

#include<linux/kernel.h> 
#include<linux/init.h> 
#include<linux/module.h> 
#include<linux/vmalloc.h> 
#include<linux/fs.h> 
#include<linux/major.h> 
#include<linux/cdev.h> 
#include<asm/uaccess.h> 
#include<linux/slab.h> 
#include<linux/device.h> 
#include<linux/types.h> 
#include<linux/kdev_t.h> 
#include<linux/wait.h> 
#include<linux/sched.h> 
#include<linux/circ_buf.h> 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("C-DAC"); 
#define MAX_DEVICE 2 
#define KERN_BUFF_SIZE 1 
#define DRIVER_NAME "ass3q1" 

int my_open(struct inode *inode, struct file *filp); 
ssize_t my_write(struct file *filp, const char __user *usr_buff, size_t count, loff_t *ppos); 
ssize_t my_read(struct file *filp, char __user *usr_buf, size_t count, loff_t *ppos); 
int my_release(struct inode *inode, struct file *filp); 
long my_ioctl(struct file *filp, unsigned int cmd,unsigned long arg); 


/* DEFINE A DEVICE SPECIFIC DATA */ 
typedef struct privatedata1 
{ 
    int minor_num; 
    struct cdev mycdev; 
    struct circ_buf KERN_BUFF; 
    int KERN_SIZE; 
// char KERN_BUFF[KERN_BUFF_SIZE]; 
}my_privatedata; 

my_privatedata devices[MAX_DEVICE]; 

/* DECLARE THE REQUIRED VARIABLES */ 
int major; 
int minor=1; 
dev_t device_num; 

struct class *my_class; 
struct device *my_device; 

/* DEFINE THE FILE OPERATIONS STRUCTURE OF THE CHAR DRIVER */ 
struct file_operations my_fops={ 
    .owner  = THIS_MODULE, 
    .open  = my_open, 
    .write  = my_write, 
    .read  = my_read, 
    .release = my_release, 
    .unlocked_ioctl = my_ioctl, 
}; 


/* INITIALISATION FUNCTION */ 
static int __init my_init(void) 
{ 
    int i; 
    int res; 
    printk("\nI am in Init Function"); 
    /* DYNAMICALLY DEVICE NUMBER */ 
    res = alloc_chrdev_region(&device_num,minor,MAX_DEVICE,DRIVER_NAME); 
    if(res<0) 
    { 
     printk("\nRegister Device Num generation failed"); 
     return -1; 
    } 
    major = MAJOR(device_num); 

    my_class = class_create(THIS_MODULE,DRIVER_NAME); 
    if(my_class == NULL) 
    { 
     printk("\nClass creation failed"); 
     return -1; 
    } 

    for(i=0; i<MAX_DEVICE; i++) 
    { 
     device_num = MKDEV(major, minor + i); 
     cdev_init(&devices[i].mycdev,&my_fops);  //registration of device 
     cdev_add(&devices[i].mycdev,device_num,1); //attachment of device 

     /* CREATE DEVICE NODES IN /dev/ DIRECTORY */ 
     my_device = device_create(my_class,NULL,device_num,NULL,"sample_cdev%d",i);  
     if(my_device == NULL) 
     { 
      class_destroy(my_class); 
      printk("\nDevice creation failed"); 
      return -1; 
     } 

     devices[i].minor_num = minor+i; 
    } 
    return 0; 
} 

static void __exit my_exit(void) 
{ 
    int i; 

    printk("\nI am in Exit Function"); 
    /* REMOVE DEVICES AND NODES */ 
    for(i=0; i<MAX_DEVICE; i++) 
    { 
     device_num = MKDEV(major, minor + i); 
     cdev_del(&devices[i].mycdev); 
     device_destroy(my_class, device_num); 
    } 

    /* DESTROY CLASS */ 
    class_destroy(my_class); 

    /* UNREGISTER DEVICE WITH KERNEL */ 
    device_num = MKDEV(major, minor); 
    unregister_chrdev_region(device_num, MAX_DEVICE); 
} 

/* DEVICE OPEN METHOD */ 
int my_open(struct inode *inode, struct file *filp) 
{ 
    my_privatedata *dev = container_of(inode->i_cdev, my_privatedata, mycdev); 
    filp->private_data = dev; 
    dev->KERN_SIZE = 4096; 
    printk("\nIn character driver open function device node %d", dev->minor_num); 
    return 0; 
} 

/* DEVICE WRITE METHOD */ 
ssize_t my_write(struct file *filp, const char __user *usr_buff, size_t count, loff_t *ppos) 
{ 
    my_privatedata *dev = filp->private_data; 

    if(CIRC_SPACE(dev->KERN_BUFF.head, dev->KERN_BUFF.tail, dev->KERN_SIZE) >= 1) 
    { 
     int i; 
     char ch; 
     for(i=0; i<count; i++) 
     { 
      get_user(ch, &usr_buff[i]); 
      dev->KERN_BUFF.buf[dev->KERN_BUFF.head] = ch; 
      printk("\nIn character driver write function and value of KERN_BUFF is: %s", dev->KERN_BUFF.buf); 
      dev->KERN_BUFF.head = (dev->KERN_BUFF.head + 1) & (dev->KERN_SIZE-1); 
     } 
    } 
    else 
    { 
     printk("\nCopy from user to kernel space failed"); 
     return -EFAULT; 
    } 
    return 0; 
} 

/* DEVICE READ METHOD */ 
ssize_t my_read(struct file *filp, char __user *usr_buf, size_t count, loff_t *ppos) 
{ 
    my_privatedata *dev = filp->private_data; 
    int res; 
    printk("\nI am in character driver read function"); 
    dev->KERN_BUFF.buf = "Bye Bye"; 
// usr_buf = dev->KERN_BUFF.buf; 

    res = copy_to_user((char *)usr_buf, (char *)dev->KERN_BUFF.buf, strlen(dev->KERN_BUFF.buf)+1); 
    printk("\nData '%s' from kernel buffer to user buffer copied successfully with bytes: %d",dev->KERN_BUFF.buf,strlen(dev->KERN_BUFF.buf)); 

/* if(res == 0) 
    { 
     printk("\nData '%s' from kernel buffer to user buffer copied successfully with bytes: %d",dev->KERN_BUFF.buf,strlen(dev->KERN_BUFF.buf)); 
     memset(dev->KERN_BUFF.buf, 0, strlen(dev->KERN_BUFF.buf)); 
     return strlen(dev->KERN_BUFF.buf); 
    } 
    else 
    { 
     printk("\nCopy from kernel to user failed"); 
     return -EFAULT; 
    } 
*/ 
    return 0; 
} 

/* DEVICE RELEASE METHOD */ 
int my_release(struct inode *inode, struct file *filp) 
{ 
    my_privatedata *dev = filp->private_data; 
    printk("\nI am in release function and minor number is %d", dev->minor_num); 
    return 0; 
} 

/* DRIVER IOCTL METHOD */ 
long my_ioctl(struct file *filp, unsigned int cmd,unsigned long arg) 
{ 
    printk("\nIn Driver ioctl function"); 
    my_privatedata *dev = filp->private_data; 

    switch (cmd) 
    { 
     case 1: 
      { 
       int count; 
       count = CIRC_CNT(dev->KERN_BUFF.head, dev->KERN_BUFF.tail,dev->KERN_SIZE); 
       printk("\nSize of buffer count is %d",count); 
       return count; 
       break; 
      } 
     case 2: 
      { 
       int space; 
       space = CIRC_SPACE(dev->KERN_BUFF.head, dev->KERN_BUFF.tail,dev->KERN_SIZE); 
       printk("\nSize of buffer count is %d",space); 
       return space; 
       break; 
      } 
     default: 
      { 
       printk("\nNothing to show"); 
       break; 
      } 
    } 
} 

module_init(my_init); 
module_exit(my_exit); 

我的用戶空間應用程序的作家是

#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<fcntl.h> 
#include<string.h> 

int main() 
{ 
    int fd; 
    char Ubuff[50], Kbuff[50]; 

    fd = open("/dev/sample_cdev1", O_RDWR); 
    if(fd < 0) { 
     perror("Unable to open the device file\n"); 
     return -1; 
    } 

    printf("\nPlease enter a string"); 
    gets(Ubuff); 

    /* Write the data into the device */ 
    write(fd , Ubuff , strlen(Ubuff) + 1); 

    close(fd); 
    return 0; 
} 

我的用戶空間閱讀器應用程序是

#include<stdio.h> 
#include<stdlib.h> 
#include<unistd.h> 
#include<fcntl.h> 
#include<string.h> 

int main() 
{ 
    int fd; 
    char Ubuff[50], Kbuff[50]; 

    fd = open("/dev/sample_cdev1", O_RDWR); 
    if(fd < 0) { 
     perror("Unable to open the device file\n"); 
     return -1; 
    } 

    /* Read the data back from the device */ 
    memset(Kbuff , 0 ,sizeof(Kbuff)); 
    read(fd , Kbuff , sizeof(Kbuff)); 
    printf("Data from kernel : %s\n", Kbuff); 

    close(fd); 
    return 0; 
} 

在my_write功能,我得到一個內核空指針引用錯誤,在

  dev->KERN_BUFF.buf[dev->KERN_BUFF.head] = ch; 
      printk("\nIn character driver write function and value of KERN_BUFF is: %s", dev->KERN_BUFF.buf); 
      dev->KERN_BUFF.head = (dev->KERN_BUFF.head + 1) & (dev->KERN_SIZE-1); 

my_read功能似乎並不正確,但由於我無法寫東西到內核環形緩衝區,我無法測試my_read功能。

我在做什麼錯?

+0

我沒有檢查張貼的代碼。但是,管道已經做了這種非常類型的組織。如果是我,我只需使用管道。 – user3629249

+0

在用戶空間閱讀器應用程序中,當讀取返回值(當前未被檢查)指示讀取的0字節或指示錯誤時,memset,read,printf序列是否應該處於循環中並退出循環? – user3629249

+0

'gets'已折舊並很快從C.中刪除,建議使用'fgets',因爲緩衝區溢出很容易避免。 – user3629249

回答

0

我認爲這個問題是你有沒有在你的循環緩衝區分配的任何空間... dev->KERN_BUFF.buf = kmalloc(...) 不要忘記釋放。 此外,您正在註冊2 my_private_data,這意味着每個fd都會獲得自己的my_private_data。我認爲你希望生產者和消費者能夠解決相同的數據。也許你會需要一個...用spin_lock

也看到這一點:CIRCULAR BUFFERS