2012-08-25 15 views
10

Para una tarea, he escrito un controlador de dispositivo de caracteres. Parece funcionar bien. Puedo leer y escribir. El problema es que cuando leo el dispositivo, se repite sin parar, imprimiendo el contenido del búfer de mensajes una y otra vez.bucle continuo al leer del dispositivo de caracteres

Esto parece que debería ser bastante directo. Simplemente use copy_to_user(), pero ha demostrado ser muy problemático.

De todos modos, aquí está el código. Creo que el problema está en la función gdev_read(). Los printk están ahí para servir como depuración y como puntos de discusión, ya que tengo que presentar el proyecto en clase.

/* 
* 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. Bien. Después de pasar un par de días más buscando en la web, descubrí que si devuelvo 0 desde gdev_read, no obtengo infinitos bucles. Sin embargo, no se imprimen datos. Ojalá pudiera resolver esto. – skothar

Respuesta

7

Si es cero no se devuelve desde read() (en su caso gdev_read()), la función de lectura se llamará de nuevo. Para detener esto, usa el parámetro loff_t *offset. Increméntelo por cuántos bytes ha leído usando (*offset) += bytes; después de copy_to_user(). La próxima vez que se llame read(), offset será lo que haya incrementado. Ahora solo verifique cuántos bytes ha enviado previamente y solo envíe lo que aún le queda. Su función debería tener este aspecto:

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

pero el valor de la variable "bytes" nunca será cero, entonces ¿no se volverá a llamar? – aditya

+0

con eso también necesitaría una condición adicional para "devolver 0"; es decir, "if (* ppos! = 0) luego devuelve 0;". Una vez que sus datos han sido leídos desde el dispositivo, debe devolver 0 para dejar de leer más. – mysticTot

0

usted podría utilizar 'simple_read_from_buffer' función de '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' y 'buffer_len 'están definidos en su módulo.

Cuestiones relacionadas