E/S
Driver Impresora
– Airam Godoy Hernández
– Jose Yeray Suárez Perdomo
1
Entrada/Salida(1)
• Se accede mediante el uso de archivos
•
especiales (/dev).
Este tipo de archivos tienen tres características:
– 1.-El número que identifica al controlados
– 2.-El número que identifica al dispositivo físico
– 3.-Modo de funcionamiento
• Modo bloque
• Modo carácter
2
Entrada/Salida(2)
• Peticiones de acceso manejadas por el
controlador
• Este interactúa con el dispositivo físico
• Primitivas para leer y escribir iguales a las
usadas en archivos regulares
3
Modo bloque
• Corresponden a dispositivos estructurados
• Se accede proporcionando el número de
•
•
•
•
bloque.
Las E/S se realizan mediante la función del
búfer caché.
También puede trabajar en modo carácter.
Implementación más confusa por necesitar
más velocidad.
Ejemplo: El diskette, disco duro,…
4
Modo carácter
• Corresponden a dispositivos no
estructurados
• Pueden ser accedidos como una corriente
de bytes, como un fichero.
• Se leen y escriben los datos byte a byte.
• Se accede de forma secuencial (no
permite retrocesos)
• Son bastantes transparentes
5
Driver de impresora
• Modo carácter
• Puede utilizar dos métodos diferentes para
dialogar con el puerto
– Interrupciones
• Mediante las IRQ
– Exploracion
• Mediante bucles que comprueba el registro de estado de los
puertos
• Permite evitar que se produzcan numerosas interrupciones
6
Estructuras
• Se definen mediante descriptores localizados en
•
•
•
•
la tabla lp_table
El tamaño de lp_table es 8 por defecto
(#define LP_NO 8)
Cada posicion contiene información de la
impresora, mediante lp_struct
(struct lp_struct lp_table[LP_NO];)
Se encuentra definida en lp.h
Especifica el tipo de cada uno de los elementos
7
Struct lp_struct
Tipo
Campo
Descripcion
int
Base
Dirección de la base de los puertos de E/S utilizados
Unsigned int
IRQ
Número de interrucipn utilizada
Int
Flags
Estado de la impresora conectada
Unsigned int
Chars
Número de intentos a efectuar para imprimir un carácter
Unsigned int
Time
Duración de la suspensión para una espera expresada en ciclos de
reloj
Unsigned int
Wait
Número de bucles de espera a efectuar antes de que la impresora
tenga en cuenta un carácter
Struct wait_queue *
Lp_wait_q
Cola de espera utilizada para esperar la llegada de una
interrupción
Char *
Lp_buffer
Puntero a una memoria intermedia que contiene los caracteres a
imprimir
Unsigned int
Lastcall
Fecha de la última escritura en la impresora
Unsigned int
Runchars
Número de caracteres escritos en la impresora sin provocar
suspensión
Unsigned int
Waittime
Campo no utilizado
Struct lp_stats
Stats
Estadísticas sobre el uso de la impresora
8
Struct file_operations
• static struct file_operations lp_fops = {
• lp_lseek,
• NULL,
/* lp_read */
• lp_write,
• NULL,
/* lp_readdir */
• NULL,
/* lp_select */
• lp_ioctl,
• NULL,
/* lp_mmap */
• lp_open,
• lp_release};
9
Funciones de gestión de la
impresora con Spolled
•
La función lp_char_polled
–
–
–
•
Implementa el envio de un carácter
Efectúa un bucle de espera hasta que la impresora esté disponible de
recibir un carácter
Si se envía correctamente devuelve un 1 sino un 0
La función lp_write_polled
–
–
–
–
Implementa el envio de una serie carácter
Efectúa un bucle sobre cada carácter a imprimir
Imprime los caracteres llamando a lp_char_polled
Si se produce un error, el proceso se duerme, y se pone su estado a
TASK_INTERRUPTIBLE.
10
Funciones de gestión de la
impresora con Interrupciones
•
La función lp_char_interrupt
–
–
–
•
Implementa el envio de un carácter
Efectúa un bucle hasta que la impresora esté disponible para recibir un carácter
Si se envía correctamente devuelve un 1 sino un 0
La función lp_interrupt
–
–
–
•
Se llama cuando se produce una interrupción
Efectúa una búsqueda en la tabla lp_table para saber quien produjo la interrupción
Lama a wake_up para despertar el proceso en espera en lp_wait_q
La función lp_write_interrupt
–
–
–
–
Implementa el envio de una serie carácter
Efectúa un bucle sobra cada carácter a imprimir
Imprime los caracteres llamando a lp_char_interrupt
Si se produce un error, el proceso se duerme,se añade a lp_wait_q, y se pone su estado
a TASK_INTERRUPTIBLE.
11
Operaciones de E/S sobre
archivo(I)
• La función lp_write
– implementa la operación sobre el archivo write
– Esta llama a la función correspondiente según el modo
• La función lp_seek
– implementa la operación sobre el archivo lseek
– Devuelve el error ESPIPE
• La función lp_ioctl
– implementa la operación sobre el archivo ioctl
– Permite modificar o consultar los parámetros de la impresora
12
Operaciones de E/S sobre
archivo(II)
• La función lp_open
– implementa la operación sobre el archivo open
– Verifica que la impresora existe y que no es usada por otro
proceso
– Inicializa la impresora
– Marca la impresora como ocupada
• La función lp_release
– implementa la operación sobre el archivo release
– Marca la impresora como desocupada
13
Funciones de inicialización
• La función lp_probe
– Comprueba la presencia de un puerto paralelo
– Inicializa su descriptor
• La función lp_init
– Se llama al inicializarse el sistema, o en la carga del gestor en
forma de módulo
– Registra el gestor ( llamada a register_chrdev) , indicando la
operaciones asociadas al archivo
– Efectúa un bucle de reconocimiento de los puertos posibles
(llamada a lp_probe)
14
Lp_char_polled
• Implementa el envio de un carácter
•
•
static int lp_char_polled(char lpchar, int minor)
{ int status = 0, wait = 0;unsigned long count = 0;
• Efectúa un bucle de espera hasta que la impresora esté
disponible de recibir un carácter
•
•
•
•
do {
status = LP_S(minor);
count ++;
} while(!(status & LP_PBUSY) && count < LP_CHAR(minor));
• Si se envía correctamente devuelve un 1 sino un 0
•
•
•
•
•
•
•
if (count == LP_CHAR(minor)) return 0;
outb_p(lpchar, LP_B(minor));
while(wait != LP_WAIT(minor)) wait++;
outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
while(wait) wait--;
outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
return 1;}
15
Lp_wite_spolled
• Implementa el envio de una serie carácter
•
•
•
static int lp_write_polled(struct inode * inode, struct file * file, char * buf, int count)
{ int retval; unsigned int minor = MINOR(inode->i_rdev); char c, *temp = buf;+
temp = buf;
• Efectúa un bucle sobra cada carácter a imprimir
•
•
•
•
•
while (count > 0) {
c = get_fs_byte(temp);
Imprime los caracteres llamando a lp_char_polled
retval = lp_char_polled(c, minor);
if (retval) { count--; temp++;}
• Si se produce un error, el proceso se duerme, y se pone su
•
•
•
•
•
•
estado a TASK_INTERRUPTIBLE.
if (!retval) {
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + LP_TIME(minor);
schedule();
}
return temp-buf;}
16
Lp_char_interrupt
• Implementa el envio de un carácter
•
•
static int lp_char_interrupt(char lpchar, int minor)
{int wait = 0; unsigned char status;
• Efectúa un bucle, durante el cual, espera que la impresora esté
disponible de recibir un carácter
•
•
•
•
•
•
•
•
•
if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)
|| !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) {
outb_p(lpchar, LP_B(minor));
while(wait != LP_WAIT(minor)) wait++;
while(wait) wait--;
outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
return 1;
}
• Si se envía correctamente devuelve un 1 sino un 0
•
return 0;}
17
Lp_interrupt
• Se llama cuando se produce una interrupción
•
•
•
static void lp_interrupt(int irq)
{ struct lp_struct *lp = &lp_table[0];
struct lp_struct *lp_end = &lp_table[LP_NO];
• Efectúa una búsqueda en la tabla lp_table para saber quien produjo
la interrupción
•
•
•
•
while (irq != lp->irq) {
if (++lp >= lp_end)
return;
}
• Lama a wake_up para despertar el proceso en espera en lp_wait_q
•
•
wake_up(&lp->lp_wait_q);
}
18
Lp_wite_interrupt
• Implementa el envio de una serie carácter
•
•
•
static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
{ unsigned int minor = MINOR(inode->i_rdev); unsigned long copy_size; unsigned long
total_bytes_written = 0;
unsigned long bytes_written; struct lp_struct *lp = &lp_table[minor]; unsigned char status;
• Efectúa un bucle sobra cada carácter a imprimir
•
•
•
•
do { bytes_written = 0;
copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE);
memcpy_fromfs(lp->lp_buffer, buf, copy_size);
while (copy_size) {
• Imprime los caracteres llamando a lp_char_interrupt
•
if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) {--copy_size; ++bytes_written;}
• Si se produce un error, el proceso se duerme,se añade a
•
•
•
•
•
•
•
•
lp_wait_q, y se pone su estado a TASK_INTERRUPTIBLE.
outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor)));
status = LP_S(minor);
current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
interruptible_sleep_on(&lp->lp_wait_q);
outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor)));
total_bytes_written += bytes_written; buf += bytes_written; count -= bytes_written;
} while (count > 0);
return total_bytes_written;}
19
Lp_write y lp_seek
• Implementa la operación sobre el archivo write
•
static int lp_write(struct inode * inode, struct file * file, char * buf, int count)
• Esta llama a la función correspondiente según el modo
if (LP_IRQ(MINOR(inode->i_rdev))) return lp_write_interrupt(inode, file, buf, count);
•
else return lp_write_polled(inode, file, buf, count);}
• Implementa la operación sobre el archivo lseek
•
static int lp_lseek(struct inode * inode, struct file * file,off_t offset, int origin)
• Devuelve el error ESPIPE
• {return -ESPIPE;}
20
Lp_open
•
•
static int lp_open(struct inode * inode, struct file * file)
{ unsigned int minor = MINOR(inode->i_rdev); int ret; unsigned int irq; struct sigaction sa;
•
•
•
if (minor >= LP_NO) return -ENODEV;
if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV;
if (LP_F(minor) & LP_BUSY) return -EBUSY;
• Verifica que la impresora existe y que no es usada por otro proceso
• Inicializa la impresora
•
•
•
•
•
•
•
•
•
•
if ((irq = LP_IRQ(minor))) {
sa.sa_handler = lp_interrupt;
sa.sa_flags = SA_INTERRUPT;
sa.sa_mask = 0;
sa.sa_restorer = NULL;
ret = irqaction(irq, &sa);
if (ret) { kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
lp_table[minor].lp_buffer = NULL;
printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret);
return ret; } }
•
•
LP_F(minor) |= LP_BUSY;
return 0;}
• Marca la impresora como ocupada
21
Lp_release
• Implementa la operación sobre el archivo release
•
•
•
•
static void lp_release(struct inode * inode, struct file * file)
{
unsigned int minor = MINOR(inode->i_rdev);
unsigned int irq;
• Marca la impresora como desocupada
•
•
•
•
•
•
•
if ((irq = LP_IRQ(minor))) {
free_irq(irq);
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
lp_table[minor].lp_buffer = NULL;
}
LP_F(minor) &= ~LP_BUSY;
}
22
Lp_init
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Se llama al inicializarse el sistema, o en la carga del gestor en forma de módulo
long lp_init(long kmem_start)
{ int offset = 0;unsigned int testvalue = 0;int count = 0;
Registra el gestor ( llamada a register_chrdev) , indicando la operaciones asociadas al archivo
if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) {
printk("unable to get major %d for line printer\n", LP_MAJOR);
return kmem_start; }
Efectúa un bucle de reconocimiento de los puertos posibles (llamada a lp_probe)
for (offset = 0; offset < LP_NO; offset++) {
outb_p( LP_DUMMY, LP_B(offset));
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
testvalue = inb_p(LP_B(offset));
if (testvalue != 255) {
LP_F(offset) |= LP_EXIST;
lp_reset(offset);
printk("lp_init: lp%d exists (%d), ", offset, testvalue);
if (LP_IRQ(offset)) printk("using IRQ%d\n", LP_IRQ(offset));
else printk("using polling driver\n");
count++;
}}
if (count == 0) printk("lp_init: no lp devices found\n"); return kmem_start;}
23
Lp_ioctl
• implementa la operación sobre el archivo ioctl
•
•
•
•
static int lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{ unsigned int minor = MINOR(inode->i_rdev);int retval = 0;
if (minor >= LP_NO) return -ENODEV;
if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV;
• Permite modificar o consultar los parámetros de la impresora
•
•
•
•
•
•
•
•
•
switch ( cmd ) {case LPTIME: LP_TIME(minor) = arg; break;
case LPCHAR:LP_CHAR(minor) = arg; break;
case LPABORT: if (arg) LP_F(minor) |= LP_ABORT;
else LP_F(minor) &= ~LP_ABORT; break;
case LPWAIT: LP_WAIT(minor) = arg; break;
case LPGETIRQ: retval = LP_IRQ(minor); break;
default: retval = -EINVAL; }
return retval;
}
24
Descargar

Entrada/Salida