De cara al examen de la asignatura, solo entran las tres primeras secciones (hasta la transparencia 63, incluida).
d->cilindro = 7; d->cabeza = 2; d->sector = 16; d->dir=10000; d->nsect=1; d->tipo = OP_LECTURA; d->control = INICIO_OPER;
unsigned int volatile *p = (unsigned int volatile *) 0X88888888; *p = 1;
dispo[ndisp++]=kmalloc(struct info_dispo, GFP_KERNEL); dispo[ndisp]->registros = ioremap(X, 16);Para desarrollar un código más legible, sería conveniente crear una estructura de datos que refleje la disposición de los registros de E/S del dispositivo y hacer que el campo que recoge la dirección lógica sea un puntero de ese tipo, tal como se muestra a continuación:
struct regs { uint32_t dir; uint32_t tam; uint32_t ctrl; uint32_t est; }; // NOTA: __iomem es una anotación para marcar que un puntero // se usa para accesos de E/S. Usado por herramientas de // verificación del código. struct info_dispo { ..................... struct regs __iomem *registros; void *buffer; // para el DMA: véase más adelante wait_queue_head_t cola; // véase más adelante volatile sigatomic_t hecho; // véase más adelante ..................... }; // vector con la información de los dispositivos struct info_dispo *dispo;En cuanto a las interrupciones, el manejador instalará (request_irq) en el vector de interrupciones correspondiente a esa IRQ su función de manejo de la misma.
// devuelve dirección lógica Z dispo[ndisp]->buffer=kmalloc(TAM,GFP_KERNEL);Para la programación de la operación de DMA, hay que tener en cuenta los siguientes aspectos:
dispo[ndisp]->registros->dir = virtual_to_physical(dispo[ndisp]->buffer); dispo[ndisp]->registros->tam = TAM; wmb(); // barrera de compilador + barrera de memoria de escritura dispo[ndisp]->registros->ctrl = 0; // arranca una lectura // la rut. interrupción despertará cuando termine el DMA wait_event_interruptible(dispo[ndisp]->cola, dispo[ndisp]->hecho); // función hipotética que invalida las posibles entradas en la // cache que correspondan a ese rango de direcciones lógicas invalidate_cache_range(dispo[ndisp]->buffer, TAM); // copia del buffer interno al del usuario copy_to_user(Y, dispo[ndisp]->buffer, TAM);Nótese que en ese seudo-codigo se usan directamente punteros para acceder a los registros del dispositivo. Esa técnica no está recomendada en Linux aconsejándose usar las macros correspondientes. A continuación, se muestra cómo se realizaría una de las asignaciones previas usando una de estas macros:
dispo[ndisp]->registros->tam = TAM; iowrite32(TAM, dispo[ndisp]->registros->tam);