 David Sánchez Rodríguez Programación en Ingeniería Electrónica Tema 3: Acceso a dispositivos periféricos.

1  David Sánchez Rodríguez Programación en Ingeniería El...
Author: Fernando Domínguez Parra
0 downloads 0 Views

1  David Sánchez Rodríguez Programación en Ingeniería Electrónica Tema 3: Acceso a dispositivos periféricos

2 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 2 Índice 1.Introducción 2.Drivers (módulos) en Linux - Dispostivos de caracteres 3.Drivers en Windows

3 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 3 INTRODUCCIÓN S.O. Uso cómodo del sistema y eficiente del hardware

4 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 4 INTRODUCCIÓN Hardware Sistema operativo Programas

5 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 5 INTRODUCCIÓN Sistema Unix

6 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 6 INTRODUCCIÓN Sistema Unix

7 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 7 INTRODUCCIÓN Sistema Windows

8 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 8 INTRODUCCIÓN  User space –Aplicaciones que utiliza el usuario (shell, ping…) –Interaccionan con el hardware, a través de funciones que soporta el kernel –Ejecución sin privilegios de procesador –User-mode drivers en Windows utilizan Win32 API  Kernel space –El kernel gestiona los recursos hardware del computador –Interfase entre las aplicaciones de usuario y el hardware –Módulos o drivers están dentro del espacio del kernel –Kernel-mode driver puede acceder a estructuras que un user- mode drivers no puede acceder

9 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 9 INTRODUCCIÓN Estructura básica de un driver  Punto de entrada –Carga del driver (inicializa estructuras, asocia rutinas a las operaciones en dispositivos y se prepara para futuras invocaciones de las funciones) Windows:DriverEntry (…) //Reiniciar sistema Linux:init_module() ó module_init (rutina de inicio) –Descarga del driver (libera recursos) Linux:cleanup_module() ó module_exit (rutina de salida)  Rutinas para el manejo del dispositivo –Abrir, cerrar, lectura, escritura,…

10 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 10 INTRODUCCIÓN  Programación –De forma general se utiliza el lenguaje C (punteros, manejo bits,…) –Sistemas Windows C para kernel-mode drivers C ó C++ para user-mode drivers Excepciones: –Audio/Video streaming client minidrivers en C++ –WDM audio miniport drivers en C++ –Windows Image Acquisition drivers en C++  Nociones de microprocesadores –Direccionamiento de memoria –Interrupciones Requisitos previos

11 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 11 INTRODUCCIÓN Bibliografía  Linux –Linux Device Driver (2 nd Edition), Alessandro Rubini, Jonathan Cobert. Ed. O’Reilly (hasta kernel 2.4) ftp://ftp.ora.com/pub/examples/linux/drivers2/book_pdf.rar http://examples.oreilly.com/linuxdrive2/ldd2-samples-1.0.1.tar.gz Linux Device Driver (3 rd Edition)(kernel 2.6) Disponible online en http://lwn.net/Kernel/LDD3/  Windows –Microsoft Windows Driver Development Kit (DDK) http://www.microsoft.com/whdc/devtools/ddk/default.mspx

12 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 12 DRIVERS EN LINUX  Linux permite extender las funcionalidades del kernel en tiempo de ejecución  Cada funcionalidad (código) añadido al kernel (runtime) se denomina módulo  Un módulo, entre otros, puede ser un driver de dispositivo  Los módulos pueden ser cargados y descargados dinámicamente en el kernel: –Cargar:insmod nombre_del_modulo –Descargar:rmmod nombre_del_modulo –Ver módulos:lsmod

13 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 13 DRIVERS EN LINUX  Character devices: –Dispositivo que puede ser accedido como un stream de bytes (consola, teclado, puerto serie) (normalmente un carácter) –Se acceden a través del sistema de ficheros como: /dev/tty1, /dev/lp0 –Implementan las llamadas al sistema: open, close, read y write  Block devices: –Se acceden a través del sistema de ficheros: directorio /dev –Un dispositivo de bloque es aquel que puede almacenar un sistema de fichero: disco –Sólo puede ser accedido como múltiplo de un bloque (1 Kb, 2Kb,…) –Utiliza llamadas al sistema como char-devices Tipos de dispositivos

14 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 14 DRIVERS EN LINUX  Network interfaces: –Dispositivo que intercambia datos con otros hosts –No se utiliza el sistema de ficheros –Utiliza un nombre único (eth0) –Comunicación entre kernel y driver es diferente que las usadas con “char y block drivers” –Utiliza funciones relacionadas con la transmisión de paquetes  Otros dispositivos: –SCSI drivers –FireWire and USB drivers, Tipos de dispositivos

15 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 15 DRIVERS EN LINUX #define __KERNEL__// necesario para construir módulos dinámicos #define MODULE #include int init_module(void) { printk(" Hola\n");// printk está definida en el kernel // indica la prioridad (alta) del mensaje return 0; } void cleanup_module(void) { printk(" Bye\n"); } Primer driver

16 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 16 DRIVERS EN LINUX Primer driver

17 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 17 DRIVERS EN LINUX Contador de uso del módulo  Existe un contador por cada módulo  Un módulo no puede ser descargado si está ocupado  Kernels actuales gestionan el contador automáticamente  Puede ser necesario gestionarlo manualmente (kernel 2.4)  Hay tres macros definidas en : –MOD_INC_USE_COUNT Incrementa el contador del actual módulo –MOD_DEC_USE_COUNT Decrementa el contador –MOD_IN_USE Evalúa si el contador es cero

18 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 18 DRIVERS EN LINUX Contador de uso del módulo  El valor del contador viene dado en el tercer campo de cada entrada en /proc/modules  Los campos son: nombre, bytes usados en memoria y contador nls_iso8859-1 35161 nls_cp437 5148 1 vfat 13100 1 mousedev 5588 1 keybdev 2976 0 hid 22340 0 input 5920 0

19 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 19 DRIVERS EN LINUX Utilizando recursos  Los drivers utilizan los recursos del sistema: –Memoria, I/O ports, I/O memory (memoria del dispositivo),…  Reservar memoria –void * kmalloc (unsigned int size, int priority) GFP_KERNEL como prioridad  Liberar memoria –void kfree (void *obj)

20 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 20 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  /proc/ioports: Muestra una lista de las regiones de puertos registrados actualmente utilizados para la comunicación de entrada y salida con un dispositivo. 0000-001f : dma1 0020-003f : pic1 0040-005f : timer 0060-006f : keyboard 0070-007f : rtc 0080-008f : dma page reg 0170-0177 : ide1 01f0-01f7 : ide0 02f8-02ff : serial(auto) 0376-0376 : ide1 La primera columna indica el rango de direcciones de los puertos de entrada y salida reservado para el dispositivo listado en la segunda columna

21 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 21 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  I/O ports: –Evitar usar puertos utilizados por otros drivers –Tres funciones para gestionar los puertos: int check_region (unsigned long start, unsigned long len) –Verifica si el rango indicado está reservado –Valores negativos (-EBUSY o -EINVAL) son devueltos si está ocupado struct resource * request_region (unsigned long from, unsigned long extent, const char *name) –Realiza la asignación –Éxito: devuelve un puntero non-NULL void release_region (unsigned long from, unsigned long extend) –Libera la región

22 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 22 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  I/O ports: (reserva del puerto parelelo) En init_module port = check_region (0x378,1); if (port) { printk(“ puertopar: No puedo reservar 0x378\n”); cleanup_module(); return port; } request_region (0x378, 1, “puertopar”); En cleanup_module if (!port) release_region (0x378,1);

23 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 23 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  /proc/iomem: Muestra el mapa actual de la memoria del sistema para los diversos dispositivos 00000000-0009fbff : System RAM 0009fc00-0009ffff : reserved 000a0000-000bffff : Video RAM area 000c0000-000c7fff : Video ROM 000f0000-000fffff : System ROM 00100000-07ffffff : System RAM 00100000-00291ba8 : Kernel code 00291ba9-002e09cb : Kernel data e0000000-e3ffffff : VIA Technologies, Inc. VT82C597 [Apollo VP3] La primera columna muestra los registros de memoria utilizados por cada uno de los diferentes tipos de memoria.

24 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 24 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  I/O memory: –Tres funciones para gestionar la memoria: int check_mem_region (unsigned long start, unsigned long len) –Verifica si el rango indicado está reservado –Valores negativos (-EBUSY o -EINVAL) son devueltos si está ocupado struct resource * request_mem_region (unsigned long start, unsigned long extend, const char *name) –Realiza la asignación –Éxito: devuelve un puntero non-NULL int release_mem_region (unsigned long start, unsigned long extend) –Libera la región

25 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 25 DRIVERS EN LINUX Utilizando recursos: I/O ports & I/O memory  I/O memory: (reserva de espacio de memoria) if (check_mem_region (mem_addr, mem_size)) { printk(“ drivername: memoria usada\n”); return -EBUSY; } request_mem_region (mem_addr,mem_size, “drivername”);

26 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 26 DRIVERS EN LINUX struct resource  Los rangos de los recursos utilizados son almacenados en una estructura del tipo resource  struct resource { const char *name; unsigned long start, end; unsigned long flags; struct resource *parent, *sibling, *child }; e800-e8ff:Adaptec AHA-2940U2/W / 7890 (PCI bus driver) e800-e8be:aic7xxx(driver, real ports on card)

27 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 27 DRIVERS EN LINUX MACROS de Configuración: Asignando datos at load time  Dependiendo del sistema, algunos parámetros de un driver pueden cambiar (I/O address, …) –Ej: insmod mydriver param1=123 param2=“texto” –param1 y param2 son parámetros de tipo entero y cadena, respectivamente –Tienen que estar definidos en el módulo –Macro MODULE_PARM (nombre_parametro,”tipo”); – –Tipo  “b”: 1 byte, “h”: 2 bytes, “i”: entero, “l”: long, “s”: string –Las macros deben estar colocadas fuera de cualquier función int param1=10; char param2[10]=“hola”; MODULE_PARM (param1, “i”); MODULE_PARM (param2, “s”);

28 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 28 DRIVERS EN LINUX MACROS de Configuración: Información adicional  MODULE_AUTHOR (name) –Nombre de autor  MODULE_DESCRIPTION (desc) –Descripción del módulo  MODULE_SUPPORTED_DEVICE (dev) –Dispositivo soportado por el módulo

29 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 29 Drivers LINUX: Dispositivos de Caracteres  Se acceden a través del sistema de ficheros  Normalmente localizados en /dev  Identificados con una “c” en la primera columna de un “ls –l” crw-rw---- 1 root root 10, 62 2007-05-24 10:21 acpi crw-rw---- 1 root audio 14, 12 2007-05-24 10:20 adsp crw-rw---- 1 root video 10, 175 2007-05-24 10:20 agpgart crw-rw---- 1 root audio 14, 4 2007-05-24 10:20 audio crw------- 1 root root 5, 1 2007-05-24 10:22 console brw-rw---- 1 root disk 3, 0 2007-05-24 11:19 hda brw-rw---- 1 root disk 3, 1 2007-05-24 11:19 hda1 brw-rw---- 1 root disk 3, 2 2007-05-24 11:19 hda2 crw-rw-rw- 1 root root 5, 0 2007-05-24 11:20 tty crw-rw---- 1 root root 4, 0 2007-05-24 11:20 tty0 crw------- 1 root root 4, 1 2007-05-24 10:22 tty1 crw-rw---- 1 root root 4, 10 2007-05-24 11:19 tty10

30 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 30 Drivers LINUX: Dispositivos de Caracteres  Major number –Identifican el driver asociado con el dispositivo –El kernel utiliza el “major number” para ejecutar el driver apropiado  Minor number –Un driver puede controlar varios dispositivos –Utilizado para diferenciar entre diferentes dispositivos Major and minor numbers

31 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 31 Drivers LINUX: Dispositivos de Caracteres  Asignar un major number a cada driver  Se realiza en la inicialización con la función: –int register_chrdev (unsigned int major, const char *name, struct file_operations *fops); major: major number solicitado name: nombre del dispositivo que aparecerá en /proc/devices fops: puntero a un vector de punteros a funciones se especifica las funciones que realizan las operaciones del driver Valores devueltos:0  Éxito en el registro negativo  Fallo Major and minor numbers

32 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 32 Drivers LINUX: Dispositivos de Caracteres  Kernel 2.4: major and minor numbers son de 8 bits (hasta 256 dispositivos)  Kernel 2.6: agrupado en dato de (32bits): Major (12 bits) minor (20 bits)  Asignación dinámica:major = 0 register_chrdev retorna el número  Major number reservados para uso local: 60-63, 120-127, 240-254  Crear un dispositivo (root) –Permanece hasta que sea eliminado –mknod /dev/midispositivo c 200 0  Eliminar dispositivo - rm /dev/midispositivo Major and minor numbers

33 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 33 Drivers LINUX: Dispositivos de Caracteres  Eliminar el driver del sistema int unregister_chrdev (unsigned int major, const char *name) -EINVAL es retornado si: el nombre no coincide con los registrados si major está fuera de rango Major and minor numbers

34 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 34 Drivers LINUX: Dispositivos de Caracteres  El kernel la utiliza para acceder a las funciones del driver  Argumento en la función register_chrdev(…)  Todas las funciones devuelven 0 en caso de éxito, o un valor negativo en caso de error  El vector dispone de 15 entradas  Aquellas que no son inicializadas con una función, automáticamente se inicializan a NULL file_operations structure

35 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 35 Drivers LINUX: Dispositivos de Caracteres  loff_t (*llseek) (struct file *, loff_t, int); –The llseek method is used to change the current read/write position in a file, and the new position is returned as a (positive) return value. The loff_t is a “long offset” and is at least 64 bits wide even on 32-bit platforms.  ssize_t (*read) (struct file *, char *, size_t, loff_t *); –Used to retrieve data from the device. A null pointer in this position causes the read system call to fail with -EINVAL (“Invalid argument”). A non-negative return value represents the number of bytes successfully read (the return value is a “signed size” type, usually the native integer type for the target platform).  ssize_t (*write) (struct file *, const char *, size_t,loff_t *); –Sends data to the device. If missing, -EINVAL is returned to the program calling the write system call. The return value, if non-negative, represents thenumber of bytes successfully written. file_operations structure

36 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 36 Drivers LINUX: Dispositivos de Caracteres  int (*open) (struct inode *, struct file *); –Though this is always the first operation performed on the device file, the driver is not required to declare a corresponding method. If this entry is NULL, opening the device always succeeds, but your driver isn’t notified. Debe incrementarse el contador  int (*flush) (struct file *); –The flush operation is invoked when a process closes its copy of a file descriptor for a device; it should execute (and wait for) any outstanding operations on the device. Currently, flush is used only in the network file system (NFS) code. If flush is NULL, it is simply not invoked.  int (*release) (struct inode *, struct file *); –This operation is invoked when the file structure is being released. Like open, release can be missing. Debe decrementarse el contador file_operations structure

37 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 37 Drivers LINUX: Dispositivos de Caracteres  int (*lock) (struct file *, int, struct file_lock *); –The lock method is used to implement file locking; locking is an indispensable feature for regular files, but is almost never implemented by device drivers.  ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);  ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); –These methods implement scatter/gather read and write operations. Applications occasionally need to do a single read or write operation involving multiple memory areas; these system calls allow them to do so without forcing extra copy operations on the data.  struct module *owner; –This field isn’t a method. Instead, it is a pointer to the module that “owns” this structure; it is usedby the kernel to maintain the module’s usage count. file_operations structure

38 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 38 Drivers LINUX: Dispositivos de Caracteres struct file_operations midriver_fops={ read: mifuncion_read, write: mifuncion_write, open: mifuncion_open, release: mifuncion_release, }; file_operations structure

39 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 39 Drivers LINUX: Dispositivos de Caracteres int puerto_release (struct inode *inode, struct file *filp) { … } ssize_t puerto_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) { … } ssize_t puerto_write (struct file *filp, char *buf, size_t count, loff_t *f_pos) { … } file_operations structure

40 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 40 Drivers LINUX: Dispositivos de Caracteres file structure  Representa un fichero abierto en el kernel-space  Se comunica a cualquier función que opera con el fichero  Cuando se cierra el fichero, el kernel libera la estructura  Campos importantes  mode_t f_mode; The file mode identifies the file as either readable or writable (or both), by means of the bits FMODE_READ and FMODE_WRITE. You don’t need to check permissions for read and write because the kernel checks before invoking your method.

41 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 41 Drivers LINUX: Dispositivos de Caracteres file structure  loff_t f_pos; The current reading or writing position. loff_t is a 64-bit value (long long in gcc ter minology). The driver can read this value if it needs to know the current position in the file, but should never change it.  unsigned int f_flags; These are the file flags, such as O_RDONLY, O_NONBLOCK, and O_SYNC. A driver needs to check the flag for nonblocking operation, while the other flags are seldom used. In particular, read/write permission should be checked using f_mode instead of f_flags. All the flags are defined in the header.

42 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 42 Drivers LINUX: Dispositivos de Caracteres file structure  struct file_operations *f_op; The operations associated with the file. The kernel assigns the pointer as part of its implementation of open, and then reads it when it needs to dispatch any operations.  void *private_data; The open system call sets this pointer to NULL before calling the open method for the driver. The driver is free to make its own use of the field or to ignore it. The driver can use the field to point to allocated data, but then must free memory in the release method before the file structure is destroyed by the Kernel  struct dentry *f_dentry; The directory entry (dentry) structure associated with the file.

43 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 43 Drivers LINUX: Dispositivos de Caracteres Copiando a/desde el espacio de usuario  Necesario copiar datos al/desde el espacio de usuario (read/write)  Funciones del kernel: – unsigned long copy_to_user (void *to, const void *from, unsigned long count); //Read function – unsigned long copy_from_user(void *to, const void *from, unsigned long count); //Write function

44 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 44 Drivers LINUX: Dispositivos de Caracteres Funciones para acceder a I/O ports  unsigned inb(unsigned port);  void outb(unsigned char byte, unsigned port); Read or write byte ports (eight bits wide). The port argument is defined as unsigned long for some platforms and unsigned short for others. The return type of inb is also differ ent across architectures.  unsigned inw(unsigned port);  void outw(unsigned short word, unsigned port); These functions access 16-bit ports (word wide); they are not available when compiling for the M68k and S390 platforms, which support only byte I/O.

45 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 45 Drivers LINUX: Dispositivos de Caracteres Funciones para acceder a I/O ports  unsigned inl(unsigned port);  void outl(unsigned longword, unsigned port); These functions access 32-bit ports. longword is either declared as unsigned long or unsigned int, according to the platform. Like word I/O, ‘‘long’’ I/O is not available on M68k and S390.

46 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 46 Drivers LINUX: Dispositivos de Caracteres Funciones para acceder a I/O ports The prototypes for string functions are the following:  void insb(unsigned port, void *addr, unsigned long count);  void outsb(unsigned port, void *addr, unsigned long count); Read or write count bytes starting at the memory address addr. Data is read fr om or written to the single port port.  void insw(unsigned port, void *addr, unsigned long count);  void outsw(unsigned port, void *addr, unsigned long count); Read or write 16-bit values to a single 16-bit port.  void insl(unsigned port, void *addr, unsigned long count);  void outsl(unsigned port, void *addr, unsigned long count); Read or write 32-bit values to a single 32-bit port.

47 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 47 Drivers en Windows  IRP (I/O Request Packets) – Es la estructura básica utilizada para comunicar con los drivers – Cada transacción de E/S viene descrita por una orden de trabajo (IRP) que le indica al driver lo que debe hacer. – La estructura consta de dos partes: Cabecera. Se almacena información sobre la petición, tales como parámetros, dirección del objeto device Entrada en la pila de E/S. Cada entrada contiene los parámetros y el código de las funciones a ejecutar en la petición de E/S CONCEPTOS

48 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 48 Drivers en Windows  Objeto Driver – Por cada driver instalado y cargado, se crea un objeto driver – Almacena los punteros a las rutinas que implementa el driver (en la rutina DriverEntry) – Cuando se realiza una operación sobre dispositivo, se busca en el objeto la rutina a implementar CONCEPTOS

49 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 49 Drivers en Windows  Objeto Device – Almacenan información acerca de las características y estado del dispositivo – Un objeto por cada dispositivo – La rutina DeviceEntry se encarga de crear el objeto –Almacena un puntero al objeto Driver CONCEPTOS

50 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 50 Drivers en Windows Rutinas standards

51 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 51 Drivers en Windows Tareas de la rutina DriverEntry:  Invocar IoCreateDevice para crear el objeto Device  Dar a conocer el dispositivo al sistema llamando a IoCreateSymbolicLink  Inicializar objeto Device con punteros a otras entradas del driver  Repetir los pasos para todos los controladores y dispositivos que pertenecen al driver  Retornar STATUS_SUCCESS

52 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 52 Drivers en Windows Ejemplo #include #define NativeDriverName L"\\Device\\MyDriver" #define DosDriverName L"\\DosDevices\\MyDriver" // I/O Manager calls this routine to unload the device driver VOID MyUnload (IN PDRIVER_OBJECT pDriverObject) { UNICODE_STRING DeviceLinkUnicodeString; NTSTATUS status; // "IoDeleteSymbolicLink" removes a symbolic link RtlInitUnicodeString (&DeviceLinkUnicodeString, DosDriverName); status = IoDeleteSymbolicLink (&DeviceLinkUnicodeString); // "IoDeleteDevice" removes a device object if (NT_SUCCESS(status)) IoDeleteDevice(pDriverObject->DeviceObject); } // End of DriverUnload

53 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 53 Drivers en Windows Ejemplo // Handles "CreateFile" Win32 call from user program NTSTATUS MyCreate (IN PDEVICE_OBJECT pDriverObject, IN PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; // no bytes xfered IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } //End of MyCreate // Handles "CloseHandle" Win32 call from user program NTSTATUS MyClose (IN PDEVICE_OBJECT pDriverObject, IN PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; // no bytes xfered IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } //End of MyClose

54 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 54 Drivers en Windows Ejemplo // Handles "ReadFile" Win32 call from user program NTSTATUS MyRead (IN PDEVICE_OBJECT pDriverObject, IN PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; //no bytes xfered IoCompleteRequest(pIrp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } // End of MyRead // Handles "WriteFile" Win32 call from user program NTSTATUS MyWrite (IN PDEVICE_OBJECT pDriverObject, IN PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; //no bytes xfered IoCompleteRequest(pIrp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } //End of MyWrite

55 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 55 Drivers en Windows Ejemplo // Handles "DeviceIoControl" Win32 call from user program NTSTATUS MyDeviceControl (IN PDEVICE_OBJECT pDriverObject, IN PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; //no bytes xfered IoCompleteRequest(pIrp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } //End of MyDeviceControl // DriverEntry routine. NTSTATUS DriverEntry (IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath) { PDEVICE_OBJECT pDeviceObject = NULL; UNICODE_STRING DeviceNameUnicodeString; UNICODE_STRING DeviceLinkUnicodeString; NTSTATUS status;

56 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 56 Drivers en Windows Ejemplo // "IoCreateDevice" allocates memory for and initializes a device obj status = IoCreateDevice(pDriverObject, 0,&DeviceNameUnicodeString, FILE_DEVICE_UNKNOWN,0, FALSE,&pDeviceObject); if (!NT_SUCCESS(status)) return status; // "IoCreateSymbolicLink" sets up a symbolic link status = IoCreateSymbolicLink (&DeviceLinkUnicodeString, &DeviceNameUnicodeString); if (!NT_SUCCESS(status)) { IoDeleteDevice(pDeviceObject); return status; }

57 Programación en Ingeniería Electrónica  David Sánchez Rodríguez 57 Drivers en Windows Ejemplo //-------------------------------------------------------------- // Fill Dispatch routine entry points pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDeviceControl; pDriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreate; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = MyClose; pDriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite; pDriverObject->MajorFunction[IRP_MJ_READ] = MyRead; pDriverObject->DriverUnload = MyUnload; return STATUS_SUCCESS; } // End of DriverEntry