2012-08-25 22 views
10

Per un compito a casa, ho scritto un driver di dispositivo di carattere. Sembra funzionare bene. Posso leggere e scrivere. Il problema è che quando leggo il dispositivo, si riavvolge all'infinito, stampando ripetutamente il contenuto del buffer dei messaggi.a ciclo continuo durante la lettura dal dispositivo di carattere

Sembra che dovrebbe essere abbastanza semplice. Basta usare copy_to_user(), ma ha dimostrato di essere molto problematico.

In ogni caso, ecco il codice. Penso che il problema sia nella funzione gdev_read(). Le stampanti sono lì per servire come debug e come punti di discussione, dal momento che devo presentare il progetto in classe.

/* 
* 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. Bene. Dopo aver trascorso un altro paio di giorni a cacciare il web, ho scoperto che se restituisco 0 da gdev_read, quindi non ottengo loop infiniti. Tuttavia, nessun dato viene stampato. Vorrei poter capire questo. – skothar

risposta

7

Se zero non viene restituito da read() (nel tuo caso gdev_read()), la funzione di lettura sarà chiamato di nuovo. Per smettere di utilizzare il parametro loff_t *offset. Incrementa di quanti byte hai letto utilizzando (*offset) += bytes; dopo copy_to_user(). La prossima volta che si chiama read(), offset sarà ciò che è stato incrementato. Ora controlla solo quanti byte hai inviato in precedenza e invia solo quello che hai ancora. La funzione dovrebbe essere simile a questo:

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

ma il valore della variabile "byte" non sarà mai zero, quindi non verrà richiamato? – aditya

+0

con quello avrebbe anche bisogno di una condizione aggiuntiva per "restituire 0;" cioè, "if (* ppos! = 0) quindi restituisce 0;". Una volta che i tuoi dati sono stati letti dal dispositivo, dovrebbe restituire 0 per interrompere la lettura. – mysticTot

0

si potrebbe usare 'simple_read_from_buffer' funzione dal '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' e 'buffer_len 'sono definiti nel modulo.

Problemi correlati