2012-08-25 14 views
10

Für eine Hausaufgabe habe ich einen Zeichen Gerätetreiber geschrieben. Es scheint OK zu funktionieren. Ich kann es lesen und schreiben. Das Problem ist, dass, wenn ich das Gerät lese, es Endlosschleifen ausführt und den Inhalt des Nachrichtenpuffers immer wieder ausdruckt.endlos Schleife beim Lesen von Zeichen Gerät

Dies scheint wie es sollte ziemlich geradlinig sein. Verwenden Sie einfach copy_to_user(), aber es hat sich als sehr problematisch erwiesen.

Wie auch immer, hier ist der Code. Ich denke, das Problem liegt in der Funktion gdev_read(). Die printk's dienen sowohl als Debugging- als auch als Diskussionspunkte, da ich das Projekt im Unterricht präsentieren muss.

/* 
* 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. Gut. Nachdem ich ein paar Tage mehr im Web verbracht habe, habe ich festgestellt, dass ich keine Endlosschleifen bekomme, wenn ich 0 von gdev_read zurückgebe. Es werden jedoch keine Daten gedruckt. Ich wünschte, ich könnte das herausfinden. – skothar

Antwort

7

Wenn Null nicht aus read() (in Ihrem Fall gdev_read()) zurückgeführt wird, wird die Lesefunktion erneut aufgerufen werden. Um dies zu stoppen, verwenden Sie den Parameter loff_t *offset. Erhöhen Sie es um die Anzahl der Bytes, die Sie gelesen haben, indem Sie (*offset) += bytes; nach copy_to_user() verwenden. Das nächste Mal, read() wird aufgerufen, offset wird sein, was Sie es inkrementiert haben. Überprüfen Sie jetzt, wieviele Bytes Sie zuvor gesendet haben, und senden Sie nur das, was Sie noch haben. Ihre Funktion sollte wie folgt aussehen:

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

aber Wert der Variablen "Bytes" wird nie Null sein, also wird es nicht noch einmal aufgerufen? – aditya

+0

mit diesem würde es auch eine zusätzliche Bedingung zu "0 zurückgeben"; h. "if (* ppos! = 0) gibt dann 0 zurück;". Sobald Ihre Daten vom Gerät gelesen wurden, sollte 0 zurückgegeben werden, um den weiteren Lesevorgang zu stoppen. – mysticTot

0

Sie verwenden könnte 'simple_read_from_buffer' Funktion von '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' und 'buffer_len sind in Ihrem Modul definiert.