ioctl
ioctl es una llamada de sistema en Unix que permite a una aplicación controlar o comunicarse con un driver de dispositivo, fuera de los usuales read/write de datos. Esta llamada se originó en la versión 7 del AT&T Unix. Su nombre abrevia la frase input/output control.
Descripción
[editar]Una llamada ioctl toma como parámetros:
- un descriptor de archivos abierto
- un número de código de requerimiento
- también un valor entero, posiblemente sin signo (va al driver), o un puntero a datos (también va al driver y vuelve de él)
El kernel generalmente envía un ioctl directamente al driver, el cual puede interpretar el número de requerimiento y datos en cualquier forma requerida. Los escritores del driver documentan cada número de requerimiento del driver para ese driver particular, y los proveen de constantes en el archivo de cabeceras (*.h)
Algunos sistemas tienen convenciones en su codificación, dentro del número de codificación, el tamaño de los datos a ser transferidos desde o hacia el driver del dispositivo, la dirección de la transferencia de datos y la identidad del driver implementando el requerimiento.
Independientemente de que esa convención se cumpla o no, el kernel y el driver colaboran para entregar un código de error uniforme (señalados por la constante simbólica ENOTTY) a una aplicación que haga un requerimiento al driver que no reconozca.
El nemónico ENOTTY (tradicionalmente asociado con el mensaje textual "Not a typerwriter") viene del hecho de que en los sistemas iniciales que incorporaba una llamada ioctl, solo el dispositivo teletipo (tty) planteaba este error. A través del nemónico simbólico es ajustado por los requerimientos de compatibilidad; algunos sistemas modernos muy útilmente prestan un mensaje más general, como: "Inappropriate device control operation", o la localización del mismo.
TCSETS ejemplifica un ioctl en un puerto serial. Las llamadas de lectura y escritura normales en un puerto serial reciben y envían paquetes de datos. Una llamada ioctl(fd, TCSETS, data), independiente de las llamadas normales I/O, controla varias opciones del controlador, como la manipulación de caracteres especiales, o las señales de salida en el puerto (por ejemplo, la señal DTR).
Ejemplo de uso
[editar]Un ejemplo de uso para ioctl es el manejo de los leds del teclado, KDGKLED, KDSKBLED son las macros definidas para poder acceder a los leds que la mayoría de los teclados tienen.
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <time.h>
#include <unistd.h> /*Encabezado para la función sleep() and close() */
int get_state(int fd,int *estado)
{
if (-1 == ioctl(fd, KDGKBLED, estado)){
/*Si la función ioctl devuelve -1, hubo un error, que será especificado en la función perror(), si es cero significa que finalizo exitosamente*/
perror("ioctl");
close(fd);
return -1;
}
return 0;
}
void print_caps_lock_state(int estado)
{
printf("Estado Caps Lock: %s (%d)\n",
(estado & K_CAPSLOCK) == K_CAPSLOCK ? "on" : "off", estado);
}
int apaga(int fd,int *estado)
{
get_state(fd,estado);
if (-1 == ioctl(fd, KDSKBLED, *estado ^ K_CAPSLOCK)){
perror("ioctl set");
close(fd);
return -1;
}
return 0;
}
int prende(int fd,int *estado)
{
if (-1 == ioctl(fd, KDSKBLED, K_CAPSLOCK)){
perror("ioctl set");
close(fd);
return -1;
}
get_state(fd,estado);
return 0;
}
int main()
{
int fd = open("/dev/tty0", O_NOCTTY);
if (fd == -1){
perror("open");
return -1;
}
int estado = 0;
prende(fd,&estado);
sleep(1);
apaga(fd,&estado);
sleep(2);
prende(fd,&estado);
sleep(1);
apaga(fd,&estado);
close(fd);
return 0;
}