El driver "puertopar" al completo

Procederemos ahora a ver todo el código del módulo "puertopar". En general habrá que cambiar en todo el código, respecto al módulo memoria.c, las palabras "memoria" por "puertopar". El driver final queda como sigue:

  <<puertopar.c>>=
<<puertopar inicio>>
<<puertopar init module>>
<<puertopar cleanup module>>
<<puertopar open>>
<<puertopar release>>
<<puertopar read>>
<<puertopar write>>

Sección inicial

En la parte inicial del driver utilizaremos un número mayor diferente, el 61, cambiaremos la variable global memoria_buffer por port e incluiremos con #include los ficheros ioport.h y io.h.

   <<puertopar inicio>>=

/* Definiciones e includes necesarios para los drivers */
#define MODULE 
#define __KERNEL__ 
#include <linux/config.h> 
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */ 
#include <linux/malloc.h> /* kmalloc() */ 
#include <linux/fs.h> /* everything... */ 
#include <linux/errno.h> /* error codes */ 
#include <linux/types.h> /* size_t */ 
#include <linux/proc_fs.h> 
#include <linux/fcntl.h> /* O_ACCMODE */ 
#include <linux/ioport.h>
#include <asm/system.h> /* cli(), *_flags */ 
#include <asm/uaccess.h> /* copy_from/to_user */ 
#include <asm/io.h> /* inb, outb */

/* Declaracion de funciones de puertopar.c */
int puertopar_open(struct inode *inode, struct file *filp); 
int puertopar_release(struct inode *inode, struct file *filp); 
ssize_t puertopar_read(struct file *filp, char *buf, 
  size_t count, loff_t *f_pos); 
ssize_t puertopar_write(struct file *filp, char *buf, 
  size_t count, loff_t *f_pos); 
void cleanup_module(void);

/* Estructura que declara las funciones tipicas */
/* de acceso a ficheros */
struct file_operations puertopar_fops = { 
  read: puertopar_read,
  write: puertopar_write,
  open: puertopar_open,
  release: puertopar_release 
}; 

/* Variables globales del driver */
/* Numero mayor */
int puertopar_major = 61; 

/* Variable de control para la reserva */
/* de memoria del puerto paralelo*/
int port;


Inicio del módulo

En la rutina de inicio del módulo incluiremos la reserva de la dirección de memoria del puerto paralelo como describimos antes.

   <<puertopar init module>>= 
int init_module(void) { 
  int result; 

  /* Registrando dispositivo */
  result = register_chrdev(puertopar_major, "puertopar", 
      &puertopar_fops);
  if (result < 0) { 
    printk(
      "<1>puertopar: no puedo obtener numero mayor %d\n",
      puertopar_major); 
    return result; 
  } 
   
  <<puertopar modificacion init module>> 

  printk("<1>Insertando modulo\n"); 
  return 0;

  fallo: 
    cleanup_module(); 
    return result;
}

Eliminación del módulo

La rutina de eliminación del módulo incluirá las modificaciones antes reseñadas.

   <<puertopar cleanup module>>= 
void cleanup_module(void) {

  /* Liberamos numero mayor */
  unregister_chrdev(puertopar_major, "memoria"); 

  <<puertopar modificacion cleanup module>>

  printk("<1>Quitando modulo\n");
}

Abriendo el dispositivo como fichero

Esta rutina es idéntica a la del driver "memoria".

   <<puertopar open>>=
int puertopar_open(struct inode *inode, struct file *filp) { 
  /* Aumentamos la cuenta de uso */ 
  MOD_INC_USE_COUNT; 

  /* Exito */
  return 0; 

}

Cerrando el dispositivo como fichero

De nuevo la similitud es exacta.

   <<puertopar release>>=
int puertopar_release(struct inode *inode, struct file *filp) { 

  /* Decrementamos la cuenta de uso */
  MOD_DEC_USE_COUNT; 

  /* Exito */
  return 0; 
}

Leyendo del dispositivo

La función de lectura es análoga a la del "memoria" con las consiguientes modificaciones de lectura del puerto del dispositivo.

   <<puertopar read>>=
ssize_t puertopar_read(struct file *filp, char *buf, 
  size_t count, loff_t *f_pos) {
 
  /* Buffer para leer el dispositivo */
  char puertopar_buffer;

  <<puertopar inport>>

  /* Transferimos datos al espacio de usuario */
  copy_to_user(buf,&puertopar_buffer,1); 
  
  /* Cambiamos posición de lectura segun convenga */
  if (*f_pos == 0) { 
    *f_pos+=1; 
    return 1; 
  } else { 
    return 0; 
  }
}

Escribiendo al dispositivo

Es igual que el del "memoria" pero añadiendo la escritura al puerto del dispositivo.

   <<puertopar write>>=
ssize_t puertopar_write( struct file *filp, char *buf, 
  size_t count, loff_t *f_pos) { 

  char *tmp; 

  /* Buffer para leer el dispositivo */
  char puertopar_buffer;

  tmp=buf+count-1;
  copy_from_user(&puertopar_buffer,tmp,1);

  <<puertopar outport>>
  
  return 1; 
}