Al principio (capítulo 1), dije que X y la programación de módulos del núcleo no se mezclaban. Esto es verdad para el desarrollo de módulos del núcleo, pero en el uso real quieres poder enviar mensajes a cualquiera que sea el tty9.1 de donde vino la orden que cargó el módulo.
La forma de hacer esto es usando current, un puntero a la tarea actualmente en ejecución, para obtener la estructura tty de la tarea actual. Después miramos dentro de la estructura tty para encontrar un puntero a una función de escritura de cadenas de caracteres, que usamos para escribir una cadena de caracteres a la tty.
/* printk.c - envía salida textual al tty en el que estás
* ahora, sin importarle cuando es pasado
* a través de X11, telnet, etc. */
/* Copyright (C) 1998 por Ori Pomerantz */
/* Los ficheros de cabeceras necesarios */
/* Estándar en los módulos del núcleo */
#include <linux/kernel.h> /* Estamos haciendo trabajo del núcleo */
#include <linux/module.h> /* Específicamente, un módulo */
/* Distribuido con CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* Necesarios aquí */
#include <linux/sched.h> /* Para el actual */
#include <linux/tty.h> /* Para las declaraciones de tty */
/* Imprime la cadena de caracteres al tty apropiado, el
* que usa la tarea actual */
void print_string(char *str)
{
struct tty_struct *my_tty;
/* La tty para la tarea actual */
my_tty = current->tty;
/* Si my_tty es NULL, significa que la actual tarea
* no tiene tty en la que puedas imprimir (esto es posible, por
* ejemplo, si es un demonio). En este caso, no hay nada
* que se pueda hacer. */
if (my_tty != NULL) {
/* my_tty->driver es una estructura que mantiene las funciones
* de tty, una de las cuales (write) es usada para
* escribir cadenas de caracteres a la tty. Puede ser usada
* para coger una cadena de caracteres del segmento de memoria
* del usuario o del segmento de memoria del núcleo.
*
* El primer parámetro de la función es la tty en la que
* hay que escribir, porque la misma función puede
* ser normalmente usada para todas las ttys de un cierto
* tipo. El segundo parámetro controla cuando la función
* recibe una cadena de caracteres de la memoria del núcleo
* (falsa, 0) o desde la memoria del usuario (verdad, distinto
* de cero). El tercer parámetro es un puntero a la cadena
* de caracteres, y el cuarto parámetro es la longitud de la
* cadena de caracteres.
*/
(*(my_tty->driver).write)(
my_tty, /* La misma tty */
0, /* No cogemos la cadena de caracteres de la memoria de usuario */
str, /* Cadena de caracteres */
strlen(str)); /* Longitud */
/* Las ttys fueron originalmente dispositivos hardware, las
* cuales (usualmente) se adherían estrictamente al estándar
* ASCII. De acuerdo con ASCII, para mover una nueva linea
* necesitas dos caracteres, un retorno de carro y un salto
* de linea. En Unix, en cambio, el salto de linea ASCII
* es usado para ambos propósitos - por lo tanto no podemos
* usar \n, porque no tendrá un retorno de carro y la siguiente
* linea empezará en la columna siguiente
* después del paso de linea.
*
* BTW, este es el motivo por el que el formato de un fichero de
* texto es diferente entre Unix y Windows. En CP/M y sus derivados,
* tales como MS-DOS y Windows, el estándar ASCII fue estrictamente
* adherido, y entonces una nueva linea requiere un salto de linea
* y un retorno de carro.
*/
(*(my_tty->driver).write)(
my_tty,
0,
"\015\012",
2);
}
}
/* Inicialización y Limpieza del módulo ****************** */
/* Inicializa el módulo - registra el fichero proc */
int init_module()
{
print_string("Módulo insertado");
return 0;
}
/* Limpieza - libera nuestro fichero de /proc */
void cleanup_module()
{
print_string("Módulo borrado");
}