usb_control_msg //发起USB控制传输
举例说明: 要设置亮度,怎么操作?
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(比如V4L2_CID_BRIGHTNESS)找到对应的数组项
从而知道了更加细致的信息,
然后使用usb_control_msg读写数据
怎么写代码?
实现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
/* 参考:uvc_query_v4l2_ctrl */
int myuvc_vidioc_queryctrl (struct file *file, void *fh,
struct v4l2_queryctrl *ctrl) //查询亮度值的属性
{
__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
int ret;
u8 data[2];
if (ctrl->id != V4L2_CID_BRIGHTNESS)
return -EINVAL;
memset(ctrl, 0, sizeof *ctrl);
ctrl->id = V4L2_CID_BRIGHTNESS;
ctrl->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(ctrl->name, "MyUVC_BRIGHTNESS");
ctrl->flags = 0;
pipe = usb_rcvctrlpipe(myuvc_udev, 0); //端点0,控制传输端点
type |= USB_DIR_IN;
/* 发起USB传输确定ctrl内其他成员的值 */
ret = usb_control_msg(myuvc_udev, pipe, GET_MIN, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000); //发起控制传输,超时时间5000ms
if (ret != 2) //为什么是2?
return -EIO;
ctrl->minimum = myuvc_get_le_value(data); //通过USB传输,获得两个字节的数据,这一步就是把数据解析出来,得到minimum
ret = usb_control_msg(myuvc_udev, pipe, GET_MAX, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
if (ret != 2)
return -EIO;
ctrl->maximum = myuvc_get_le_value(data); /* Note signedness */
ret = usb_control_msg(myuvc_udev, pipe, GET_RES, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
if (ret != 2)
return -EIO;
ctrl->step = myuvc_get_le_value(data); /* Note signedness */
ret = usb_control_msg(myuvc_udev, pipe, GET_DEF, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
if (ret != 2)
return -EIO;
ctrl->default_value = myuvc_get_le_value(data); /* Note signedness */
printk("Brightness: min =%d, max = %d, step = %d, default = %d\n", ctrl->minimum, ctrl->maximum, ctrl->step, ctrl->default_value);
return 0;
}
/* 参考 : uvc_ctrl_get */
int myuvc_vidioc_g_ctrl (struct file *file, void *fh,
struct v4l2_control *ctrl) //在本例子中作用是获取当前亮度值
{
__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
int ret;
u8 data[2];
if (ctrl->id != V4L2_CID_BRIGHTNESS) //uvc_control_mapping结构体里的id,这里的一个ctrl应该是对应一个属性(比如亮度)
return -EINVAL;
pipe = usb_rcvctrlpipe(myuvc_udev, 0); //rcv表示接收,及从设备传进来
type |= USB_DIR_IN;
ret = usb_control_msg(myuvc_udev, pipe, GET_CUR, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000); //跟myuvc_udev这个USB设备的myuvc_control_intf接口的ProcessingUnitID (PU)的PU_BRIGHTNESS_CONTROL (selector)建立数据传输,因为是从设备中读取,所以type是USB_DIR_IN。
if (ret != 2)
return -EIO;
ctrl->value = myuvc_get_le_value(data); //获得亮度值后,解析后放入ctrl->value 。
return 0;
}
/* 参考: uvc_ctrl_set/uvc_ctrl_commit */
int myuvc_vidioc_s_ctrl (struct file *file, void *fh,
struct v4l2_control *ctrl)
{
__u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
unsigned int pipe;
int ret;
u8 data[2];
if (ctrl->id != V4L2_CID_BRIGHTNESS)
return -EINVAL;
myuvc_set_le_value(ctrl->value, data); //把一个数值转换成若干位,也就是把ctrl传进的亮度值转换成16位数据放到data里面去,转换之后就可以直接发给USB设备了
pipe = usb_sndctrlpipe(myuvc_udev, 0); //snd表示发出,及发给设备 ,发给设备的第0个端点
type |= USB_DIR_OUT;
ret = usb_control_msg(myuvc_udev, pipe, SET_CUR, type, PU_BRIGHTNESS_CONTROL << 8,
ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
if (ret != 2)
return -EIO;
return 0;
}