Red de conocimiento informático - Conocimiento informático - ¿De qué partes consta una macro?

¿De qué partes consta una macro?

1. Escriba las funciones de apertura y escritura

2. Dígaselo al kernel

1) Defina una estructura struct file_operations y rellénela

static struct file_operations first_drv_fops = {

.owner = THIS_MODULE, /* Esta es una macro que empuja la variable __this_module creada automáticamente al compilar el módulo*/

.open = first_drv_open ,

.write = first_drv_write,

};

2), le dice al kernel la estructura struct file_operations

major = Register_chrdev( 0, "first_drv", &first_drv_fops); //Registrarse, informar al kernel

Parámetros relacionados: primero, número de dispositivo, 0 asigna automáticamente el número de dispositivo principal; de lo contrario, el número de dispositivo principal es 0-255

Segundo: nombre del dispositivo

Segundo: estructura struct file_operatives

4) Quién llama a Register_chrdev (llamada a función de entrada)

static int first_drv_init(void )

5), la función de entrada debe modificarse con macros del kernel

module_init(first_drv_init);

module_init definirá una estructura, hay un puntero de función en esta estructura apunta a la función first_drv_init Cuando cargamos o instalamos un controlador, el kernel encontrará automáticamente esta estructura y luego llamará al puntero de función interna. Este puntero de función apunta a la función first_drv_init. estructura file_operations

6). Si hay una función de entrada, habrá una función de salida

module_exit(first_drv_exit);

Finalmente agregue el protocolo

6). p >

MODULE_LICENSE("GPL");

3. mdev crea automáticamente nodos de dispositivo basados ​​en la información del sistema:

Es demasiado problemático crear manualmente archivos de dispositivo cada vez que se escribir un controlador. Usar el sistema de archivos de administración del dispositivo es mucho más conveniente. Devfs se ha utilizado antes del kernel 2.6, pero tiene muchos defectos. Crea una gran cantidad de archivos de dispositivo que en realidad no existen. Además, la asignación entre dispositivos y archivos de dispositivos es incierta. Por ejemplo, un disco U puede corresponder a sda o sdb. No hay suficientes números de dispositivos primarios/secundarios. El kernel posterior a 2.6 introdujo el sistema de archivos sysfs, que se monta en /sys. Cuando se usa con udev, puede completar las funciones de devfs y compensar esas deficiencias. (Permítanme mencionar aquí que el kernel actual ya usa netlink).

udev es una aplicación en el espacio del usuario. En las aplicaciones integradas, se usa mdev y mdev está en ocupado. mdev es una versión simplificada de udev.

Primero agregue la opción para admitir mdev en Busybox:

Utilidades del sistema Linux --->

[*] mdev

[ *] Soporte /etc/mdev.conf

[*] Soporte de subdirectorios/enlaces simbólicos

[*] Soporte de sustituciones de expresiones regulares al cambiar el nombre del dispositivo

[*] Admite la ejecución de comandos al agregar o eliminar dispositivos

Luego modifique /etc/init.d/rcS:

echo /sbin/mdev > /proc/sys/kernel/hotplug

/sbin/mdev -s

Ejecute mdev -s: use '-s' como parámetro para llamar a mdev escrito en el directorio /sbin (en realidad es un enlace, la función es pasar parámetros al directorio /bin del programa Busybox y llámelo), mdev escanea todos los directorios de dispositivos de clase en /sys/class y /sys/block. Si hay un archivo llamado dev en el directorio y el archivo contiene el número de dispositivo, entonces mdev utiliza esta información para crear un archivo de nodo de dispositivo en /dev para este dispositivo. Generalmente, mdev -s se ejecuta solo una vez al inicio.

Evento de conexión en caliente: dado que el comando se ejecuta al inicio: echo /sbin/mdev > /proc/sys/kernel/hotplug, cuando ocurre un evento de conexión en caliente, el kernel llamará al /mdev del directorio sbin. En este momento, mdev usa ACTION y DEVPATH en las variables de entorno para determinar la acción del evento de conexión en caliente y qué directorio en /sys se ve afectado.

Luego verificará si hay un archivo de atributos dev en este directorio. Si lo hay, use esta información para crear un archivo de nodo de dispositivo para este dispositivo en /dev

Vuelva a empaquetar el sistema de archivos, de modo que /. directorio sys, / Hay algo en el directorio dev

El siguiente es el prototipo de create_class:

#define class_create(propietario, nombre) /

( { /

estructura estática lock_class_key __key; /

__class_create(propietario, nombre, &__key); /

})

estructura externa; class * __must_check __class_create(struct module *owner,

const char *name,

struct lock_class_key *key);

El prototipo de class_destroy es el siguiente:

extern void class_destroy (struct class *cls);

El prototipo de device_create es el siguiente:

extern struct device *device_create(struct class *cls, dispositivo de estructura *parent,

dev_t devt, void *drvdata,

const char *fmt, ...)

__attribute__((format(printf, 5 , 6)));

El prototipo de device_destroy es el siguiente:

extern void device_destroy(struct class *cls, dev_t devt); El uso es el siguiente, consulte los siguientes ejemplos:

static struct class *firstdrv_class;

static struct class_device *firstdrv_class_dev;

firstdrv_class = class_create(THIS_MODULE , "firstdrv");

firstdrv_class_dev = class_device_create(firstdrv_class, NULL , MKDEV(principal, 0), NULL, "xyz"); /* /dev/xyz */

class_device_unregister(firstdrv_class_dev);

class_destroy(firstdrv_class);

Echemos un vistazo a cómo la aplicación encuentra esta estructura

En la aplicación usamos open para abrir un dispositivo: como por ejemplo: open(/dev/xxx, O_RDWR);

xxx tiene un atributo, como el carácter del dispositivo es c, seguido de permisos de lectura y escritura, así como el nombre del dispositivo principal. y nombre del dispositivo secundario Usamos Register_c al registrarnos.

hrdev(0, "first_drv", &first_drv_fops) (con número de dispositivo principal, nombre de dispositivo, estructura struct file_operatives) registra la estructura first_drv_fops en la matriz del kernel chrdev. Hay funciones de apertura y escritura en la estructura, entonces, ¿qué pasa con la aplicación? La forma en que lo descubrimos fue encontrar los first_drv_fops que registramos en la matriz del kernel chrdev según el tipo de dispositivo y el número de dispositivo principal en las propiedades del archivo abierto.

Código de ejemplo:

#incluir

#incluir

#incluir

#incluir

#incluir

#incluir

#include

#include

#include

#include

clase de estructura estática *firstdrv_class;

estructura estática class_device *firstdrv_class_dev;

volatile unsigned long *gpfcon = NULL;

volatile unsigned long *gpfdat = NULL;

static int first_drv_open ( struct inode *inode, struct file *file)

{

//printk("first_drv_open\n");

/* Configurar GPF4,5 , 6 es la salida*/

*gpfcon &= ~((0x3<<(4*2)) | (0x3<<(5*2)) | (0x3<<(6*2) ) );

*gpfcon |= ((0x1<<(4*2)) | (0x1<<(5*2)) | (0x1<<(6*2)));< / p>

devuelve 0;

}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)

{

int val;

//printk("first_drv_write\n");

copy_from_user(&val, buf, count); copy_to_user ();

if (val == 1)

{

//Ilumina

*gpfdat &= ~( (1 <<4) | (1<<5) | (1<<6));

}

más

{

// Apaga la luz

*gpfdat |= (1<<4) (1<<5) | (1<<6);

}

devuelve 0;

}

estructura estática file_operaciones first_drv_fops = {

.owner = THIS_MODULE, /* Esta es una macro que enviado al módulo compilado creado automáticamente_

_this_module variable*/

.open = first_drv_open,

.write = first_drv_write,

};

int major;

static int first_drv_init(void)

{

major = Register_chrdev(0, "first_drv", &first_drv_fops // Registrarse, informar al kernel

<); p > firstdrv_class = class_create(THIS_MODULE, "firstdrv");

firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(principal, 0), NULL, "xyz" /* /dev/xyz */

gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);

gpfdat = gpfcon + 1;

devuelve 0;

}

static void first_drv_exit(void)

{

unregister_chrdev(major, "first_drv"); // Desinstalar

class_device_unregister (firstdrv_class_dev);

class_destroy(firstdrv_class);

iounmap(gpfcon);

}

module_init(first_drv_init);

p>

module_exit(first_drv_exit);

MODULE_LICENSE("GPL");

Makefile para compilación

KERN_DIR = /work/system /linux -2.6.22.6

todos:

make -C $(KERN_DIR) M=`pwd` módulos

limpio:

hacer -C $(KERN_DIR) M=`pwd` módulos limpios

rm -rf module.order

obj-m += first_drv.o

Programa de prueba:

#include

#include

#include

#include

/* firstdrvtest en

p>

* firstdrvtest off

*/

int main(int argc, char **argv)

{

int fd;

int val = 1;

fd = open("/dev/xyz", O_RDWR);

if (fd < 0)

{

printf("¡no se puede abrir!\n");

}

if (argc ! = 2)

{

printf("Uso:\n");

printf("%s \n", argv[0]);

devuelve 0;

}

if (strcmp(argv[1], " on") == 0)

{

val = 1;

}

else

{

val = 0;

}

escribir(fd, &val, 4);

devolver 0;

}