#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>    /* Necesario cuando se utiliza las macros module_init y module_exit */
#include <linux/proc_fs.h> /* Necesario cuando se utiliza /proc */



MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gilberto Diaz");

#define procfs_name "EjemploDeUsoDeProcFS"


int Parametro1 = 0;
extern int Parametro2;

struct proc_dir_entry *Proc_File;


module_param(Parametro1, int, 0);
MODULE_PARM_DESC(Parametro1, "Este es el primer parametro del modulo. Entero con signo");


/* Esta función se invoca cada vez que se lee el archivo en /proc
 *
 * Argumentos
 * =========
 * 1. Buffer donde los datos se insertan, si se decide utilizarlo.
 * 2. Apuntador a apuntador de caracteres. Útil si se decide no utilizar el buffer apartado por el kernel.
 * 3. Posición actual en el archivo. 
 * 4. El tamaño del buffer del primer argumento. 
 * 5. Escribe "1" aqui para indicar fin de archivo (EOF).
 * 6. Apuntador a los datos (Útil en caso de una lectura común para múltiples entradas en /proc)
 *
 */

int procfile_read(char *buffer, char **buffer_location, off_t offset, int buffer_length,
		  int *eof, void *data) {
	int ret;
	printk(KERN_INFO "El archivo en /proc ha sido leido (/proc/%s) called\n", procfs_name);
	if (offset > 0) {
		/* Retornar 0 si se terminó de leer */
		ret = 0;
	} else {
		/* Llenar elbuffer, retornar el tamaño delbuffer */
		ret = sprintf(buffer, "Prueba de Proc FS!\n");
	}
	return ret;
}


int init_module(void) {
	Proc_File = create_proc_entry(procfs_name, 0644, NULL);

	printk(KERN_INFO "Ejemplo de Modulo con ProcFS\n");
	printk(KERN_INFO "Parametro1 = %i\n", Parametro1);
	printk(KERN_INFO "Parametro2 = %i\n", Parametro2);

	if (Proc_File == NULL) {
		remove_proc_entry(procfs_name, NULL);
		printk(KERN_ALERT "Error: No se pudo inicializar /proc/%s\n", procfs_name);
		return -ENOMEM;
	}
	Proc_File->read_proc = procfile_read;
	Proc_File->mode = S_IFREG | S_IRUGO;
	Proc_File->uid = 0;
	Proc_File->gid = 0;
	Proc_File->size = 37;
	printk(KERN_INFO "/proc/%s created\n", procfs_name);

	return 0;
}
