240 likes | 357 Views
E/S Driver Impresora. Airam Godoy Hernández Jose Yeray Suárez Perdomo. 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
E N D
E/SDriver Impresora • Airam Godoy Hernández • Jose Yeray Suárez Perdomo
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
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
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,…
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
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
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
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};
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.
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.
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
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
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)
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;}
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;}
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;}
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); • }
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;}
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;}
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; • Verifica que la impresora existe y que no es usada por otro proceso • if (minor >= LP_NO) return -ENODEV; • if ((LP_F(minor) & LP_EXIST) == 0) return -ENODEV; • if (LP_F(minor) & LP_BUSY) return -EBUSY; • 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;}} • Marca la impresora como ocupada • LP_F(minor) |= LP_BUSY; • return 0;}
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; • }
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;}
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; • }