28、从零写UVC驱动之实现设置属性

1. 先看APP以确定需要实现哪些接口
xawtv.c:
  grabber_scan
    ng_vid_open
      v4l2_driver.open // v4l2_open
        get_device_capabilities(h);
          // 调用VIDIOC_QUERYCTRL ioctl确定是否支持某个属性
          /* controls */
          for (i = 0; i < MAX_CTRL; i++) {
            h->ctl[i].id = V4L2_CID_BASE+i;
            if (-1 == xioctl(h->fd, VIDIOC_QUERYCTRL, &h->ctl[i], EINVAL) ||
            (h->ctl[i].flags & V4L2_CTRL_FLAG_DISABLED))
            h->ctl[i].id = -1;
          }
怎么去获得/设置属性?
看drv0-v4l2.c
可见这2个函数:
v4l2_read_attr : VIDIOC_G_CTRL
v4l2_write_attr : VIDIOC_S_CTRL

所以: 视频驱动里要实现3个ioctl:
VIDIOC_QUERYCTRL
VIDIOC_G_CTRL
VIDIOC_S_CTRL

2. 硬件上怎么设置属性?
2.1 UVC规范里定义了哪些属性 : uvc_ctrl.c里数组: static struct uvc_control_info uvc_ctrls[]

{
.entity = UVC_GUID_UVC_PROCESSING, // 属于哪了个entity(比如PU)
.selector = PU_BRIGHTNESS_CONTROL, // 用于亮度
.index = 0, // 对应Processing Unit Descriptor的bmControls[0]
.size = 2, // 数据长度为2字节
.flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
| UVC_CONTROL_RESTORE,
},

2.2 我们的设备支持哪些属性
这需要去看描述符, 比如 Processing Unit Descriptor的bmControls的值为7f 14
可知BIT0为1,表示支持BRIGHTNESS

在代码里:
uvc_drvier.c
uvc_ctrl_init_device
  // 对于每一个entity(IT,PU,SU,OT等)
    list_for_each_entry(entity, &dev->entities, list) {
      // 取出bmControls
      bmControls = ....

      // 计算bmControls里位值为1的个数,就是支持的属性个数
      ncontrols += hweight8(bmControls[i]);

      // 为每一个属性分配一个struct uvc_control
      entity->controls = kzalloc..

      // 设置这些struct uvc_control
      ctrl = entity->controls;
      for (...)
      {
        ctrl->entity = entity;
        ctrl->index = i;
      }

      // 把uvc_control和uvc_control_info挂构
      uvc_ctrl_add_ctrl(dev, info);
        ctrl->info = 某个uvc_control_info数组项(同属于一个entity, index相同)

2.3 怎么去操作这些属性
  参考 uvc_query_v4l2_ctrl
  uvc_find_control
    找到一个uvc_control_mapping结构体: uvc_ctrl.c里有static struct uvc_control_mapping uvc_ctrl_mappings[]
      {
        .id = V4L2_CID_BRIGHTNESS, // APP根据ID来找到对应的属性
        .name = "Brightness",
        .entity = UVC_GUID_UVC_PROCESSING, // 属于哪了个entity(比如PU)
        .selector = PU_BRIGHTNESS_CONTROL, // 用于亮度
        .size = 16, // 数据占多少位
        .offset = 0, // 从哪位开始
        .v4l2_type = V4L2_CTRL_TYPE_INTEGER, // 属性类别
        .data_type = UVC_CTRL_DATA_TYPE_SIGNED,// 数据类型
       },

    uvc_control_mapping结构体 用来更加细致地描述属性

  uvc_query_ctrl
    usb_control_msg

举例说明: 要设置亮度,怎么操作?
a. 根据PU的描述符的bmControls, 从它的bit0等于1知道它支持调节亮度
b. 在uvc_ctrls数组中根据entity和index找到这一项:
  {
    .entity = UVC_GUID_UVC_PROCESSING,
    .selector = PU_BRIGHTNESS_CONTROL,
    .index = 0,
    .size = 2,
    .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
        | UVC_CONTROL_RESTORE,
  },

知道了:这个设备支持SET_CUR, GET_CUR, GET_MIN等
要设置时,可以向PU的selector发数据, 发的数据是2字节

c. 在uvc_ctrl_mappings数组中根据ID找到对应的数组项
从而知道了更加细致的信息,
然后使用usb_control_msg读写数据

3. 怎么写代码?
实现3个ioctl: vidioc_queryctrl/vidioc_g_ctrl/vidioc_s_ctrl
vidioc_queryctrl : 发起USB控制传输获得亮度的最小值、最大值、默认值、步进值
vidioc_s_ctrl : 把APP传入的亮度值通过USB传输发给硬件
vidioc_g_ctrl : 发起USB传输获得当前亮度值

要点:数据发给谁?发给usb_device的
            VideoControl Interface
              里面的Processing Unit
                里面的PU_BRIGHTNESS_CONTROL

原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/8748013.html

时间: 2024-08-02 21:21:00

28、从零写UVC驱动之实现设置属性的相关文章

C语言零基础项目驱动式学习第四天

//类型修饰符  数组名[数组元素个数] = {初始化}; //定义数组的时候[]中必须是常量表达式, 不可以是变量; /* int age[5] = {21, 18, 25, 20, 18}; int array[10] = {0};//代表数组中有10个元素, 每个都是0; int array1[8] = {1};//代表数组中有8个元素,第一个是1,其余的为0; int age2[2 + 3] = {0}; */ //定义数组和使用数组的最大区别是, 前面是否有类型修饰符 //使用数组元素

C语言零基础项目驱动式学习第二天

//BOOL 类型是一种非真即假的数据类型,取值只有YES和NO, //BOOL 其实是OC中得数据类型,在C语言中,认为非0即为真. //BOOL 类型规定的存储空间为一个字节. //    BOOL a = YES; //    BOOL b = NO; //    printf("a = %d, b = %d\n", a, b); //    int a = 15, b = 18; //    BOOL c = a > b; //    printf("c = %

第二十二篇:再写Windows驱动,再玩Windbg---NET

2011年到现在,就没再怎么搞过Windows驱动了. 最近, 由于项目需要, 试着改一改一个显卡驱动(KMDOD), 从实践上证明, 我在理论上对一个驱动的架构的正确与否.(USB Display = KMDOD + AVStream). 其中, KMDOD是完成显示的部分功能, 完成其中的VidPN(Video present network), 将驱动中原来的POST物理设备转变为USB物理设备. 而AVStream之所以这样提出, 完成是由于USB Video class的启发, 要不然

C语言零基础项目驱动式学习第三天

一 while循环二do   while循环三 for循环for循环的执行顺序用如下表达式: for(expression1;expression2;expression3)        循环变量初值; 循环条件; 循环变量增量  {                expression4; }       执行的顺序应该是: 1)第一次循环,即初始化循环.      首先执行表达式expression1(一般为初始化语句):再执行expression2(一般为条件判断语句),判断express

C语言零基础项目驱动式学习第一天

引言: 智能手机(Smart Phone)是一种运算能力及功能比传统手机更强的手机.目前的操作系统基本上有以下几种: 1. Symbian Os 众所周知塞班隶属于NOKIA,Symbian开发之初的目标是保证在较低资源的设备上能长时间的运行,这导致了塞班的应用程序开发有着较为陡峭的学习路线,开发成本高,但是程序的运行的效率很高> 2.Android 开源, 联盟,Android凝聚了几乎遍布全球的力量,这是Android形象及声音能够被传到全球移动互联网市场每一个角落的根本原因.不过, 1).

sonix uvc驱动的添加 RT5350支持H264

根据sonix提供的驱动,需要在内核下进行配置,以添加到内核或与模块的方式进行编译: 1.makefile中添加驱动的目录,尽量保持和原有的一致, obj-$(CONFIG_USB_SN9C102)       += sn9c102/ obj-$(CONFIG_USB_SONiX_UVC_SN9C29x) += sonix_uvc_sn9c291/ obj-$(CONFIG_USB_ET61X251)      += et61x251/ 2.kconfig中添加src目录如下 source "d

怎么写Linux驱动

搞了一段时间驱动后的个人感悟,不管什么驱动,要少走弯路,共同的驱动工作流程应该如下: 1.看书,看资料,搞清驱动的原理:内核的该类驱动的架构,工作机制等,建议必读的文档是linux内核源代码的Document目录下的该驱动的txt文档,这里的文档最直接,最核心.最关键... 该有的都有了. 2.看datasheet,datasheet往往很多页,需要现在全看吗?No,现在先看总体的相关内容,先了解管脚定义,了解总体架构,了解寄存器或内存分配.掌握硬件的基本工作原理. 以上两步别想着偷懒略过,即使

如何写分层驱动(复杂的字符驱动)----以lcd驱动为例

*********如何写分层驱动(复杂的字符驱动)----以lcd驱动为例************** 思路:复杂的驱动都是建立在简单的驱动的基础上,所以首先要知道内核简单字符设备驱动如何写 1.如何简单驱动程序 1.1 构造file_operations .open = drv_open .read = drv_read 1.2 告诉内核有1.1这个结构,register_chrdev(主设备号,fop,name) 上面可以被下面三句话代替 分配cdev 设置cdev cdev_add 1.3

sonix uvc驱动的加入 RT5350支持H264

依据sonix提供的驱动,须要在内核下进行配置,以加入到内核或与模块的方式进行编译: 1.makefile中加入驱动的文件夹,尽量保持和原有的一致, obj-$(CONFIG_USB_SN9C102)       += sn9c102/ obj-$(CONFIG_USB_SONiX_UVC_SN9C29x) += sonix_uvc_sn9c291/ obj-$(CONFIG_USB_ET61X251)      += et61x251/ 2.kconfig中加入src文件夹例如以下 sourc