¿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", amp; first_drv_fops); //Registrar, 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 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 una macro del núcleo
module_init(first_drv_init);
module_init definirá una estructura. El 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. el kernel la estructura struct file_operaciones
6). Si hay una función de entrada, habrá una función de salida
module_exit(first_drv_exit);
Finalmente agregue el protocolo
MODULE_LICENSE("GPL");
3. mdev crea automáticamente nodos de dispositivo basados en la información del sistema:
Es demasiado problemático crear un dispositivo manualmente. archivos cada vez que escribe un controlador, es mucho más conveniente utilizar el sistema de archivos de administración del dispositivo. 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 ---gt
[*] 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 gt /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 programa /busybox en el directorio bin y llamarlo), 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. , mdev utilizará 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: echo /sbin/mdev gt; /proc/sys/kernel/hotplug se ejecuta al inicio, cuando se produce 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) /
( { /
static struct lock_class_key __key; /
__class_create(propietario, nombre, amp; __key); extern struct class * __must_check __class_create( struct module *owner,
const char *name,
struct lock_class_key *key
El prototipo de class_destroy es como siguiente:
extern void class_destroy(struct class *cls);
El prototipo de device_create es el siguiente:
extern struct device *device_create(struct class * cls, struct dispositivo *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 específico es el siguiente, consulte los siguientes ejemplos:
static struct class *firstdrv_class;
static struct class_device *firstdrv_class_dev;
firstdrv_class = class_create (ESTE_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(principal, 0), NULL, "xyz"); p>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 que usamos
Utilice 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 el nombre del dispositivo secundario, cuando registramos, registramos la estructura first_drv_fops en la matriz del kernel chrdev a través de Register_chrdev(0, "first_drv", amp; first_drv_fops) (con el número de dispositivo principal, el nombre del dispositivo, la estructura struct file_operations), y hay una función de escritura abierta en la estructura, entonces, ¿cómo la encuentra la aplicación? De hecho, encuentra los first_drv_fops que registramos en la matriz del núcleo chrdev según el tipo de dispositivo y el número de dispositivo principal en los atributos del archivo abierto.
Código de ejemplo:
#include
#include
#include
#include
#include
#include
#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 y 6 como salida */
*gpfcon amp;= ~((0x3lt;lt;(4*2)) | ( 0x3lt;lt;(5*2)) | (0x3lt; lt; (6*2)));
*gpfcon |= ((0x1lt; lt; (4*2)) | (0x1lt ; lt; (5*2)) | (0x1lt;lt;(6*2)));
devuelve 0;
}
estático 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(amp; val, buf, count); // copy_to_user();
if (val == 1)
{
// Ilumina
*gpfdat amp;= ~((1lt;lt;4) | (1lt;lt;5) | (1lt;lt;6) );
}
else
{
// Apaga la luz
*gpfdat |= (1lt; lt; 4) |
t;lt;5) | (1lt;lt;6);
}
devuelve 0;
}
estructura estática 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, p >
.write = first_drv_write,
};
int mayor;
static int first_drv_init(void)
{
major = Register_chrdev(0, "first_drv", & first_drv_fops); // Registrarse, informar al kernel
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;
}
vacío estático first_drv_exit(void) p >
{
unregister_chrdev(major, "first_drv"); // Desinstalar
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
p>iounmap(gpfcon);
}
module_init(first_drv_init);
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=`módulos `pwd`
limpiar:
make -C $(KERN_DIR) M=`módulos `pwd` limpio
rm -rf module.order
obj-m = first_drv.o
Programa de prueba:
#include
# include
#include
#include
/* firstdrvtest activado
* firstdrvtest desactivado
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/xyz", O_RDWR
if (fd lt; 0)
{
printf("¡no se puede abrir!\n");
}
if (argc != 2)
{
printf("Uso:\n");
printf("s \n", argv[0]);
devuelve 0; p>
p>
}
if (strcmp(argv[1], "on") == 0)
{
val = 1;
}
más
{
val = 0
}
escribir (fd, amp; val, 4
devolver
}
;