2012-08-25 21 views
10

Do zadania domowego napisałem sterownik urządzenia znaków. Wydaje się działać dobrze. Potrafię to przeczytać i napisać. Problem polega na tym, że kiedy czytam urządzenie, nieskończone pętle, w kółko wypisują zawartość bufora komunikatów.bez końca pętla podczas odczytu z urządzenia znaków

Wygląda na to, że powinno być dość proste. Po prostu użyj copy_to_user(), ale okazało się to bardzo problematyczne.

W każdym razie, tutaj jest kod. Myślę, że problem występuje w funkcji gdev_read(). Pliki do druku mają służyć zarówno do debugowania, jak i do mówienia, ponieważ muszę przedstawić projekt na zajęciach.

/* 
* 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. Dobrze. Po spędzeniu kilku kolejnych dni na polowaniu odkryłem, że jeśli zwrócę 0 z gdev_read, to nie otrzymam nieskończonych pętli. Jednak żadne dane nie są drukowane. Chciałabym móc to wymyślić. – skothar

Odpowiedz

7

Jeśli zera nie są zwracane z read() (w przypadku gdev_read()), funkcja odczytu zostanie wywołana ponownie. Aby to zatrzymać, należy użyć parametru loff_t *offset. Zwiększ ją o liczbę bajtów przeczytanych przy użyciu (*offset) += bytes; po copy_to_user(). Następnym razem, gdy zostanie wywołany read(), będzie to numer, do którego je zwiększyłeś. Teraz sprawdź, ile wcześniej wysłałeś bajtów, i wyślij tylko to, co jeszcze zostało. Twoja funkcja powinna wyglądać następująco:

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

, ale wartość zmiennej "bytes" nigdy nie będzie równa zero, więc czy nie będzie ona ponownie wywoływana? – aditya

+0

z tym, że potrzebowałby także dodatkowego warunku do "powrotu 0;" tj. "if (* ppos! = 0) then return 0;". Po odczytaniu danych z urządzenia należy zwrócić 0, aby zatrzymać dalsze czytanie. – mysticTot

0

Można użyć 'simple_read_from_buffer' funkcję z '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' oraz 'buffer_len "są zdefiniowane w twoim module.

Powiązane problemy