[Conceptos básicos de Linux]: dispositivo de medios de marco V4L2

Este artículo ofrece una introducción detallada a la administración de dispositivos de flujo de datos en tiempo de ejecución de V4L2, incluyendo lo que se llama [administración de dispositivos en tiempo de ejecución], para qué se usa, cómo usarlo, etc. El objetivo de este artículo es dominar el uso de la codificación y la aplicación funcional del dispositivo meida.

一 、 marco de medios

1.1 Introducción

La API de control relacionada se encuentra en Documentation / DocBook / media / v4l / media-controller.xml. Este documento se centra en la implementación del marco principal de medios de prueba. Nota: No puede ver nada viéndolo directamente. Hacer htmldocs u otras cosas en el directorio raíz del kernel servirá. Es fácil de ver.

1.2. Equipo de control en tiempo de ejecución

Es decir, el control de la línea de flujo de datos después de que se inicia el dispositivo, al igual que una línea de ensamblaje de fábrica, cada nodo (etiquetado, impresión y empaque) en la línea de ensamblaje es como cada subdispositivo en el dispositivo de entrada, y el control del dispositivo en tiempo de ejecución es Para lograr el efecto de poder controlar el nodo, por ejemplo, hay varias máquinas para etiquetar, cuál debe seleccionarse para este procesamiento de tubería, si agregar la pantalla de seda, qué máquina agregar, y así.

1.3, papel

Proporcionar administración de tuberías en tiempo real. La tubería se entiende como una tubería. Imagínese una tubería de agua. El agua dentro es el flujo de datos. El video csi-> isp-> en el dispositivo de entrada forma una línea de tubería. El marco de medios proporciona funciones como apertura, cierre, control de efectos y control de nodos de la tubería.

1.4 Cómo utilizar

El kernel utiliza principalmente cuatro estructuras para organizar numerosos nodos: media_device, media_entity, media_link y media_pad. Todo el marco de los medios se utiliza en torno a estas cuatro estructuras, que se introducirán en detalle a continuación.

1.5, modelo de dispositivo abstracto

Uno de los propósitos del marco de medios es descubrir la topología del dispositivo y configurarlo en tiempo de ejecución. Para lograr este objetivo, el marco de medios abstrae los dispositivos de hardware en entidades, que están conectadas a través de enlaces.

1. Entidad: abstracción del módulo del dispositivo de hardware (análogo a los diversos componentes y chips en la placa de circuito)

2, pad: abstracción del puerto del dispositivo de hardware (componentes analógicos, pines en el chip)

3. Enlace: la abstracción de la conexión del dispositivo de hardware, los dos extremos del enlace son almohadillas (conexiones entre los pines de los componentes analógicos)

#------------#                #------------#
|          __|__            __|__          |
|         |  |  |   link   |  |  |         |
|         | pad |<-------->| pad |         |
|         |__|__|          |__|__|         |
|            |                |            |
|   entity   |                |   entity   |
#------------#                #------------# 

Imagina que si necesitas establecer una conexión entre entidades, necesitas almacenar el enlace y la información de la entidad en el panel. El enlace necesita almacenar el panel y la información de la entidad, y la entidad necesita almacenar el enlace y la información del panel. Pertenece a tú y yo, en tu caso.

Dos, equipo multimedia

Un dispositivo multimedia está representado por una estructura media_device. Normalmente, la estructura debe estar incrustada en una estructura definida por el dispositivo más grande, y la mayoría de las veces, media_device y v4l2_device están en un nivel paralelo, o el código de omap3isp es un ejemplo:

struct isp_device {
    struct v4l2_device v4l2_dev;
    struct v4l2_async_notifier notifier;
    struct media_device media_dev;
    struct device *dev;
    u32 revision;
    ... ...
}

2.1. Utilice la siguiente función para registrar el dispositivo multimedia:

registro_dispositivo_medios (struct dispositivo_medios * mdev);

La persona que llama a la función debe establecer los siguientes miembros de la estructura antes del registro (es responsabilidad de la persona que llama inicializar la estructura por adelantado):

  • dev: debe apuntar a un dispositivo principal, generalmente el miembro del dispositivo de la plataforma.
  • modelo: el nombre del modelo.

Los siguientes miembros son opcionales:

  • serial: número de serie, debe ser único
  • bus_info: información del bus, si es un dispositivo PCI, se puede configurar en "PCI:"
  • hw_revision: versión de hardware. Si es posible, debe formatearse con la definición de macro KERNEL_VERSION
  • driver_version: versión del controlador. El nombre del nodo del dispositivo final es media [0-9], y el kernel genera automáticamente el número de nodo.

2.2. Utilice la siguiente función para desinstalar el dispositivo

media_device_unregister (struct media_device * mdev);

Cabe señalar que desinstalar un dispositivo que no ha sido registrado es *** inseguro ***. Hay varias razones principales por las que la adivinación del código de visualización personal no es segura:

  1. Si no está registrado, el miembro de la entidad dentro de media_device no se puede inicializar. Si su valor es un valor indeterminado, causará acceso ilegal;
  2. Si no está registrado, los miembros de devnode internos no se inicializarán y se producirán problemas durante la desinstalación.

三 、 entidades 、 pads 、 enlaces

3.1 、 entidades

Las entidades están representadas por una estructura media_entity, que generalmente está incrustada en una estructura más grande, como la estructura v4l2_subdev o video_device (no necesita asignar espacio usted mismo, la estructura ya está incluida), por supuesto, también puede asignar directamente un entidad. Utilice la siguiente función para inicializar la entidad:

media_entity_init (struct media_entity * entidad, u16 num_pads, struct media_pad * pads, u16 extra_links);

Los parámetros que deben tenerse en cuenta antes de ejecutar la función de inicialización son:

  • num_pads: el número de pads, que está relacionado con la estructura del subdispositivo del controlador;
  • pads: matriz de estructura media_pad, normalmente la almohadilla está incrustada en la estructura definida por el controlador, la dirección de la matriz se pasa a este parámetro y la almohadilla debe inicializarse de antemano;
  • extra_links: esta función asigna el número de enlaces basado en num_pads, este parámetro indica cuántos enlaces adicionales se necesitan además del número preasignado;
  • entidad: el nombre, tipo, banderas, revisión y group_id de media_entity deben establecerse antes o después de la inicialización. Si la estructura está incrustada en una estructura de nivel superior, estos miembros también pueden configurarse mediante un código de marco de nivel superior. La identificación se completa durante el registro (si el miembro de la identificación se establece de antemano, el valor preestablecido se mantendrá durante el registro). La entidad tiene banderas relacionadas [banderas] para identificar su estado y función, MEDIA_ENT_FL_DEFAULT significa que esta es una entidad predeterminada. Puede establecer el ID de grupo de varias entidades en el mismo número entero para identificar que pertenecen a la misma categoría. Para el kernel, el ID de grupo es inútil, pero el ID de grupo se pasará al espacio de usuario cuando se enumere la entidad. Útil en determinadas situaciones en el espacio de usuario.

3,2 、 almohadillas

El pad está representado por una estructura media_pad, y los datos de los pads son administrados por el controlador (forma de matriz). Los pads usan subíndices de entidad y matriz para una identificación única. El id dentro de la entidad no se repetirá, pero el id del pad entre diferentes entidades puede repetirse, por lo que el índice del pad debe ser confirmado conjuntamente por la entidad y el id.

Dado que la cantidad de pads se conoce de antemano (el chip que fabrica, debe saber cuántos pines tiene), la estructura media_pad ya no se asigna dinámicamente y el controlador debe ser responsable de administrar la matriz de la estructura (evite la asignación dinámica) . El controlador debe establecer el atributo de dirección de pads antes de que se llame a la función media_entity_init. Pads tiene bits de banderas para indicar sus atributos. Solo necesita configurar este miembro durante la inicialización, y el resto lo hace la función media_entity_init:

MEDIA_PAD_FL_SINK:    目的 pad
MEDIA_PAD_FL_SOURCE:  源 pad

3.3 、 enlaces

Los enlaces están representados por una estructura media_link. Todos los pads de cada entidad almacenan todos los enlaces relacionados con él. Un enlace será almacenado por el pad de origen y el pad de destino respectivamente, para realizar el recorrido en ambas direcciones, positiva y negativa. . Utilice la siguiente función para crear enlaces:

media_entity_create_link(struct media_entity *source, u16 source_pad, struct media_entity *sink, u16 sink_pad, u32 flags);

Los enlaces tienen algunos bits de banderas para identificar sus atributos:

MEDIA_LNK__FLENABLED:link 被使能,可以用来传输数据,多个 link 连接到同一个 sink pad 时,只有一个 link 可能被使能。
MEDIA_LNK_FL_IMMUTABLE:link 的使能状态不能在运行时被改变,一般情况下这两个标志位同时被设置。
MEDIA_LNK_FL_DYNAMIC:link 的状态是动态可变的。

A diferencia de las almohadillas, la cantidad de enlaces no siempre se confirma de antemano (a veces en la placa de circuito no puede confirmar completamente cuántos dispositivos deben conectarse a los pines, es muy probable que haya cambios temporales), por lo que la función media_entity_init se basa en Los parámetros entrantes preasignan una cierta cantidad de estructura media_link, si no es suficiente, se asignará dinámicamente en media_entity_create_link (si el número de enlaces es mayor o igual a max_link, el número de enlaces se expandirá ).

Cuatro, registro y desinstalación

El controlador necesita usar las siguientes funciones para registrar y desinstalar la entidad (no necesita ejecutarse manualmente, se hace en la función v4l2_device_un / register_subdev):

media_device_register_entity(struct media_device *mdev, struct media_entity *entity);
media_device_unregister_entity(struct media_entity *entity);

El kernel usa un número entero positivo único para representar cada entidad (única bajo el mismo dispositivo_de_medios), y el controlador también puede especificar el valor de ID de la entidad completando el miembro media_entity-> id, pero debe ser único. Si los ID son generados automáticamente por el kernel, no hay garantía de que sean continuos. De hecho, los ID generados automáticamente por el kernel son asignados por la entidad media_device-> entity_id ++, y el valor se inicializa a 1 en el función media_device_register Liman.

Después de descargar la entidad, debe llamar a las siguientes funciones para liberar los recursos relacionados solicitados, principalmente para liberar la memoria de estructura media_link asignada dinámicamente:

media_entity_cleanup(struct meida_entity *entity); //与 media_entity_init 结对使用

Para atravesar entidades, puedes realizar la llamada al sistema MEDIA_IOC_ENUM_ENTITIES en el espacio de usuario. Debes establecer el ID de media_entity_desc en (0 | MEDIA_ENT_ID_FLAG_NEXT). Durante el ciclo, solo necesitas configurar id | = MEDIA_ENT_ID_FLAG_NEXT para completar el proceso transversal de la entidad. Si necesita enumerar la Entidad especificada, debe establecer la identificación en el valor de identificación de la entidad especificada (la identificación de la entidad del núcleo comienza desde 1), esto se puede ver en la función de registro de la entidad. El ejemplo de código es el siguiente, intenté simplificar el código publicado para evitar ocupar demasiado espacio:

int enum_media_device_entities(int iFd)
{
    int iRet;
    struct media_entity_desc desc;
    
    desc.id = 0 | MEDIA_ENT_ID_FLAG_NEXT;
    while(1) {
        iRet = ioctl(iFd, MEDIA_IOC_ENUM_ENTITIES, &desc);
        if(iRet < 0) {
            MODULE_WRN("enum media entities end \r\n");
            break;
        }
        MODULE_DBG("entity name [%s]\r\n", desc.name);
        desc.id |= MEDIA_ENT_ID_FLAG_NEXT;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int iErr = 0, ivFd;
    ivFd = open("/dev/media0", O_RDWR);
    iErr = enum_media_device_entities(ivFd);
    
    close(ivFd);
  open_err:
    return iErr;
}

5. Recorrido del gráfico (profundidad primero)

¿Qué hace el recorrido del gráfico? Nos proporciona una forma de acceder a cada entidad especificada en tiempo de ejecución. En cuanto a por qué necesitamos acceso, es porque es posible que necesitemos administrarlas en tiempo de ejecución .

Las siguientes funciones se pueden utilizar para recorrer las entidades que pertenecen al mismo dispositivo de medios (recorrido lineal, recorrido de gráfico atípico, es decir, el mismo método de recorrido que la lista vinculada):

struct media_entity *entity;
media_device_for_ench_entity(entity, mdev) {
    /* entity will point to each entity in turn */
    ... ...
}

Es posible que el controlador necesite atravesar todas las entidades accesibles de una entidad determinada a través de los enlaces habilitados. El marco de medios proporciona una API de profundidad para realizar esta tarea. Cabe señalar que es necesario evitar atravesar el gráfico de lazo cerrado, de lo contrario caerá en un lazo infinito. Para evitar esta situación, la función limita la profundidad máxima de recorrido a MEDIA_ENTITY_ENUM_MAX_DEPTH. La última definición de esta macro es 16 ** [A partir de Linux-4.4. 138] **.

media_entity_graph_walk_start(struct media_entity_graph *graph, struct media_entity *entity);
meida_entity_graph_walk_next(struct media_entity_graph *graph);

Al usarlo, primero inicialice el gráfico con la primera función, y luego llame a la segunda función para atravesar en un bucle. Después de que se complete el recorrido, la segunda función devolverá NULL. El proceso de recorrido se puede interrumpir en cualquier momento y no es necesario llamar a la función de limpieza.

Hay una función de ayuda correspondiente para encontrar el enlace de dos pads dados, o para encontrar otro pad conectado a él a través de un pad.

media_entity_find_link(struct media_pad *source, struct media_pad *sink);
media_entity_remote_pad(struct media_pad *pad);

Seis, complementar la configuración de los enlaces.

Los atributos del enlace se pueden cambiar en tiempo de ejecución, simplemente llame a la siguiente función para completar:

media_entity_setup_link(struct media_link *link, u32 flags);

El parámetro banderas se utiliza para establecer los atributos del enlace especificado. Los atributos permitidos van desde el atributo MEDIA_LINK_FL_ENABLED al atributo MEDIA_LINK_FL_ENABLE o MEDIA_LINK_FL_DISABLE. Si el enlace se establece con la bandera MEDIA_LINK_FL_IMMUTABLE, no se puede habilitar ni deshabilitar. Cuando un enlace está habilitado o cerrado, el marco de medios llamará al receptor y al link_setup en el lado de la fuente en dos llamadas para configuraciones relacionadas. Si la segunda llamada falla, la primera también será restaurada.

El controlador del dispositivo multimedia puede configurar media_device-> link_notify para que apunte a una función de devolución de llamada, que se llamará después de que se complete la operación link_setup. Si algún enlace no es inmutable, el controlador de entidad debe implementar la operación link_setup por sí mismo. La configuración de un enlace no debería afectar a otros enlaces. Si un enlace está conectado a la plataforma del fregadero y el enlace está habilitado, entonces otros vínculos a la plataforma ya no se pueden habilitar y se debe devolver -EBUSY en este momento.

6.1 canalización dado el estilo de los medios

El concepto de canalización se introdujo antes y no se repetirá. Aquí hay un diagrama explicativo (de hecho, esto no es muy claro y fácil de entender, y hay más claros y fáciles de entender que no se pueden publicar debido a algunas razones . Utilice su imaginación, de acuerdo con la figura. La descripción anterior abstrae una imagen por sí misma, siempre que solo se centre en un punto (la canalización es la abstracción de los enlaces de flujo de datos, creo):

Cuando la transmisión está activada, el controlador debe notificar a todas las entidades en la tubería para mantener el estado actual sin cambios, y puede llamar a la siguiente función para completar la notificación (esta función solo llamará a la devolución de llamada de validación en el lado del receptor):

media_entity_pipeline_start(struct media_entity *entity, struct media_pipeline *pipe);

Esta función marcará todas las entidades en la conexión de enlace habilitado como estado de transmisión, ya sea directa o indirectamente. La estructura media_pipeline a la que apunta el segundo parámetro se pasará a todas las entidades de la canalización. El controlador necesita incrustar la estructura media_pipeline en una estructura de nivel superior y puede acceder a la canalización desde la estructura media_entity. Cuando necesite detener la transmisión, debe llamar a:

media_entity_pipeline_stop(struct media_entity *entity);

Dado que la función de inicio se puede llamar de forma anidada, correspondiente a ella, la función de parada también debe mantener un número correspondiente de llamadas. La función media_entity_pipeline_start comprobará la validez del enlace. En este momento, el miembro link_validate de media_entity se utilizará para completar la comprobación. La siguiente imagen es una ilustración del recorrido:

                                                                                                     recorrido de la tubería

El número del círculo en la figura anterior se refiere al orden de las visitas. Vale la pena mencionar que la implementación del kernel del recorrido de grafos primero en amplitud es muy intrigante y de valor de referencia, y vale la pena encontrar el código del kernel usted mismo. Entre ellos, se utilizan conceptos como pilas y mapas de bits. El código específico está en la función media-entity.c / media_entity_pipelien_start.

Dado que el recorrido anterior es primero en amplitud y todo recorrido, es decir, si su ISP tiene dos fuentes de entrada, entonces estas dos fuentes de entrada pueden estar activadas al mismo tiempo, la mayoría de las veces no queremos que esto suceda. lo que se espera es que se abran la fuente de entrada especificada y la canalización de enlace único especificada. En este momento, debe administrar la canalización usted mismo y puede implementar su propia estructura de canalización para la gestión relacionada. La implementación es muy simple, esta estructura de canalización es similar a la siguiente:

struct spec_pipeline {
    struct list_head entities;    //pipeline 线上的 entity 链表头
    struct media_entity entities[PIPE_LENGTH];     //与上一个类似,随自己想法去实现
    int (*open_fun)(struct media_entity entity, int onoff);
    int (*s_stream)(struct media_entity entity, int onoff);
    ... ...
};

Consejos:

1. Se puede encontrar v4l2_subdev de media_entity usando la función media_entity_to_v4l2_subdev.

2. Puede agregar el indicador de habilitación para el enlace en la parte streamon del módulo de video. La función media_entity_pipeline_start agregará valor al miembro entity.stream_count y pasará la tubería en el segundo parámetro al miembro entity.pipe en la línea de enlace. Una vez que se completa el indicador de habilitación, se puede realizar un recorrido del gráfico en cada entidad para llamar a su miembro set_stream para iniciar la transmisión. De hecho, cuando se llama a s_param, s_fmt y otros ioctl, se necesita un recorrido de gráfico para llamar a las funciones de devolución de llamada de cada entidad en toda la canalización para configuraciones relacionadas.

3. Una vez registrados todos los nodos del subdispositivo, la conexión de cada entidad se puede completar a través de media_entity_create_link, esperando que se abra más tarde el flujo de datos completo.

4. ¿Por qué existe un marco de medios? Debido a que solo hay subdev, cada clase de subdispositivo está en un estado de nivel y no hay diferencia en la dirección del flujo de datos. Si necesita establecer una canalización de flujo de datos, debe implementarla usted mismo, que será Más problemático. Con el marco de medios, estas gestiones serán mucho más convenientes, porque proporciona todas las operaciones de gestión del pipeline, de modo que muchos subdevs se pueden conectar en serie como un flujo de datos completo, para llevar a cabo correctamente y transferencia de datos dirigida.

5. Tanto v4l2_subdev como video_device tienen una estructura media_entity (tipo no puntero). La entidad en video_devcie se registrará con el registro del dispositivo de video, y el nombre será el nombre del dispositivo de video. Los dos son diferentes. Cuando se usa Necesita especial atención.

Supongo que te gusta

Origin blog.csdn.net/u014674293/article/details/111488115
Recomendado
Clasificación