2012-08-25 28 views
10

Đối với bài tập về nhà, tôi đã viết một trình điều khiển thiết bị ký tự. Dường như nó hoạt động tốt. Tôi có thể đọc và viết nó. Vấn đề là khi tôi đọc thiết bị, nó không ngừng lặp lại, in ra các nội dung của bộ đệm tin nhắn hơn và hơn.lặp vô tận khi đọc từ thiết bị ký tự

Điều này có vẻ tương tự như vậy. Chỉ cần sử dụng copy_to_user(), nhưng nó đã được chứng minh là rất có vấn đề.

Dù sao, đây là mã. Tôi nghĩ rằng vấn đề nằm trong hàm gdev_read(). Các printk đang có để phục vụ như gỡ lỗi cũng như các điểm nói chuyện, vì tôi phải trình bày dự án trong lớp.

/* 
* Implement a generic character pseudo-device driver 
*/ 

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

/* you need these, or the kernel will be tainted */ 
MODULE_LICENSE("GPL"); 
MODULE_DESCRIPTION("A simple sample character device driver"); 

/* 
* function prototypes 
*/ 
int init_module(void); 
void cleanup_module(void); 
static ssize_t gdev_read(struct file *, char *, size_t, loff_t *); 
static ssize_t gdev_write(struct file *, const char *, size_t, loff_t *); 
static int gdev_open(struct inode *, struct file *); 
static int gdev_release(struct inode *, struct file *); 

/* macros */ 
#define TRUE 1 
#define FALSE 0 
#define MAX_MSG_LEN 64 

/* 
* global variables 
*/ 
static dev_t dev_num; /* device number, for new device */ 
static char *mesg; /* buffer for message */ 


/* file operations structure, so my device knows how to act */ 
static struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .read =  gdev_read, 
    .write = gdev_write, 
    .open =  gdev_open, 
    .release = gdev_release, 
}; 

/* character device struct. Declaired here, but initialized elsewhere */ 
struct cdev *gdev; 

int init_module(void) 
{ 
    int err; 
    printk(KERN_ALERT "in init_module\n"); 

    if(alloc_chrdev_region(&dev_num, 0, 1, "/dev/gdev")){ 
     printk(KERN_INFO "Could not allocate device numbers\n"); 
     printk(KERN_INFO "Module gdev not loaded\n"); 
     return -1; 
    } 

    /* now I need to make the device and register it */ 
    gdev = cdev_alloc(); 
    gdev->owner = THIS_MODULE; 
    gdev->ops = &fops; 
    err = cdev_add(gdev, dev_num, 1); 
    if(err){ 
     printk(KERN_NOTICE "Error %d adding gdev", err); 
     return err; 
    } 

    mesg = (char *)vmalloc(MAX_MSG_LEN); 

    printk(KERN_INFO "Module gdev successfully loaded.\n"); 
    printk(KERN_INFO "gdev Major Number: %d\n", MAJOR(dev_num)); 

    return 0; 
} 


void cleanup_module(void) 
{ 
    printk(KERN_ALERT "in cleanup_module\n"); 
    unregister_chrdev_region(dev_num, 3); 
    vfree(mesg); 
    cdev_del(gdev); 
    printk(KERN_INFO "Module gdev unregistered\n"); 
} 

static ssize_t gdev_read(struct file *filp, char *page, 
      size_t len, loff_t *offset) 
{ 
    ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN; 
    printk(KERN_ALERT "in gdev_read\n"); 
    if(copy_to_user(page, mesg, bytes)){ 
     return -EFAULT; 
    } 
    return bytes; 
} 

static ssize_t gdev_write(struct file *filp, const char *page, 
      size_t len, loff_t *offset) 
{ 
    ssize_t bytes = len < MAX_MSG_LEN ? len : MAX_MSG_LEN; 
    printk(KERN_ALERT "in gdev_write\n"); 
    if(copy_from_user(mesg, page, bytes)){ 
     return -EFAULT; 
    } 

    return bytes; 
} 

static int gdev_open(struct inode *inode, struct file *filp) 
{ 
    printk(KERN_ALERT "in gdev_open\n"); 
    return 0; 
} 

static int gdev_release(struct inode *inode, struct file *filp) 
{ 
    printk(KERN_ALERT "in gdev_release\n"); 
    /* doesn't do anything because it doesn't need too */ 
    return 0; 
} 
+0

hm. Tốt. Sau khi dành thêm vài ngày để khám phá trang web, tôi đã thấy rằng nếu tôi trả về 0 từ gdev_read, thì tôi sẽ không nhận được các vòng lặp vô hạn. Tuy nhiên, không có dữ liệu nào được in. Ước gì tôi có thể tìm ra cái này. – skothar

Trả lời

7

Nếu zero không được trả về từ read() (trong trường hợp của bạn gdev_read()), chức năng đọc sẽ được gọi một lần nữa. Để ngăn chặn điều này, bạn sử dụng thông số loff_t *offset. Tăng thêm số lượng byte bạn đã đọc bằng cách sử dụng (*offset) += bytes; sau copy_to_user(). Lần sau, read() được gọi, offset sẽ là những gì bạn đã tăng lên. Bây giờ, bạn chỉ cần kiểm tra xem bạn đã gửi bao nhiêu byte và chỉ gửi những gì bạn còn lại. Chức năng của bạn sẽ trông như thế này:

static ssize_t gdev_read(struct file *filp, char *page, 
      size_t len, loff_t *offset) 
{ 
    ssize_t bytes = len < (MAX_MSG_LEN-(*offset)) ? len : (MAX_MSG_LEN-(*offset)); 
    printk(KERN_ALERT "in gdev_read\n"); 
    if(copy_to_user(page, mesg, bytes)){ 
     return -EFAULT; 
    } 
    (*offset) += bytes; 
    return bytes; 
} 
+0

nhưng giá trị của biến "byte" sẽ không bao giờ bằng không, do đó, nó sẽ không được gọi lại? – aditya

+0

với điều đó, nó cũng sẽ cần thêm một điều kiện để "trả về 0;" nghĩa là "nếu (* ppos! = 0) thì trả về 0;". Khi dữ liệu của bạn đã được đọc từ thiết bị, nó sẽ trả về 0 để dừng đọc thêm. – mysticTot

0

Bạn có thể sử dụng 'simple_read_from_buffer' chức năng từ 'linux/fs.h':

static ssize_t gdev_read(struct file *filep, char __user *buff, size_t count, loff_t *offp) 
{ 
    return simple_read_from_buffer(buff, count, offp, my_buffer, buffer_len); 
} 

'my_buffer' và 'buffer_len 'được xác định trong mô-đun của bạn.

Các vấn đề liên quan