【V4L2】 Marco V4L2-dispositivo v4l2

Índice de contenidos de los artículos de la serie.

【V4L2】 Marco V4L2-dispositivo v4l2



Este artículo presenta la estructura troncal relativamente fácil de entender en V4L2, que involucra dos estructuras centrales: v4l2_device y
v4l2_subdev. El artículo presenta estas dos estructuras
tomando como ejemplo el código omap3isp del kernel Linux-4.4. La llamada introducción todavía juega un papel auxiliar.

Lo siguiente "esta rutina" se refiere a la rutina omap3isp.

Suplemento del marco V4L2

Primero mire la imagen:
Insertar descripción de la imagen aquí
División del submódulo V4L2.
Esta no es una división oficial. La dividí según mis propios sentimientos. Eso es todo. Entonces, el tema de este artículo es el sistema de subdispositivo, que es el tercer "subdesarrollador" en la figura anterior. También se puede ver en la figura que este artículo habla principalmente sobre cómo administrar muchos dispositivos de entrada. Nota: Son todos los dispositivos, no los dispositivos en la ruta del flujo de datos en tiempo de ejecución.


dispositivo principal

El dispositivo maestro se abstrae mediante v4l2_device. Esta rutina utiliza el árbol de dispositivos para la resolución de dispositivos y utiliza el controlador de plataforma para la sonda del controlador correspondiente. Existe la función isp_probe en el archivo drivers/media/platform/omap3isp/isp.c. La primera definición de parámetro de esta función es isp_device. Recuerde el artículo anterior, que mencionó que en la mayoría de los casos, la estructura v4l2_device debe integrarse en una estructura más grande. Esto para impulsar la personalización estructura, eso es todo, entonces su definición es la siguiente (eliminar la parte que no esté relacionada con el análisis):

struct isp_device {
    
    
    struct v4l2_device v4l2_dev;
    struct v4l2_async_notifier notifier;
    struct media_device media_dev;

    ... ...
}

Entre ellos, el relacionado con esta sección pertenece a la estructura v4l2_device v4l2_dev, que servirá como el administrador que administra todo el omap3isp en serie.

Al mismo tiempo, su uso es consistente con el "integrado" mencionado anteriormente. struct isp_device es una estructura definida por el controlador. Esta estructura puede considerarse como la estructura abstracta del dispositivo de todo omap3isp. En otras palabras: representa el gran omap3isp. dispositivo de. Verá su uso a continuación.

Registrar v4l2_device

Hay una función de llamada en la función isp_probe de isp.c isp_register_entities, y el contenido al principio es aproximadamente el siguiente:

... ...
    isp->v4l2_dev.mdev = &isp->media_dev;
    ret = v4l2_device_register(isp->dev, &isp->v4l2_dev);
    if (ret < 0) {
    
    
        dev_err(isp->dev, "%s: V4L2 device registration failed (%d)\n",
            __func__, ret);
        goto done;
    }
... ...

De hecho, puede ver que la función de registro no agrega dispositivos de alto nivel a una lista vinculada, sino que inicializa miembros de la estructura, como inicializar el encabezado de la lista vinculada de subdispositivos, agregar referencias de desarrollo, etc. Antes de conectar todos los subdispositivos en serie, v4l2_devicese debe inicializar y registrar el dispositivo general.

v4l2_subdev

Esta estructura es un subdispositivo abstracto para la gestión de subdispositivos. Tiene varias operaciones como "inicialización", "registro de subdispositivo" y "registro de nodo de subdispositivo". Por lo general, las instancias de la función "inicialización" se definen dentro de cada módulo controlador de subdispositivo, y las entidades de las dos funciones "registrar subdispositivo" y "registrar nodo de subdispositivo" se definen dentro del módulo de dispositivo principal, como por ejemplo: isp .c en.

Código anterior (en la función isp_probe):

ret = isp_initialize_modules(isp);
if (ret < 0)
    goto error_iommu;
ret = isp_register_entities(isp);
if (ret < 0)
    goto error_modules;

Primero veamos isp_initialize_modulesla implementación en la función:

static int isp_initialize_modules(struct isp_device *isp)
{
    
    
    int ret;

    ret = omap3isp_csiphy_init(isp);

    ret = omap3isp_csi2_init(isp);

... ...

    ret = omap3isp_h3a_aewb_init(isp);

    ret = omap3isp_h3a_af_init(isp);
... ...
    return 0;
... ...

Luego ingrese a omap3isp_xxxx_initla función y podrá ver que hay v4l2_subdev_initllamadas a funciones similares. El artículo intenta pegar la menor cantidad de código posible y habla más sobre la implementación y el mecanismo de uso. Creo que podrá encontrar el código relevante usted mismo. .

Entonces la estructura es más o menos así:

  1. Tiene un dispositivo de entrada omap3isp cuyo administrador aparece en un archivo de código separado llamado isp.c;

  2. Defina una estructura abstracta personalizada para representar el dispositivo omap3isp, denominada isp_device, e incruste v4l2_device internamente como una herramienta de administración de subdispositivos;

  3. Subdispositivos abstractos: similar a csi, vista previa, 3a, etc. en un subdispositivo. Cada subdispositivo tiene un archivo de código llamado ispxxx.c. Cada subdispositivo tiene su propia estructura abstracta llamada isp_xxx_dev y v4l2_subdev está incrustado. internamente como un subdispositivo Herramienta de abstracción de dispositivo a utilizar. Al mismo tiempo, implemente su propia función de inicialización de dispositivo, denominada xxx_init_eneities;

  4. Llame a xxx_init_entities del subdispositivo en la función de sonda del administrador isp.c, y la función de inicialización del subdispositivo inicializará v4l2_subdev;

  5. Registre v4l2_device en la función de sonda del administrador, registre el subdispositivo y, si es necesario, registre el nodo del subdispositivo para generar /dev/nodeX en el espacio de usuario;

  6. Ya está, ahora puede administrar todos los subdispositivos a través de v4l2_device. El marco en sí proporciona métodos de administración muy útiles y funciones de devolución de llamada relacionadas, miembros de estructura, etc.

Gestión de equipos

La gestión del dispositivo requiere inevitablemente la interconexión e interoperabilidad entre el dispositivo principal y el subdispositivo, de lo contrario no hay forma de gestionarlo. Esta sección presentará cómo realizar la interconexión de datos y la interoperabilidad entre el dispositivo principal y el subdispositivo. -dispositivo.

Interoperabilidad del dispositivo principal y del subdispositivo

Después de establecer la conexión mediante los pasos anteriores, ¿cómo encontrar el subdispositivo desde el dispositivo principal? ¿Cómo encontrar el dispositivo principal desde el dispositivo secundario? ¿Cómo pasar de v4l2_device a una estructura abstracta de dispositivo principal personalizada? ¿Cómo obtener una estructura personalizada de v4l2_subdev al subdispositivo?

  • Cómo encontrar subdispositivos desde el dispositivo principal. Primero, necesita obtener la estructura v4l2_device. Luego puede usar list_for_each_entry para recorrer los subdispositivos. Hay un miembro de nombre dentro de la estructura del subdispositivo, con una longitud de 32 bytes. Este campo debe ser el v4l2_device completo. Es único entre los subordinados, por lo que si desea encontrar un subdispositivo específico, puede comparar el campo de nombre del subdispositivo durante el recorrido para ver si es lo que busca. querer encontrar.

  • Cómo encontrar el dispositivo principal desde el subdispositivo Hay un miembro puntero v4l2_dev en la estructura v4l2_subdev, que apuntará al miembro v4l2_device cuando se registre el subdispositivo, y la función de registro es v4l2_device_register_subdev. Una vez completado este paso, la estructura del dispositivo principal se puede obtener obteniendo el miembro v4l2_dev dentro de la estructura del subdispositivo.

  • ¿Cómo crear una instancia de la estructura desde el dispositivo maestro al dispositivo maestro? Puede ver que no hay un puntero privado dentro de v4l2_device. Entonces, cómo encontrar la estructura de instanciación del dispositivo maestro. En este momento, puede obtenerla a través de otro parcial. método., Por ejemplo, al definir la estructura, coloque v4l2_device en el primer miembro de la estructura, y después de obtener v4l2_device a través de v4l2_subdev, puede forzar su dirección en la estructura instanciada personalizada por el dispositivo maestro para realizar el acceso.

  • Cómo crear una instancia de la estructura de un subdispositivo a otro. Hay dos punteros privados dentro del subdispositivo: dev_priv, host_priv. El primero es fácil de entender y fácil de usar. Al usarlo, simplemente llame a v4l2_set_subdevdatala función y apunte dev_priv a la estructura de instanciación del subdispositivo, y luego se puede usar para v4l2_get_subdevdataobtener los datos de la estructura de la instanciación de la estructura del subdispositivo de v4l2_subdev. No es fácil entender la utilidad de este último, pero también se puede v4l2_set_subdev_hostdata/v4l2_get_subdev_hostdataconfigurar/obtener a través de él. El host también es el terminal de control principal. Por ejemplo, el controlador del lado SOC de un sensor de cámara se puede utilizar como terminal principal. terminal de control. Otro ejemplo es una cámara que usa I2C para la comunicación. El controlador I2C en el lado SOC del sensor se puede usar como host_priv y controlar el comportamiento del subdispositivo a través de I2C si es necesario. O simplemente puede utilizar la estructura instanciada por el dispositivo principal como datos del host.

Intercambio de información entre dispositivos maestro y esclavo.

Esta sección utiliza múltiples casos de uso reales para explicar en profundidad varios métodos y escenarios de intercambio de información. Por ejemplo: ¿Cómo controlar el acceso a subdispositivos de un tipo específico? ¿Cómo devuelve el subdispositivo notificaciones al dispositivo principal?

  • Acceda a todos los dispositivos sensores y cierre su flujo de datos
  1. Cuando el subdispositivo está registrado, debe proporcionar funciones operativas relevantes, es decir, la estructura v4l2_subdev_ops. En este ejemplo, solo configuramos el miembro s_stream de su miembro de video.

  2. Proporcione el ID del grupo del subdispositivo, que es el miembro grp_id de v4l2_subdev. Aquí lo configuramos en un tipo de enumeración que supongo (solo debe asegurarse de que este tipo de enumeración sea único para todo el v4l2_device). Supongo que es OMAP3ISP_CAMSENSOR .

  3. No entraré en detalles sobre la inicialización y el registro de subdispositivos. Los métodos de inicialización y registro se han mencionado antes.

  4. Ejecute v4l2_device_call_all(v4l2_device, OMAP3ISP_CAMSENSOR, video, s_stream, 0); en este momento, atravesará todos los subdispositivos del grupo OMAP3ISP_CAMSENSOR bajo el nombre de v4l2_device y llamará a su función de módulo s_stream para cerrar el flujo de datos.

  • Una vez cerrado el flujo de datos del subdispositivo, se devuelve una notificación al dispositivo principal.
  1. Es necesario proporcionar la función de operación de notificación a miembros del dispositivo principal.

  2. Defina el formato de notificación, como mi propia definición, los 8 bits superiores indican qué subdispositivo, los segundos 8 bits indican qué tipo de operación (aquí están las operaciones de tipo de video) y los segundos 8 bits indican la función de operación específica (s_stream ), los 8 bits inferiores representan el valor de operación (0 se apaga).

  3. El subdispositivo llama a la función v4l2_subdev_notify para enviar una notificación formal. En este momento, también puede tomar algunos parámetros. Solo necesita pasar su dirección y el maestro y el subdispositivo acuerdan el formato de los datos.

  4. El dispositivo principal realiza operaciones relevantes después de recibir la notificación.

Centro de transporte video_device

Esta estructura integra la función del módulo terminal de gestión del flujo de datos y es responsable de proporcionar el intercambio de datos desde el espacio del kernel al espacio del usuario, es una función muy importante e indispensable.

Normalmente, todos los subdispositivos pueden registrar una estructura video_device para generar un nodo de dispositivo en el espacio del usuario para la operación del usuario, pero la diferencia es que solo el módulo responsable de transmitir datos de video necesita registrar el nombre del nodo del dispositivo de tipo de video (como el terminal de datos DMA del enlace de datos del dispositivo de entrada del kernel), y se pueden usar otros tipos de v4l-subdev.

video_device solo está asociado con v4l2_device, a través del cual se puede acceder a los recursos de toda la red del subdispositivo.

Cómo registrar un nodo de tipo de video

Regístrese con el video_register_deviceparámetro VFL_TYPE_GRABBER. En este momento, cuando la función se ejecuta y regresa, puede ver el /dev/videoXnodo del dispositivo en el espacio de usuario.

Tenga en cuenta que se debe proporcionar su función de operación, similar a la siguiente:

static struct v4l2_file_operations isp_video_fops = {
    
    
    .owner = THIS_MODULE,
    .unlocked_ioctl = video_ioctl2,
    .open = isp_video_open,
    .release = isp_video_release,
    .poll = isp_video_poll,
    .mmap = isp_video_mmap,
};

videobuf2Esta sección no presenta en detalle cómo lo implementan sus miembros, pero se presentará en detalle en un artículo posterior .

Cómo registrar otros tipos de nodos

Para dispositivos de entrada v4l2, use v4l2_device_register_subdev_nodespara registrar nodos de dispositivo en lotes. Seguirá llamando video_register_devicea la función internamente, pero usará VFL_TYPE_SUBDEVel tipo en lugar del anterior VFL_TYPE_GRABBER. Luego, el nombre del nodo del dispositivo generado en el espacio de usuario es v4l- subdevX.

En este caso, la función de operación del nodo del dispositivo registrado es la función de operación predeterminada definida en v4l2-device.c, que se define de la siguiente manera:

const struct v4l2_file_operations v4l2_subdev_fops = {
    
    
    .owner = THIS_MODULE,
    .open = subdev_open,
    .unlocked_ioctl = subdev_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl32 = subdev_compat_ioctl32,
#endif
    .release = subdev_close,
    .poll = subdev_poll,
};

conclusión

Hasta ahora, se han introducido básicamente las operaciones básicas del dispositivo y se presentarán algunas operaciones más avanzadas en los artículos siguientes. Como adelanto, el siguiente artículo trata sobre el marco de medios, paso a paso. Después de leer y practicar este artículo, puede ver el nodo del dispositivo /dev/video en el espacio de usuario. Puede escribir un pequeño caso de prueba. Al abrir el nodo del dispositivo, recorra el subdispositivo y escriba el nombre del subdispositivo. También puede agregar información más detallada. En resumen, el propósito de este artículo es implementar una topología de dispositivo bajo el marco de administración de dispositivos v4l2. Puede imprimir esta estructura de topología para completar la tarea perfectamente.

Supongo que te gusta

Origin blog.csdn.net/qq_44710568/article/details/132605425
Recomendado
Clasificación