1917 lines
70 KiB
C
1917 lines
70 KiB
C
#ifdef SUPPORT_MS_EXTENSIONS
|
|
#pragma bss_seg(".usb.data.bss")
|
|
#pragma data_seg(".usb.data")
|
|
#pragma code_seg(".usb.text")
|
|
#pragma const_seg(".usb.text.const")
|
|
#pragma str_literal_override(".usb.text.const")
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include "usb_ctrl_transfer.h"
|
|
#include "usb_host.h"
|
|
#include "usb_ctrl_transfer.h"
|
|
#include "host_uvc.h"
|
|
#include "usb_stack.h"
|
|
#include "device/device_drive.h"
|
|
#include "app_config.h"
|
|
/* #include "usb/host/usb_host.h" */
|
|
|
|
#define LOG_TAG_CONST USB
|
|
#define LOG_TAG "[USB]"
|
|
#define LOG_ERROR_ENABLE
|
|
#define LOG_DEBUG_ENABLE
|
|
#define LOG_INFO_ENABLE
|
|
/* #define LOG_DUMP_ENABLE */
|
|
#define LOG_CLI_ENABLE
|
|
#include "debug.h"
|
|
|
|
#if TCFG_HOST_UVC_ENABLE
|
|
|
|
/*static USB_DEV uvc_ep3;*/
|
|
/*static USB_DEV uvc_ep4;*/
|
|
#define USB_DT_INTERFACE_HEADER_DESCRIPTOR_SIZE 0x0d
|
|
#define STOP_TRANSFER 1
|
|
#define UVC_SUPPORT_MJEPG_ENABLE 1
|
|
#define UVC_SUPPORT_H264_ENABLE 0//707不支持
|
|
#define UVC_SUPPORT_YUYV_ENABLE 0//707不支持
|
|
#if (UVC_SUPPORT_MJEPG_ENABLE+UVC_SUPPORT_H264_ENABLE+UVC_SUPPORT_YUYV_ENABLE)!=1
|
|
#error "uvc config error!!!!!"
|
|
#endif
|
|
|
|
#define time_get(t,ms) t = jiffies + msecs_to_jiffies(ms)
|
|
#define time_out(a,b) (((long)(a) - (long)(b)) > 0)
|
|
|
|
#define check_ret(ret)\
|
|
if ((int)(ret) < DEV_ERR_NONE) {\
|
|
log_error("err ret = %d\n",ret);\
|
|
return ret;\
|
|
}
|
|
|
|
struct usb_video_manager {
|
|
u8 online;
|
|
u8 open;
|
|
volatile u8 in_irq;
|
|
u8 itf_base;
|
|
const char *name;
|
|
u8 *buffer;
|
|
u32 frame_cnt;
|
|
struct device dev;
|
|
};
|
|
|
|
static struct usb_video_manager uvc_manager[USB_MAX_HW_NUM];
|
|
|
|
#define usbpriv_to_usbid(priv) ((usb_dev)(priv->usb_id))
|
|
|
|
static u8 usbdev_to_usbid(struct device *device)
|
|
{
|
|
struct usb_video_manager *hdl = container_of(device, struct usb_video_manager, dev);
|
|
return hdl->name[3] - '0';
|
|
|
|
}
|
|
int uvc_host_online(void)
|
|
{
|
|
int id = 0;
|
|
for (id = 0; id < 2; id++) {
|
|
if (uvc_manager[id].online) {
|
|
return id;
|
|
}
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
u32 uvc_host_get_frame(usb_dev usb_id)
|
|
{
|
|
return uvc_manager[usb_id].frame_cnt;
|
|
}
|
|
static int uvc_set_power(struct usb_host_device *host_dev, u32 value)
|
|
{
|
|
usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
hdl->online = 0;
|
|
return 0;
|
|
}
|
|
static int uvc_get_power(struct usb_host_device *host_dev, u32 value)
|
|
{
|
|
usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
return hdl->online;
|
|
}
|
|
static int uvc_ioctl(struct usb_host_device *host_dev, u32 cmd, u32 arg)
|
|
{
|
|
return 0;
|
|
}
|
|
static const struct interface_ctrl uvc_host_ops = {
|
|
.interface_class = USB_CLASS_VIDEO,
|
|
.set_power = uvc_set_power,
|
|
.get_power = uvc_get_power,
|
|
.ioctl = uvc_ioctl,
|
|
};
|
|
static struct usb_interface_info uvc_host_inf[USB_MAX_HW_NUM] = {
|
|
{
|
|
.ctrl = (struct interface_ctrl *) &uvc_host_ops,
|
|
.dev.uvc = NULL,
|
|
},
|
|
};
|
|
|
|
#define device_to_uvc(device) (uvc_host_inf[usb_id].dev.uvc)
|
|
|
|
/**
|
|
* @brief usb video 初始化
|
|
*
|
|
* @param: usb_id : usb端口ID
|
|
* 0: usb0 fusb
|
|
* 1: usb1 husb
|
|
* @param: sub_id : 同一usb端口的 子设备id
|
|
* 目前支持husb端口上挂最多2个子设备
|
|
*
|
|
* @return: 0: 成功 非0: 失败
|
|
**/
|
|
int usb_host_video_init(const usb_dev usb_id, const u8 sub_id)
|
|
{
|
|
int ret = 0;
|
|
struct device *device;
|
|
struct usb_host_device *host_dev;
|
|
struct usb_uvc *uvc;
|
|
u32 maxpsize;
|
|
struct usb_video_manager *hdl = &uvc_manager[sub_id];
|
|
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
/* uvc = device_to_uvc(device); */
|
|
uvc = uvc_host_inf[sub_id].dev.uvc;
|
|
if (!uvc) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
maxpsize = (uvc->wMaxPacketSize & 0x7ff) * (((uvc->wMaxPacketSize >> 11) & 0x3) + 1);
|
|
if (uvc->xfer_type == USB_ENDPOINT_XFER_ISOC) {
|
|
if (usb_id == 0) {
|
|
hdl->buffer = malloc(maxpsize);
|
|
} else if (usb_id == 1) {
|
|
hdl->buffer = malloc(maxpsize * ISO_INTR_CNT);
|
|
}
|
|
if (!hdl->buffer) {
|
|
log_error("err no mem in hdl->buffer");
|
|
ret = -DEV_ERR_INVALID_BUF;
|
|
goto __exit_fail;
|
|
}
|
|
uvc->host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_ISOC);
|
|
if ((int)uvc->host_ep < 0) {
|
|
log_error("uvc get ep_num fail");
|
|
ret = -DEV_ERR_INUSE;
|
|
goto __exit_fail;
|
|
}
|
|
if (usb_id == 0) {
|
|
uvc->ep_buffer = usb_h_alloc_ep_buffer(usb_id, uvc->host_ep | USB_DIR_IN, maxpsize);
|
|
} else if (usb_id == 1) {
|
|
uvc->ep_buffer = usb_h_alloc_ep_buffer(usb_id, uvc->host_ep | USB_DIR_IN, maxpsize * ISO_INTR_CNT);
|
|
}
|
|
if (!uvc->ep_buffer) {
|
|
log_error("uvc alloc ep buffer fail");
|
|
ret = -DEV_ERR_INVALID_BUF;
|
|
goto __exit_fail;
|
|
}
|
|
} else if (uvc->xfer_type == USB_ENDPOINT_XFER_BULK) {
|
|
hdl->buffer = malloc(maxpsize * 2); //第二份用于保存bulk的上一包
|
|
if (!hdl->buffer) {
|
|
log_error("err no mem in hdl->buffer");
|
|
ret = -DEV_ERR_INVALID_BUF;
|
|
goto __exit_fail;
|
|
}
|
|
uvc->host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
|
|
if ((int)uvc->host_ep < 0) {
|
|
log_error("uvc get ep_num fail");
|
|
ret = -DEV_ERR_INUSE;
|
|
goto __exit_fail;
|
|
}
|
|
uvc->ep_buffer = usb_h_alloc_ep_buffer(usb_id, uvc->host_ep | USB_DIR_IN, maxpsize * 2); //bulk传输dma使用double buffer
|
|
if (!uvc->ep_buffer) {
|
|
log_error("uvc alloc ep buffer fail");
|
|
ret = -DEV_ERR_INVALID_BUF;
|
|
goto __exit_fail;
|
|
}
|
|
}
|
|
ret = usb_control_msg(host_dev, USB_REQ_SET_INTERFACE, 0x01, 0, hdl->itf_base + 1, NULL, 0);
|
|
/* check_ret(ret); */
|
|
if (ret < DEV_ERR_NONE) {
|
|
log_error("USB_REQ_SET_INTERFACE %d to 0 fail", 0);
|
|
goto __exit_fail;
|
|
}
|
|
|
|
hdl->online = 1;
|
|
|
|
return DEV_ERR_NONE;
|
|
|
|
__exit_fail:
|
|
if (uvc->ep_buffer) {
|
|
usb_h_free_ep_buffer(usb_id, uvc->ep_buffer);
|
|
uvc->ep_buffer = NULL;
|
|
}
|
|
if (hdl->buffer) {
|
|
free(hdl->buffer);
|
|
hdl->buffer = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static struct device *uvc_host_device_find(const char *name)
|
|
{
|
|
if (!name) {
|
|
return NULL;
|
|
}
|
|
usb_dev usb_id = name[3] - '0';
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
if (usb_id >= 0 && usb_id <= 1 && name && hdl->name) {
|
|
if (!strcmp(hdl->name, name)) {
|
|
return &hdl->dev;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int uvc_dummy_stream_out(void *fd, int cnt, void *stream_list, int eof)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int usb_uvc_parser(struct usb_host_device *host_dev, u8 interface_num, u8 *pBuf)
|
|
{
|
|
int len = 0;
|
|
int cur_len;
|
|
int cur_type;
|
|
int cur_sub_type;
|
|
int loop = 1;
|
|
int bControlSize;
|
|
int formart_num;
|
|
u32 frame_num;
|
|
u16 wTotalLength = 0;
|
|
u32 wMaxPacketSize = 0;
|
|
u32 AlternateSetting = 0;
|
|
u8 assocition_num = 0;
|
|
u8 format_support = 0;
|
|
struct usb_endpoint_descriptor end_desc;
|
|
struct usb_uvc *real_uvc = NULL;
|
|
struct usb_private_data *private_data = &host_dev->private_data;
|
|
usb_dev usb_id = private_data->usb_id;
|
|
if (interface_num) {
|
|
//同一个usb口下另外一个uvc 设备
|
|
usb_id = 0;
|
|
}
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
u8 int_ep = 0;
|
|
u8 ItfSubClass = 0;
|
|
u8 *pformat;
|
|
|
|
struct usb_uvc *uvc = (struct usb_uvc *)zalloc(sizeof(struct usb_uvc));
|
|
if (!uvc) {
|
|
log_error("err no mem in usb_uvc_parser\n\n");
|
|
len = -DEV_ERR_INVALID_BUF;
|
|
goto __err;
|
|
}
|
|
uvc->bfh = 0;
|
|
uvc->cur_frame = 1;
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
|
|
while (loop) {
|
|
cur_len = *(pBuf + len);
|
|
cur_type = *(pBuf + len + 1);
|
|
cur_sub_type = *(pBuf + len + 2);
|
|
|
|
if (!cur_len) {
|
|
break;
|
|
}
|
|
/* log_debug_hexdump(pBuf + len, cur_len); */
|
|
|
|
if (cur_type == USB_DT_INTERFACE_ASSOCIATION) {
|
|
if (*(pBuf + len + 4) != USB_CLASS_VIDEO ||
|
|
*(pBuf + len + 5) != UVC_SC_VIDEO_INTERFACE_COLLECTION) {
|
|
break;
|
|
}
|
|
// composite device
|
|
log_debug("USB_DT_INTERFACE_ASSOCIATION");
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
if (++assocition_num >= 1) {
|
|
//有2个uvc设备
|
|
break;
|
|
}
|
|
} else if (cur_type == USB_DT_INTERFACE) {
|
|
if (cur_len != USB_DT_INTERFACE_SIZE) {
|
|
len = -USB_DT_INTERFACE;
|
|
goto __err;
|
|
}
|
|
if (*(pBuf + len + 5) != USB_CLASS_VIDEO) {
|
|
break;
|
|
}
|
|
log_debug("USB_DT_INTERFACE");
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
AlternateSetting = *(pBuf + len + 3);
|
|
log_debug("AlternateSetting:%d", AlternateSetting);
|
|
|
|
if (*(pBuf + len + 6) == UVC_SC_VIDEOCONTROL) {
|
|
ItfSubClass = UVC_SC_VIDEOCONTROL;
|
|
hdl->itf_base = *(pBuf + len + 2);
|
|
} else if (*(pBuf + len + 6) == UVC_SC_VIDEOSTREAMING) {
|
|
ItfSubClass = UVC_SC_VIDEOSTREAMING;
|
|
} else {
|
|
log_error("invalid video subclass");
|
|
len = -USB_DT_INTERFACE;
|
|
goto __err;
|
|
}
|
|
} else if (cur_type == USB_DT_CS_INTERFACE) {
|
|
if (ItfSubClass == UVC_SC_VIDEOCONTROL) {
|
|
switch (cur_sub_type) {
|
|
case UVC_VC_HEADER:
|
|
log_debug("VC_HEADER:%d %d, uvc ver %02x%02x", len, *(pBuf + len), *(pBuf + len + 4), *(pBuf + len + 3));
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
case UVC_VC_INPUT_TERMINAL:
|
|
bControlSize = *(pBuf + len + 14);
|
|
log_debug("VC_INPUT_TERMINAL:%d %d %d", len, *(pBuf + len), bControlSize);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
case UVC_VC_PROCESSING_UNIT:
|
|
bControlSize = *(pBuf + len + 7);
|
|
log_debug("VC_PROCESSING_UNIT:%d %d %d", len, *(pBuf + len), bControlSize);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
case UVC_VC_OUTPUT_TERMINAL:
|
|
bControlSize = *(pBuf + len + 8);
|
|
log_debug("VC_OUTPUT_TERMINAL:%d %d %d", len, *(pBuf + len), bControlSize);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
case UVC_VC_SELECTOR_UNIT:
|
|
break;
|
|
|
|
case UVC_VC_EXTENSION_UNIT:
|
|
bControlSize = *(pBuf + len + 20);
|
|
log_debug("VC_EXTENSION_UNIT:%d %d %d %d",
|
|
len,
|
|
*(pBuf + len),
|
|
bControlSize,
|
|
*(pBuf + len + 22 + bControlSize));
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
default :
|
|
log_debug("Unrecognized VC UNIT:%d %d", len, *(pBuf + len));
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
}
|
|
} else if (ItfSubClass == UVC_SC_VIDEOSTREAMING) {
|
|
switch (cur_sub_type) {
|
|
case UVC_VS_INPUT_HEADER:
|
|
formart_num = *(pBuf + len + 3);
|
|
bControlSize = *(pBuf + len + 12);
|
|
memcpy(&wTotalLength, pBuf + len + 4, 2);
|
|
log_debug("VS_INPUT_HEADER:%d %d %d",
|
|
wTotalLength,
|
|
formart_num,
|
|
bControlSize);
|
|
log_debug_hexdump(pBuf + len, *(pBuf + len));
|
|
wTotalLength -= *(pBuf + len);
|
|
break;
|
|
|
|
case UVC_VS_FORMAT_MJPEG:
|
|
format_support = UVC_SUPPORT_MJEPG_ENABLE;
|
|
pformat = pBuf + len;
|
|
frame_num = pformat[4];
|
|
uvc->mjpeg_format_index = pformat[3];
|
|
wTotalLength -= pformat[0];
|
|
uvc->format += UVC_VS_FORMAT_MJPEG;
|
|
log_debug("find mjpeg format descriptor %d %d %d",
|
|
frame_num,
|
|
pformat[3],
|
|
wTotalLength);
|
|
log_debug_hexdump(pformat, pformat[0]);
|
|
uvc->cur_frame = pformat[6];
|
|
log_debug("default frame id %d", uvc->cur_frame);
|
|
pformat += pformat[0];
|
|
uvc->reso_num = frame_num;
|
|
real_uvc = (struct usb_uvc *)zalloc(sizeof(struct usb_uvc) + sizeof(struct uvc_frame_info) * (1 + frame_num));
|
|
if (!real_uvc) {
|
|
log_error("err no mem in usb_uvc_parser\n\n");
|
|
len = -DEV_ERR_INVALID_BUF;
|
|
goto __err;
|
|
}
|
|
for (int i = 0; i < frame_num; i++) {
|
|
memcpy(&real_uvc->pframe[i].width, &pformat[5], 2);
|
|
memcpy(&real_uvc->pframe[i].height, &pformat[7], 2);
|
|
log_debug("frame info %d %d x %d",
|
|
1 + i,
|
|
real_uvc->pframe[i].width,
|
|
real_uvc->pframe[i].height);
|
|
log_debug_hexdump(pformat, pformat[0]);
|
|
u32 f_interval = 0;
|
|
u32 f_interval_step = 0;
|
|
memcpy(&f_interval, pformat + 21, 4);
|
|
log_debug("default frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
uvc->fps = (f_interval ? (10000000 / f_interval) : 0);
|
|
if (pformat[25] == 0) {
|
|
memcpy(&f_interval, pformat + 26, 4);
|
|
log_debug("min frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
memcpy(&f_interval, pformat + 30, 4);
|
|
log_debug("max frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
memcpy(&f_interval_step, pformat + 34, 4);
|
|
log_debug("frame interval step %d, fps step %d", f_interval_step,
|
|
f_interval_step ? (10000000 / f_interval_step) : 0);
|
|
} else {
|
|
for (int icnt = 0; icnt < pformat[25]; icnt++) {
|
|
memcpy(&f_interval, pformat + 26 + 4 * icnt, 4);
|
|
log_debug("frame interval %d %d, fps %d", icnt, f_interval, 10000000 / f_interval);
|
|
}
|
|
}
|
|
wTotalLength -= pformat[0];
|
|
cur_len += pformat[0];
|
|
pformat += pformat[0];
|
|
}
|
|
break;
|
|
|
|
case UVC_VS_FORMAT_UNCOMPRESSED:
|
|
format_support = UVC_SUPPORT_YUYV_ENABLE;
|
|
pformat = pBuf + len;
|
|
frame_num = pformat[4];
|
|
uvc->yuyv_format_index = pformat[3];
|
|
wTotalLength -= pformat[0];
|
|
uvc->format += UVC_VS_FORMAT_UNCOMPRESSED;
|
|
log_debug("find yuy2 frame descriptor %d %d %d",
|
|
frame_num,
|
|
pformat[3],
|
|
wTotalLength);
|
|
pformat += pformat[0];
|
|
uvc->reso_num = frame_num;
|
|
real_uvc = (struct usb_uvc *)malloc(sizeof(struct usb_uvc) + sizeof(struct uvc_frame_info) * (1 + frame_num));
|
|
memset(real_uvc, 0, sizeof(struct usb_uvc) + sizeof(struct uvc_frame_info) * (1 + frame_num));
|
|
for (int i = 0; i < frame_num; i++) {
|
|
/* u16 width, heigth; */
|
|
/* memcpy(&width, &pformat[5], 2); */
|
|
/* memcpy(&heigth, &pformat[7], 2); */
|
|
/* log_debug("frame info %d %d*%d", 1 + i, width, */
|
|
/* heigth); */
|
|
memcpy(&real_uvc->pframe[i].width, &pformat[5], 2);
|
|
memcpy(&real_uvc->pframe[i].height, &pformat[7], 2);
|
|
log_debug("frame info %d %d*%d", 1 + i, real_uvc->pframe[i].width,
|
|
real_uvc->pframe[i].height);
|
|
if ((real_uvc->pframe[i].width == 1280) &&
|
|
(real_uvc->pframe[i].height == 720)) {
|
|
uvc->cur_frame = i + 1;
|
|
} else if ((real_uvc->pframe[i].width == 640) &&
|
|
(real_uvc->pframe[i].height == 480)) {
|
|
uvc->cur_frame = i + 1;
|
|
}
|
|
wTotalLength -= pformat[0];
|
|
cur_len += pformat[0];
|
|
pformat += pformat[0];
|
|
}
|
|
break;
|
|
|
|
case UVC_VS_STILL_IMAGE_FRAME:
|
|
wTotalLength -= cur_len;
|
|
log_debug("find still image format descriptor %d", wTotalLength);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
case UVC_VS_FORMAT_FRAME_BASED:
|
|
format_support = UVC_SUPPORT_H264_ENABLE;
|
|
pformat = pBuf + len;
|
|
frame_num = pformat[4];
|
|
uvc->h264_format_index = pformat[3];
|
|
wTotalLength -= pformat[0];
|
|
uvc->format += UVC_VS_FORMAT_FRAME_BASED;
|
|
log_debug("find format frame base descriptor %d %d %d",
|
|
frame_num,
|
|
pformat[3],
|
|
wTotalLength);
|
|
log_debug_hexdump(pformat, pformat[0]);
|
|
uvc->cur_frame = pformat[6];
|
|
log_debug("default frame id %d", uvc->cur_frame);
|
|
pformat += pformat[0];
|
|
uvc->reso_num = frame_num;
|
|
real_uvc = (struct usb_uvc *)zalloc(sizeof(struct usb_uvc) + sizeof(struct uvc_frame_info) * (1 + frame_num));
|
|
if (!real_uvc) {
|
|
log_error("err no mem in usb_uvc_parser\n\n");
|
|
len = -DEV_ERR_INVALID_BUF;
|
|
goto __err;
|
|
}
|
|
for (int i = 0; i < frame_num; i++) {
|
|
memcpy(&real_uvc->pframe[i].width, &pformat[5], 2);
|
|
memcpy(&real_uvc->pframe[i].height, &pformat[7], 2);
|
|
log_debug("frame info %d %d x %d",
|
|
1 + i,
|
|
real_uvc->pframe[i].width,
|
|
real_uvc->pframe[i].height);
|
|
log_debug_hexdump(pformat, pformat[0]);
|
|
u32 f_interval = 0;
|
|
u32 f_interval_step = 0;
|
|
memcpy(&f_interval, pformat + 21, 4);
|
|
log_debug("default frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
uvc->fps = (f_interval ? (10000000 / f_interval) : 0);
|
|
if (pformat[25] == 0) {
|
|
memcpy(&f_interval, pformat + 26, 4);
|
|
log_debug("min frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
memcpy(&f_interval, pformat + 30, 4);
|
|
log_debug("max frame interval %d, fps %d", f_interval, 10000000 / f_interval);
|
|
memcpy(&f_interval_step, pformat + 34, 4);
|
|
log_debug("frame interval step %d, fps step %d", f_interval_step,
|
|
f_interval_step ? (10000000 / f_interval_step) : 0);
|
|
} else {
|
|
for (int icnt = 0; icnt < pformat[25]; icnt++) {
|
|
memcpy(&f_interval, pformat + 26 + 4 * icnt, 4);
|
|
log_debug("frame interval %d %d, fps %d", icnt, f_interval, 10000000 / f_interval);
|
|
}
|
|
}
|
|
wTotalLength -= pformat[0];
|
|
cur_len += pformat[0];
|
|
pformat += pformat[0];
|
|
}
|
|
break;
|
|
|
|
case UVC_VS_COLORFORMAT:
|
|
wTotalLength -= cur_len;
|
|
log_debug("find colorformat descriptor %d", wTotalLength);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
|
|
default:
|
|
wTotalLength -= cur_len;
|
|
log_debug("unrecognized vs descriptor %d", wTotalLength);
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
break;
|
|
}
|
|
}
|
|
} else if (cur_type == USB_DT_CS_ENDPOINT) {
|
|
if (cur_len != 5) {
|
|
len = -USB_DT_CS_ENDPOINT;
|
|
goto __err;
|
|
}
|
|
|
|
log_debug("USB_DT_CS_ENDPOINT");
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
} else if (cur_type == USB_DT_ENDPOINT) {
|
|
if (cur_len != USB_DT_ENDPOINT_SIZE) {
|
|
len = -USB_DT_ENDPOINT;
|
|
goto __err;
|
|
}
|
|
|
|
log_debug("USB_DT_ENDPOINT");
|
|
log_debug_hexdump(pBuf + len, cur_len);
|
|
memcpy(&end_desc, pBuf + len, USB_DT_ENDPOINT_SIZE);
|
|
|
|
if (end_desc.bEndpointAddress & USB_DIR_IN) {
|
|
log_debug("Endpoint IN %x", end_desc.bEndpointAddress);
|
|
} else {
|
|
log_debug("Endpoint OUT %x", end_desc.bEndpointAddress);
|
|
}
|
|
|
|
log_debug("wMaxPacketSize = %d, %d additional transaction", end_desc.wMaxPacketSize & 0x7ff, end_desc.wMaxPacketSize >> 11);
|
|
|
|
if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
|
|
log_debug(">>>>>XFER_BULK\n");
|
|
} else if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
|
|
log_debug(">>>>>XFER_INT = %d\n", end_desc.bInterval);
|
|
int_ep = 1;
|
|
} else if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) {
|
|
log_debug(">>>>>XFER_ISOC = %d\n", end_desc.bInterval);
|
|
} else if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_CONTROL) {
|
|
log_debug(">>>>>XFER_CONTROL\n");
|
|
}
|
|
|
|
if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) {
|
|
uvc->int_ep.epin = end_desc.bEndpointAddress & 0x0f;
|
|
uvc->int_ep.interval = end_desc.bInterval;
|
|
uvc->int_ep.wMaxPacketSize = end_desc.wMaxPacketSize;
|
|
uvc->int_ep.enable = 1;
|
|
} else if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) {
|
|
if (end_desc.wMaxPacketSize > wMaxPacketSize) {
|
|
wMaxPacketSize = end_desc.wMaxPacketSize;
|
|
uvc->ep = end_desc.bEndpointAddress & 0x0f;
|
|
uvc->wMaxPacketSize = end_desc.wMaxPacketSize;
|
|
uvc->interval = end_desc.bInterval;
|
|
uvc->if_alt_num = AlternateSetting;
|
|
uvc->xfer_type = USB_ENDPOINT_XFER_ISOC;
|
|
}
|
|
} else if ((end_desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
|
|
if (end_desc.wMaxPacketSize > wMaxPacketSize) {
|
|
wMaxPacketSize = end_desc.wMaxPacketSize;
|
|
uvc->ep = end_desc.bEndpointAddress & 0x0f;
|
|
uvc->wMaxPacketSize = end_desc.wMaxPacketSize;
|
|
uvc->interval = end_desc.bInterval;
|
|
uvc->if_alt_num = AlternateSetting;
|
|
uvc->xfer_type = USB_ENDPOINT_XFER_BULK;
|
|
}
|
|
}
|
|
/*log_d("=======[%s - %d] >>>> \nif_alt_num : %d\ninterval : %d\nwMaxPacketSize : %d\n", __FUNCTION__,*/
|
|
/*__LINE__, AlternateSetting, end_desc.bInterval, end_desc.wMaxPacketSize);*/
|
|
} else {
|
|
log_error("error %x", len);
|
|
log_debug_hexdump(pBuf + len, 16);
|
|
loop = 0;
|
|
cur_len = 0;
|
|
}
|
|
len += cur_len;
|
|
}
|
|
|
|
|
|
if (real_uvc) {
|
|
memcpy(real_uvc, uvc, sizeof(*uvc));
|
|
}
|
|
free(uvc);
|
|
uvc = NULL;
|
|
#if 1
|
|
struct usb_uvc *uvc_old = uvc_host_inf[usb_id].dev.uvc;
|
|
if (!format_support && uvc_old) {
|
|
uvc_old->ep = real_uvc->ep;
|
|
if (real_uvc) {
|
|
free(real_uvc);
|
|
}
|
|
} else {
|
|
uvc_host_inf[usb_id].dev.uvc = real_uvc;
|
|
}
|
|
/* struct usb_uvc *pu = uvc_host_inf[usb_id].dev.uvc; */
|
|
/* printf("%s %d host_ep:%d ep:%d if_alt_num:%d fps:%d bfh:%d error_frame:%d cur_frame:%d mjpeg:%d yuyv:%d h264:%d reso_num:%d camera_open:%d xfer_type:%d ep_buf_ch:%d format:%d", __func__, __LINE__, pu->host_ep, pu->ep, pu->if_alt_num, pu->fps, pu->bfh, pu->error_frame, pu->cur_frame, pu->mjpeg_format_index, pu->yuyv_format_index, pu->h264_format_index, pu->reso_num, pu->camera_open, pu->xfer_type, pu->ep_buf_ch, pu->format); */
|
|
#else
|
|
uvc_host_inf[usb_id].dev.uvc = real_uvc;
|
|
#endif
|
|
host_dev->interface_info[interface_num] = &uvc_host_inf[usb_id];
|
|
hdl->dev.private_data = host_dev;
|
|
hdl->name = usb_id ? "uvc1" : "uvc0";
|
|
hdl->frame_cnt = 0;
|
|
|
|
return len;
|
|
|
|
__err:
|
|
log_error("error in usb_uvc_parser");
|
|
if (real_uvc) {
|
|
free(real_uvc);
|
|
real_uvc = NULL;
|
|
}
|
|
if (uvc) {
|
|
free(uvc);
|
|
uvc = NULL;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
#define USB_GET_REQ (USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|
|
#define USB_SET_REQ (USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|
|
|
|
int uvc_host_get_backlight_compensation(void *fd, u32 *iostatus)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
s32 ret;
|
|
u32 tmp_buf = 0;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
usb_dev usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
//PU_BACKLIGHT_COMPENSATION_CONTROL
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, 0x0100, (0x02 << 8) | hdl->itf_base, (u8 *)&tmp_buf, 2);
|
|
memcpy(iostatus, &tmp_buf, 4);
|
|
/* log_debug("%x", *iostatus); */
|
|
check_ret(ret);
|
|
return DEV_ERR_NONE;
|
|
}
|
|
|
|
int uvc_host_req_processing_unit(void *fd, struct uvc_processing_unit *pu)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
int err = 0;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
|
|
err = usb_control_msg(host_dev, pu->request, pu->type, pu->value, pu->index, (u8 *)pu->buf, pu->len);
|
|
|
|
return err;
|
|
}
|
|
|
|
static u8 Video_Probe_Commit_Control[26] = {
|
|
0x00, 0x00, //bmHint
|
|
0x01, //FormatIndex
|
|
0x01, //FrameIndex
|
|
DW1BYTE(FRAME_FPS_0), DW2BYTE(FRAME_FPS_0), DW3BYTE(FRAME_FPS_0), DW4BYTE(FRAME_FPS_0), //dwFrameInterval Frame interval in 100 ns units.
|
|
0x00, 0x00, //KeyFrameRate
|
|
0x00, 0x00, //PFrameRate
|
|
0x00, 0x27, //CompQuanlity
|
|
0x00, 0x00, //CompWindowsSize
|
|
0x00, 0x00, //0x32,0x00, //Delay
|
|
DW1BYTE(300 * 1024), DW2BYTE(300 * 1024), DW3BYTE(300 * 1024), DW4BYTE(300 * 1024), //MaxVideoFrameSize
|
|
LOBYTE(512), HIBYTE(512), 0x00, 0x00, //MaxPayLoadTransferSize
|
|
};
|
|
|
|
static u32 StreamInterfaceNum_get_cur(struct device *device, u16 id)
|
|
{
|
|
u32 ret;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
usb_dev usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
id = cpu_to_be16(id);
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, id, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
//log_debug("%s:%x\n",__FUNCTION__,id);
|
|
check_ret(ret);
|
|
return DEV_ERR_NONE;
|
|
}
|
|
static u32 StreamInterfaceNum_set_cur(struct device *device, u16 id)
|
|
{
|
|
u32 ret;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
usb_dev usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
if (!uvc) {
|
|
return -1;
|
|
}
|
|
id = cpu_to_be16(id);
|
|
Video_Probe_Commit_Control[2] = uvc->mjpeg_format_index;
|
|
Video_Probe_Commit_Control[3] = uvc->cur_frame;
|
|
log_debug("%s:mjpeg_fmt_idx:%x cur_frame:%x\n", __func__, uvc->mjpeg_format_index, uvc->cur_frame);
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, id, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
//log_debug("%s:%x\n",__FUNCTION__,usb_id);
|
|
check_ret(ret);
|
|
return DEV_ERR_NONE;
|
|
}
|
|
static void Stream_head_analysis(u8 *rx_addr)
|
|
{
|
|
#if 0
|
|
u32 frame_cnt = 0, scr = 0;
|
|
u16 sof_count = 0;
|
|
/// Stream Head
|
|
rx_addr[0x00] = 0x0C;//Head Length
|
|
rx_addr[0x01] = hdr->bfh_val; //BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
|
|
/* rx_addr[0x1] &= ~(BIT(2) | BIT(3) | BIT(5) | BIT(6)); */
|
|
frame_cnt = hdr->frame_cnt;
|
|
rx_addr[0x02] = frame_cnt ;//PTS[7:0]
|
|
rx_addr[0x03] = (frame_cnt >> 8); //PTS[15:8]
|
|
rx_addr[0x04] = (frame_cnt >> 16) ; //PTS[23:16]
|
|
rx_addr[0x05] = (frame_cnt >> 24) ; //PTS[31:24]
|
|
scr = hdr->scr;
|
|
rx_addr[0x06] = DW1BYTE(scr);//SCR[7:0]
|
|
rx_addr[0x07] = DW2BYTE(scr);//SCR[15:8]
|
|
rx_addr[0x08] = DW3BYTE(scr);//SCR[23:16]
|
|
rx_addr[0x09] = DW4BYTE(scr);//SCR[31:24]
|
|
sof_count = hdr->sof_cnt;
|
|
rx_addr[0x0A] = LOBYTE(sof_count); //SCR[42:32] 1KHz SOF token counter
|
|
rx_addr[0x0B] = HIBYTE(sof_count); //SCR[47:42] res set to 0.
|
|
#endif
|
|
}
|
|
|
|
static struct uvc_stream_list uvc_global_l[USB_MAX_HW_NUM][ISO_INTR_CNT];
|
|
|
|
static void vs_iso_handler(struct usb_host_device *host_dev, u32 ep)
|
|
{
|
|
usb_dev usb_id;
|
|
int rx_len;
|
|
u8 *start_addr;
|
|
u8 error_flag;
|
|
/* u8 stream_state = 0; */
|
|
u32 maxpsize;
|
|
static u32 trans_err_cnt[USB_MAX_HW_NUM] = {0};
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return;
|
|
}
|
|
uvc = device_to_uvc(device);
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
//fix 连续拔插
|
|
if (!hdl->open) {
|
|
return;
|
|
}
|
|
hdl->in_irq = 1;
|
|
maxpsize = (uvc->wMaxPacketSize & 0x7ff) * (((uvc->wMaxPacketSize >> 11) & 0x3) + 1);
|
|
rx_len = usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, hdl->buffer, maxpsize, USB_ENDPOINT_XFER_ISOC, 0);
|
|
if (rx_len < 0) {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
trans_err_cnt[usb_id]++;
|
|
if (trans_err_cnt[usb_id] >= 1000) {
|
|
trans_err_cnt[usb_id] = 0;
|
|
usb_host_force_reset(usb_id);
|
|
}
|
|
} else {
|
|
trans_err_cnt[usb_id] = 0;
|
|
}
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1);
|
|
start_addr = hdl->buffer;
|
|
struct uvc_stream_list *uvc_list = uvc_global_l[usb_id];
|
|
if (rx_len > 0 && rx_len > start_addr[0]) {
|
|
rx_len -= start_addr[0];
|
|
error_flag = start_addr[1];
|
|
/* if (!uvc->error_frame) { */
|
|
uvc_list->addr = start_addr + start_addr[0];
|
|
uvc_list->length = rx_len;
|
|
/* } */
|
|
if (start_addr[0] != 0x0c && start_addr[0] != 0x02) {
|
|
log_error("start_addr = %x", start_addr[0]);
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
}
|
|
//BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
|
|
if ((error_flag & BIT(6)) && uvc->error_frame == 0) {
|
|
log_error("stream_err");
|
|
uvc->error_frame = 1;
|
|
//send_error_info
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
}
|
|
if (error_flag & BIT(1)) { //endof frame
|
|
if (!uvc->error_frame) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_EOF);
|
|
/* stream_state = STREAM_EOF; */
|
|
hdl->frame_cnt++;
|
|
}
|
|
}
|
|
uvc->error_frame = 0;//clear error_frame pending
|
|
} else {
|
|
if (!uvc->error_frame) {
|
|
if (uvc->bfh != (error_flag & BIT(0))) { //new frame
|
|
uvc->bfh = error_flag & BIT(0);//clear error_frame pending
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_SOF);
|
|
/* stream_state = STREAM_SOF; */
|
|
}
|
|
} else {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_NO_ERR);
|
|
/* stream_state = STREAM_NO_ERR; */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hdl->in_irq = 0;
|
|
}
|
|
static void vs_iso_burst_handler(struct usb_host_device *host_dev, u32 ep)
|
|
{
|
|
#if ISO_INTR_MODE == 2
|
|
|
|
usb_dev usb_id;
|
|
int rx_len;
|
|
int total_rx_len;
|
|
u8 *start_addr;
|
|
u8 error_flag;
|
|
/* u8 stream_state = 0; */
|
|
u32 maxpsize;
|
|
u32 rlen_table[8];
|
|
u32 uvc_pos = 0;
|
|
u32 valid_cnt = 0;
|
|
static u32 trans_err_cnt[USB_MAX_HW_NUM] = {0};
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return;
|
|
}
|
|
uvc = device_to_uvc(device);
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
hdl->in_irq = 1;
|
|
maxpsize = (uvc->wMaxPacketSize & 0x7ff) * (((uvc->wMaxPacketSize >> 11) & 0x3) + 1);
|
|
total_rx_len = usb_h_ep_burst_read_async(usb_id, uvc->host_ep, uvc->ep, ISO_INTR_CNT, rlen_table, hdl->buffer, maxpsize * ISO_INTR_CNT, USB_ENDPOINT_XFER_ISOC, 0);
|
|
if (total_rx_len < 0) {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
trans_err_cnt[usb_id]++;
|
|
if (trans_err_cnt[usb_id] >= 1000) {
|
|
trans_err_cnt[usb_id] = 0;
|
|
usb_host_force_reset(usb_id);
|
|
}
|
|
} else {
|
|
trans_err_cnt[usb_id] = 0;
|
|
/* printf("total_len %d\n", total_rx_len); */
|
|
/* printf_buf(hdl->buffer, total_rx_len); */
|
|
}
|
|
//触发下一次接收
|
|
usb_h_ep_burst_read_async(usb_id, uvc->host_ep, uvc->ep, 0, NULL, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1);
|
|
start_addr = hdl->buffer;
|
|
struct uvc_stream_list *uvc_list = uvc_global_l[usb_id];
|
|
if (total_rx_len > 0) {
|
|
for (int i = 0; i < ISO_INTR_CNT; i++) {
|
|
rx_len = rlen_table[i];
|
|
/* printf("r %d\n", rx_len); */
|
|
/* printf_buf(start_addr, rx_len); */
|
|
if (rx_len > start_addr[0]) {
|
|
rx_len -= start_addr[0];
|
|
} else {
|
|
/* start_addr += rx_len; */
|
|
start_addr += (rx_len + 3) / 4 * 4;
|
|
continue;
|
|
}
|
|
error_flag = start_addr[1];
|
|
if (!uvc->error_frame) {
|
|
uvc_list[uvc_pos + valid_cnt].addr = start_addr + start_addr[0];
|
|
uvc_list[uvc_pos + valid_cnt].length = rx_len;
|
|
valid_cnt++;
|
|
}
|
|
if (start_addr[0] != 0x0c && start_addr[0] != 0x02) {
|
|
log_error("start_addr = %x", start_addr[0]);
|
|
uvc->error_frame = 1;
|
|
valid_cnt = 0;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
}
|
|
//BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
|
|
if ((error_flag & BIT(6)) && uvc->error_frame == 0) {
|
|
log_error("stream_err");
|
|
uvc->error_frame = 1;
|
|
valid_cnt = 0;
|
|
//send_error_info
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
}
|
|
if (error_flag & BIT(1)) { //endof frame
|
|
if (!uvc->error_frame) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, valid_cnt, &uvc_list[uvc_pos], STREAM_EOF);
|
|
/* stream_state = STREAM_EOF; */
|
|
hdl->frame_cnt++;
|
|
uvc_pos += valid_cnt;
|
|
}
|
|
}
|
|
valid_cnt = 0;
|
|
uvc->error_frame = 0;//clear error_frame pending
|
|
}
|
|
if (uvc->bfh != (error_flag & BIT(0))) { //new frame
|
|
uvc->bfh = error_flag & BIT(0);//clear error_frame pending
|
|
if (!uvc->error_frame) {
|
|
uvc_pos += (valid_cnt - 1);
|
|
valid_cnt = 1;
|
|
} else {
|
|
uvc_pos += valid_cnt;
|
|
valid_cnt = 0;
|
|
}
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_SOF);
|
|
/* stream_state = STREAM_SOF; */
|
|
}
|
|
uvc->error_frame = 0;//clear error_frame pending
|
|
}
|
|
|
|
start_addr += rx_len + start_addr[0];
|
|
}
|
|
if (!uvc->error_frame && valid_cnt) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, valid_cnt, &uvc_list[uvc_pos], STREAM_NO_ERR);
|
|
/* stream_state = STREAM_NO_ERR; */
|
|
}
|
|
}
|
|
}
|
|
hdl->in_irq = 0;
|
|
#endif
|
|
}
|
|
static void vs_bulk_handler(struct usb_host_device *host_dev, u32 ep)
|
|
{
|
|
usb_dev usb_id;
|
|
u8 _header;
|
|
int rx_len;
|
|
u8 *start_addr;
|
|
u8 error_flag;
|
|
/* u8 stream_state = 0; */
|
|
u8 *last_buf;
|
|
static u32 trans_err_cnt[USB_MAX_HW_NUM] = {0};
|
|
static u32 last_len[USB_MAX_HW_NUM];
|
|
static u32 frame_len[USB_MAX_HW_NUM];
|
|
u32 maxpsize;
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return;
|
|
}
|
|
uvc = device_to_uvc(device);
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
hdl->in_irq = 1;
|
|
maxpsize = (uvc->wMaxPacketSize & 0x7ff) * (((uvc->wMaxPacketSize >> 11) & 0x3) + 1);
|
|
rx_len = usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, hdl->buffer, maxpsize, USB_ENDPOINT_XFER_BULK, 0);//异步读取当前数据包
|
|
if (rx_len < 0) {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
trans_err_cnt[usb_id]++;
|
|
if (trans_err_cnt[usb_id] >= 1000) {
|
|
trans_err_cnt[usb_id] = 0;
|
|
usb_host_force_reset(usb_id);
|
|
}
|
|
} else {
|
|
trans_err_cnt[usb_id] = 0;
|
|
}
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);//请求下个数据包
|
|
start_addr = hdl->buffer;
|
|
struct uvc_stream_list *uvc_list = uvc_global_l[usb_id];
|
|
if (rx_len > 0) {
|
|
_header = 0;
|
|
last_buf = &hdl->buffer[maxpsize];
|
|
//BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
|
|
if (start_addr[0] == 0x0c) {
|
|
if ((start_addr[1] & 0x8c) == 0x8c || (start_addr[1] & 0x8c) == 0x80) {
|
|
if (start_addr[0x0c] == 0xff && start_addr[0x0d] == 0xd8) {
|
|
_header = 1;
|
|
}
|
|
if (*(u32 *)(&start_addr[0x0c]) == 0x1000000) {
|
|
_header = 1;
|
|
}
|
|
} else if (start_addr[1] == 0x02 || start_addr[1] == 0x03) {
|
|
if (*(u32 *)(&start_addr[0x0c]) == 0x1000000) {
|
|
_header = 1;
|
|
}
|
|
}
|
|
} else if (start_addr[0] == 0x02) {
|
|
if ((start_addr[1] & 0x8c) == 0x80) {
|
|
if (start_addr[0x02] == 0xff && start_addr[0x03] == 0xd8) {
|
|
_header = 1;
|
|
}
|
|
}
|
|
}
|
|
if (_header) {
|
|
if (rx_len >= start_addr[0]) {
|
|
rx_len -= start_addr[0];
|
|
}
|
|
/* log_debug_hexdump(start_addr, rx_len + start_addr[0]); */
|
|
uvc_list->addr = start_addr + start_addr[0];
|
|
uvc_list->length = rx_len;
|
|
error_flag = start_addr[1];
|
|
if ((error_flag & BIT(6)) && (uvc->error_frame == 0)) {
|
|
frame_len[usb_id] = 0;
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
}
|
|
if (uvc->bfh != (error_flag & BIT(0))) { //new frame
|
|
uvc->bfh = error_flag & BIT(0);//clear error_frame pending
|
|
if (last_len[usb_id] >= 2 &&
|
|
last_buf[last_len[usb_id] - 2] == 0xff &&
|
|
last_buf[last_len[usb_id] - 1] == 0xd9) {
|
|
if (!uvc->error_frame) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 0, uvc_list, STREAM_EOF);
|
|
/* stream_state = STREAM_EOF; */
|
|
hdl->frame_cnt++;
|
|
}
|
|
//log_info("frame_len[usb_id] %u", frame_len[usb_id]);
|
|
}
|
|
|
|
/* puts(" new\n"); */
|
|
if (uvc_list->length) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_SOF);
|
|
/* stream_state = STREAM_SOF; */
|
|
}
|
|
uvc->error_frame = 0;
|
|
frame_len[usb_id] = rx_len;
|
|
}
|
|
} else {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
frame_len[usb_id] = 0;
|
|
}
|
|
}
|
|
last_len[usb_id] = rx_len;
|
|
memcpy(last_buf, start_addr + start_addr[0], rx_len);
|
|
} else {
|
|
uvc_list->addr = start_addr;
|
|
uvc_list->length = rx_len;
|
|
if (!uvc->error_frame) {
|
|
/* log_debug_hexdump(start_addr, rx_len); */
|
|
if (uvc->stream_out) {//进入一帧数据回调函数
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_NO_ERR);
|
|
/* stream_state = STREAM_NO_ERR; */
|
|
}
|
|
frame_len[usb_id] += rx_len;
|
|
}
|
|
last_len[usb_id] = rx_len;
|
|
memcpy(last_buf, start_addr, rx_len);
|
|
}
|
|
}
|
|
hdl->in_irq = 0;
|
|
}
|
|
|
|
/**
|
|
* @brief uvc bulk 第2路接收
|
|
* usb0 bulk将走这个函数,usb1上的第2路uvc设备接收也会走这个函数
|
|
*
|
|
* @param: host_dev: usb句柄
|
|
* @param: ep: 接收端点
|
|
*
|
|
* @return: null
|
|
**/
|
|
static void vs_bulk_handler2(struct usb_host_device *host_dev, u32 ep)
|
|
{
|
|
usb_dev usb_id;
|
|
u8 _header;
|
|
int rx_len;
|
|
u8 *start_addr;
|
|
u8 error_flag;
|
|
/* u8 stream_state = 0; */
|
|
u8 *last_buf;
|
|
static u32 trans_err_cnt[USB_MAX_HW_NUM] = {0};
|
|
static u32 last_len[USB_MAX_HW_NUM];
|
|
static u32 frame_len[USB_MAX_HW_NUM];
|
|
u32 maxpsize;
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
/* putchar('2'); */
|
|
|
|
usb_id = host_device2id(host_dev);
|
|
struct usb_video_manager *hdl = &uvc_manager[0/*usb_id*/];
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return;
|
|
}
|
|
uvc = uvc_host_inf[0].dev.uvc;//device_to_uvc(device);
|
|
if (!host_dev) {
|
|
return;
|
|
}
|
|
hdl->in_irq = 1;
|
|
maxpsize = (uvc->wMaxPacketSize & 0x7ff) * (((uvc->wMaxPacketSize >> 11) & 0x3) + 1);
|
|
rx_len = usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, hdl->buffer, maxpsize, USB_ENDPOINT_XFER_BULK, 0);//异步读取当前数据包
|
|
if (rx_len < 0) {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
}
|
|
trans_err_cnt[usb_id]++;
|
|
if (trans_err_cnt[usb_id] >= 1000) {
|
|
trans_err_cnt[usb_id] = 0;
|
|
usb_host_force_reset(usb_id);
|
|
}
|
|
} else {
|
|
trans_err_cnt[usb_id] = 0;
|
|
}
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);//请求下个数据包
|
|
start_addr = hdl->buffer;
|
|
struct uvc_stream_list *uvc_list = uvc_global_l[0/*usb_id*/];
|
|
if (rx_len > 0) {
|
|
_header = 0;
|
|
last_buf = &hdl->buffer[maxpsize];
|
|
//BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
|
|
if (start_addr[0] == 0x0c) {
|
|
if ((start_addr[1] & 0x8c) == 0x8c || (start_addr[1] & 0x8c) == 0x80) {
|
|
if (start_addr[0x0c] == 0xff && start_addr[0x0d] == 0xd8) {
|
|
_header = 1;
|
|
}
|
|
if (*(u32 *)(&start_addr[0x0c]) == 0x1000000) {
|
|
_header = 1;
|
|
}
|
|
} else if (start_addr[1] == 0x02 || start_addr[1] == 0x03) {
|
|
if (*(u32 *)(&start_addr[0x0c]) == 0x1000000) {
|
|
_header = 1;
|
|
}
|
|
}
|
|
} else if (start_addr[0] == 0x02) {
|
|
if ((start_addr[1] & 0x8c) == 0x80) {
|
|
if (start_addr[0x02] == 0xff && start_addr[0x03] == 0xd8) {
|
|
_header = 1;
|
|
}
|
|
}
|
|
}
|
|
if (_header) {
|
|
if (rx_len >= start_addr[0]) {
|
|
rx_len -= start_addr[0];
|
|
}
|
|
/* log_debug_hexdump(start_addr, rx_len + start_addr[0]); */
|
|
uvc_list->addr = start_addr + start_addr[0];
|
|
uvc_list->length = rx_len;
|
|
error_flag = start_addr[1];
|
|
if ((error_flag & BIT(6)) && (uvc->error_frame == 0)) {
|
|
frame_len[usb_id] = 0;
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
}
|
|
if (uvc->bfh != (error_flag & BIT(0))) { //new frame
|
|
uvc->bfh = error_flag & BIT(0);//clear error_frame pending
|
|
if ((last_len[usb_id] >= 2 &&
|
|
last_buf[last_len[usb_id] - 2] == 0xff &&
|
|
last_buf[last_len[usb_id] - 1] == 0xd9) ||
|
|
((last_len[usb_id] == 1 && last_buf[last_len[usb_id] - 1] == 0xd9)) ||
|
|
(last_len[usb_id] >= 4 && last_buf[last_len[usb_id] - 4] == 0x55 && last_buf[last_len[usb_id] - 3] == 0xAA && last_buf[last_len[usb_id] - 2] == 0x66 && last_buf[last_len[usb_id] - 1] == 0xCC)) {
|
|
if (!uvc->error_frame) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 0, uvc_list, STREAM_EOF);
|
|
/* stream_state = STREAM_EOF; */
|
|
hdl->frame_cnt++;
|
|
}
|
|
//log_info("frame_len[usb_id] %u", frame_len[usb_id]);
|
|
}
|
|
|
|
/* puts(" new\n"); */
|
|
if (uvc_list->length) {
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_SOF);
|
|
/* stream_state = STREAM_SOF; */
|
|
}
|
|
uvc->error_frame = 0;
|
|
frame_len[usb_id] = rx_len;
|
|
}
|
|
} else {
|
|
uvc->error_frame = 1;
|
|
if (uvc->stream_out) {
|
|
uvc->stream_out(uvc->priv, -1, NULL, STREAM_ERR);
|
|
/* stream_state = STREAM_ERR; */
|
|
}
|
|
frame_len[usb_id] = 0;
|
|
}
|
|
}
|
|
last_len[usb_id] = rx_len;
|
|
memcpy(last_buf, start_addr + start_addr[0], rx_len);
|
|
} else {
|
|
uvc_list->addr = start_addr;
|
|
uvc_list->length = rx_len;
|
|
if (!uvc->error_frame) {
|
|
/* log_debug_hexdump(start_addr, rx_len); */
|
|
if (uvc->stream_out) {//进入一帧数据回调函数
|
|
uvc->stream_out(uvc->priv, 1, uvc_list, STREAM_NO_ERR);
|
|
/* stream_state = STREAM_NO_ERR; */
|
|
}
|
|
frame_len[usb_id] += rx_len;
|
|
}
|
|
last_len[usb_id] = rx_len;
|
|
memcpy(last_buf, start_addr, rx_len);
|
|
}
|
|
}
|
|
hdl->in_irq = 0;
|
|
}
|
|
static void usb_intr_config(struct device *device, u8 ep, u8 enable)
|
|
{
|
|
u8 id = usbpriv_to_usbid(usbdev_to_usbpriv(device_to_usbdev(device)));
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (enable) {
|
|
usb_set_intr_rxe(id, ep);
|
|
} else {
|
|
usb_h_set_ep_isr(host_dev, ep, NULL, NULL);
|
|
usb_clr_intr_rxe(id, ep);
|
|
usb_write_rxcsr(id, ep, RXCSRH_ClrDataTog | RXCSRH_FlushFIFO);
|
|
usb_write_rxinterval(id, ep, 0);
|
|
/* usb_write_fifosize(id, ep, 0); */ //默认都没开
|
|
}
|
|
}
|
|
static void iso_ep_rx_init(struct device *device)
|
|
{
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
u8 devnum = host_dev->private_data.devnum;
|
|
|
|
/* usb_write_rxfuncaddr(usb_id, uvc->host_ep, devnum); */
|
|
if (usb_id == 0) {
|
|
usb_h_set_ep_isr(host_dev, uvc->host_ep | USB_DIR_IN, vs_iso_handler, host_dev);
|
|
usb_h_ep_config(usb_id, uvc->host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, uvc->interval, uvc->ep_buffer, uvc->wMaxPacketSize);
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1);
|
|
} else if (usb_id == 1) {
|
|
#if ISO_INTR_MODE == 2
|
|
usb_h_set_ep_isr(host_dev, uvc->host_ep | USB_DIR_IN, vs_iso_burst_handler, host_dev);
|
|
usb_write_fifosize(usb_id, uvc->host_ep, BIT(5) | BIT(4) | BIT(3) | (ISO_INTR_CNT - 1));
|
|
usb_h_ep_config(usb_id, uvc->host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, uvc->interval, uvc->ep_buffer, uvc->wMaxPacketSize);
|
|
usb_h_ep_burst_read_async(usb_id, uvc->host_ep, uvc->ep, 0, NULL, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1);
|
|
#else
|
|
usb_h_set_ep_isr(host_dev, uvc->host_ep | USB_DIR_IN, vs_iso_handler, host_dev);
|
|
usb_h_ep_config(usb_id, uvc->host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, uvc->interval, uvc->ep_buffer, uvc->wMaxPacketSize);
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1);
|
|
#endif
|
|
}
|
|
}
|
|
static void bulk_ep_rx_init(struct device *device)
|
|
{
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
void *bulk_rx_handler = NULL;
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
if (usb_id == 1) {
|
|
bulk_rx_handler = vs_bulk_handler;
|
|
} else {
|
|
bulk_rx_handler = vs_bulk_handler2;
|
|
}
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
|
|
u8 devnum = host_dev->private_data.devnum;
|
|
usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
|
|
/* usb_write_rxfuncaddr(usb_id, uvc->host_ep, devnum); */
|
|
usb_h_set_ep_isr(host_dev, uvc->host_ep | USB_DIR_IN, bulk_rx_handler, host_dev);
|
|
usb_h_ep_config(usb_id, uvc->host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, uvc->interval, uvc->ep_buffer, uvc->wMaxPacketSize);
|
|
usb_h_ep_read_async(usb_id, uvc->host_ep, uvc->ep, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
|
|
}
|
|
|
|
int uvc_host_close_camera(void *fd)
|
|
{
|
|
int ret;
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
struct usb_host_device *host_dev;
|
|
u8 status;
|
|
u32 timeout;
|
|
device = (struct device *)fd;
|
|
if (!device) {
|
|
return DEV_ERR_NONE;
|
|
}
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return DEV_ERR_NONE;
|
|
}
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
uvc = device_to_uvc(device);
|
|
if (!uvc) {
|
|
return DEV_ERR_NONE;
|
|
}
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
status = host_dev_status(host_dev);
|
|
time_get(timeout, 1000);
|
|
|
|
if (uvc->xfer_type == USB_ENDPOINT_XFER_ISOC) {
|
|
#if (STOP_TRANSFER == 0)
|
|
#if CAMERA_CLOSE_BY_IRQ
|
|
while (hdl->in_irq) {
|
|
if (time_out(jiffies, timeout)) {
|
|
log_error("wait uvc exiting isr timeout");
|
|
break;
|
|
}
|
|
}
|
|
usb_intr_config(device, uvc->host_ep, 0);
|
|
#endif
|
|
if (uvc->camera_open) {
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
#endif
|
|
return DEV_ERR_NONE;
|
|
}
|
|
if (status) {
|
|
ret = usb_control_msg(host_dev, USB_REQ_SET_INTERFACE, 0x01, 0, hdl->itf_base + 1, NULL, 0);
|
|
log_debug("USB_REQ_SET_INTERFACE %d to %d", 0x01, 0);
|
|
}
|
|
|
|
#else /*STOP_TRANSFER*/
|
|
if (uvc->camera_open) {
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
#endif
|
|
#if CAMERA_CLOSE_BY_IRQ
|
|
while (hdl->in_irq) {
|
|
if (time_out(jiffies, timeout)) {
|
|
log_error("wait uvc exiting isr timeout");
|
|
break;
|
|
}
|
|
}
|
|
usb_intr_config(device, uvc->host_ep, 0);
|
|
#endif
|
|
if (status) {
|
|
usb_control_msg(host_dev, USB_REQ_SET_INTERFACE, 0x01, 0, hdl->itf_base + 1, NULL, 0);
|
|
log_debug("USB_REQ_SET_INTERFACE %d to %d", 0x01, 0);
|
|
}
|
|
uvc->camera_open = 0;
|
|
}
|
|
#endif
|
|
|
|
} else if (uvc->xfer_type == USB_ENDPOINT_XFER_BULK) {
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
#endif
|
|
while (hdl->in_irq) {
|
|
if (time_out(jiffies, timeout)) {
|
|
log_error("wait uvc exiting isr timeout");
|
|
break;
|
|
}
|
|
}
|
|
usb_intr_config(device, uvc->host_ep, 0);
|
|
uvc->camera_open = 0;
|
|
if (status) {
|
|
//clear endpoint feature, halt endpoint
|
|
ret = usb_control_msg(host_dev, USB_REQ_CLEAR_FEATURE, 0x02, 0, uvc->ep | USB_DIR_IN, NULL, 0);
|
|
log_debug("USB_REQ_CLEAR_FEATURE");
|
|
check_ret(ret);
|
|
|
|
Video_Probe_Commit_Control[0] = 0;
|
|
Video_Probe_Commit_Control[1] = 0;
|
|
Video_Probe_Commit_Control[2] = uvc->mjpeg_format_index;
|
|
Video_Probe_Commit_Control[3] = uvc->cur_frame;
|
|
log_debug("%s:mjpeg_fmt_idx:%x cur_frame:%x\n", __func__, uvc->mjpeg_format_index, uvc->cur_frame);
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
log_debug("Video Probe Control SET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
log_debug("Video Probe Control GET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
log_debug("Video Probe Control SET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
log_debug("Video Probe Control GET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
|
|
u8 tmp_buf[10];
|
|
ret = usb_control_msg(host_dev, UVC_GET_DEF, USB_GET_REQ, 0x1400, (0x01 << 8) | hdl->itf_base, tmp_buf, 0x0a);
|
|
check_ret(ret);
|
|
log_debug("CameraTerminal GET_DEF");
|
|
log_debug_hexdump(tmp_buf, ret);
|
|
|
|
memset(tmp_buf, 0, sizeof(tmp_buf));
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, 0x1400, (0x01 << 8) | hdl->itf_base, tmp_buf, 0x0a);
|
|
check_ret(ret);
|
|
log_debug("CameraTerminal SET_CUR");
|
|
log_debug_hexdump(tmp_buf, ret);
|
|
}
|
|
}
|
|
return DEV_ERR_NONE;
|
|
}
|
|
|
|
static int usb_uvc_info(struct device *device);
|
|
|
|
int uvc_host_open_camera(void *fd)
|
|
{
|
|
u32 ret;
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
struct usb_host_device *host_dev;
|
|
device = (struct device *)fd;
|
|
if (!device) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
/*ret = uvc_host_close_camera(device);*/
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
uvc = device_to_uvc(device);
|
|
if (!uvc) {
|
|
return -DEV_ERR_OFFLINE;
|
|
}
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
|
|
uvc->bfh = 0;
|
|
uvc->error_frame = 1;
|
|
if (uvc->xfer_type == USB_ENDPOINT_XFER_ISOC) {
|
|
log_debug("USB_ENDPOINT_XFER_ISOC\n");
|
|
#if (STOP_TRANSFER == 0)
|
|
if (uvc->camera_open) {
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc->bak_stream_out;
|
|
#endif
|
|
log_debug("warning: UVC ALREADY OPEN\n\n\n");
|
|
return 0;
|
|
}
|
|
usb_uvc_info(device);
|
|
ret = usb_control_msg(host_dev, USB_REQ_SET_INTERFACE, 0x01, uvc->if_alt_num, hdl->itf_base + 1, NULL, 0);
|
|
log_debug("USB_REQ_SET_INTERFACE %d to %d", hdl->itf_base + 1, uvc->if_alt_num);
|
|
check_ret(ret);
|
|
iso_ep_rx_init(device);
|
|
uvc->camera_open = 1;
|
|
#else /*STOP_TRANSFER*/
|
|
if (!uvc->camera_open) {
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc->bak_stream_out;
|
|
#endif
|
|
usb_uvc_info(device);
|
|
ret = usb_control_msg(host_dev, USB_REQ_SET_INTERFACE, 0x01, uvc->if_alt_num, hdl->itf_base + 1, NULL, 0);
|
|
log_debug("USB_REQ_SET_INTERFACE %d to %d", hdl->itf_base + 1, uvc->if_alt_num);
|
|
check_ret(ret);
|
|
iso_ep_rx_init(device);
|
|
uvc->camera_open = 1;
|
|
}
|
|
#endif
|
|
|
|
} else if (uvc->xfer_type == USB_ENDPOINT_XFER_BULK) {
|
|
log_debug("USB_ENDPOINT_XFER_BULK\n");
|
|
usb_uvc_info(device);
|
|
bulk_ep_rx_init(device);
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc->bak_stream_out;
|
|
#endif
|
|
uvc->camera_open = 1;
|
|
}
|
|
log_info("uvc usb open ok");
|
|
return DEV_ERR_NONE;
|
|
}
|
|
|
|
#define USE_HUSB 0
|
|
static int usb_uvc_info(struct device *device)
|
|
{
|
|
#if USE_HUSB
|
|
u8 tmp_Video_Probe_Commit_Control[26] = {
|
|
0x00, 0x00,
|
|
0x02,//1 yuv 2 mjpg
|
|
0x01,//6 1280*720 5 640*360 1 640*480
|
|
0x15, 0x16, 0x05, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x00, 0x00,
|
|
0x20, 0x00,
|
|
0x00, 0x60, 0x09, 0x00,
|
|
0x00, 0x0c, 0x00, 0x00
|
|
};
|
|
StreamInterfaceNum_get_cur(device, 1);
|
|
memcpy(Video_Probe_Commit_Control, tmp_Video_Probe_Commit_Control, 26);
|
|
StreamInterfaceNum_set_cur(device, 1);
|
|
|
|
StreamInterfaceNum_get_cur(device, 1);
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
|
|
memcpy(Video_Probe_Commit_Control, tmp_Video_Probe_Commit_Control, 26);
|
|
StreamInterfaceNum_set_cur(device, 1);
|
|
memcpy(Video_Probe_Commit_Control, tmp_Video_Probe_Commit_Control, 26);
|
|
StreamInterfaceNum_set_cur(device, 2);
|
|
|
|
|
|
//StreamInterfaceNum_get_cur(device,1);
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
#else
|
|
int ret = 0;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -1;
|
|
}
|
|
/* usb_dev usb_id = host_device2id(host_dev); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Probe Control GET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Probe Control SET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_MIN, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Probe Control GET_MIN");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_MAX, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Probe Control GET_MAX");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
ret = usb_control_msg(host_dev, UVC_GET_CUR, USB_GET_REQ, 0x0100, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Probe Control GET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
Video_Probe_Commit_Control[2] = uvc->mjpeg_format_index;
|
|
Video_Probe_Commit_Control[3] = uvc->cur_frame;
|
|
log_debug("%s:mjpeg_fmt_idx:%x cur_frame:%x\n", __func__, uvc->mjpeg_format_index, uvc->cur_frame);
|
|
ret = usb_control_msg(host_dev, UVC_SET_CUR, USB_SET_REQ, 0x0200, hdl->itf_base + 1, Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
log_debug("Video Commit Control SET_CUR");
|
|
log_debug_hexdump(Video_Probe_Commit_Control, sizeof(Video_Probe_Commit_Control));
|
|
check_ret(ret);
|
|
|
|
#endif
|
|
return DEV_ERR_NONE;
|
|
}
|
|
|
|
static void toogle_port()
|
|
{
|
|
|
|
}
|
|
|
|
struct status_packet_format {
|
|
u8 bStatusType;//bit0-3 : 0=Reserved, 1=VideoControl interface, 2 = VideoStreaming interface
|
|
u8 bOriginator;//ID of Teriminal, Unit or Interface
|
|
};
|
|
|
|
struct status_vc_packet {
|
|
u8 bEvent;//0x0 : Control Change , 0x1 - 0xFF : Reserved
|
|
u8 bSelector;//Report the Control Selector of th control that issued the interrupt
|
|
u8 bAttribute;//0x0:Control value change, 0x1:Control info change, 0x2:Control failure change, 0x3-0xff : Reserved
|
|
u8 bValue;//0x0:Equivalent to the result of a GET_CUR request, 0x1:GET_INFO request, 0x2:GET_CUR request on VC_REQUEST_ERROR_CODE_CONTROL
|
|
};
|
|
|
|
struct status_vs_packet {
|
|
u8 bEvent;//0x0:Button Press, 0x1-0xff:Stream Error
|
|
u8 bValue;//Button Press--0x0:button released, 0x1:button pressed
|
|
};
|
|
|
|
void *uvc_host_open(void *arg)
|
|
{
|
|
struct uvc_host_param *info = (struct uvc_host_param *)arg;
|
|
struct usb_uvc *uvc;
|
|
struct device *device;
|
|
struct usb_host_device *host_dev;
|
|
struct usb_video_manager *hdl;
|
|
usb_dev usb_id = 0;
|
|
|
|
device = uvc_host_device_find(info->name);
|
|
if (device) {
|
|
atomic_inc(&(device->ref));
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return NULL;
|
|
}
|
|
|
|
if (info->name) {
|
|
usb_id = info->name[3] - '0';
|
|
/* usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
}
|
|
hdl = &uvc_manager[usb_id];
|
|
if (hdl->open) {
|
|
log_error("uvc host reopen !!!");
|
|
return device;
|
|
}
|
|
uvc = device_to_uvc(device);
|
|
if (uvc) {
|
|
uvc->priv = info->priv;
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
if (!uvc->camera_open) {
|
|
uvc->stream_out = info->uvc_stream_out;
|
|
}
|
|
uvc->bak_stream_out = info->uvc_stream_out;
|
|
#else
|
|
uvc->stream_out = info->uvc_stream_out;
|
|
#endif
|
|
uvc->offline = info->uvc_out;
|
|
}
|
|
hdl->open = 1;
|
|
return device;
|
|
} else {
|
|
log_debug("err uvc_host_open device NULL\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int uvc_host_close(void *fd)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_uvc *uvc;
|
|
struct usb_host_device *host_dev;
|
|
|
|
if (device && (device->private_data != NULL)) {
|
|
if (atomic_dec_and_test(&device->ref)) {
|
|
struct usb_video_manager *hdl = container_of(device, struct usb_video_manager, dev);
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return DEV_ERR_NONE;
|
|
}
|
|
usb_dev usb_id = hdl->name[3] - '0';
|
|
log_info("uvc_host_close %s\n", hdl->name);
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
uvc = device_to_uvc(device);
|
|
if (uvc) {
|
|
/* usb_intr_config(device, uvc->host_ep, 0); */
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->bak_stream_out = uvc_dummy_stream_out;
|
|
#endif
|
|
uvc->priv = NULL;
|
|
uvc->offline = NULL;
|
|
}
|
|
/* struct usb_video_manager *hdl = &uvc_manager[usb_id]; */
|
|
hdl->open = 0;
|
|
}
|
|
}
|
|
return DEV_ERR_NONE;
|
|
}
|
|
|
|
int uvc_host_get_pix_table(void *fd, struct uvc_frame_info **pix_table)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -1;
|
|
}
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
|
|
if (uvc && uvc->reso_num) {
|
|
*pix_table = uvc->pframe;
|
|
return uvc->reso_num;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int uvc_host_get_fps(void *fd)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -1;
|
|
}
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
if (uvc) {
|
|
return uvc->fps;
|
|
}
|
|
return 25;
|
|
}
|
|
|
|
int uvc_host_set_pix(void *fd, int index)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -1;
|
|
}
|
|
/* usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev)); */
|
|
usb_dev usb_id = usbdev_to_usbid(device);
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
|
|
if (uvc) {
|
|
uvc->cur_frame = index;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int uvc_force_reset(void *fd)
|
|
{
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -1;
|
|
}
|
|
usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
uvc_host_close_camera(fd);
|
|
return usb_host_force_reset(usb_id);
|
|
}
|
|
|
|
int uvc_host_camera_out(const usb_dev usb_id)
|
|
{
|
|
struct device *device;
|
|
struct usb_uvc *uvc;
|
|
struct usb_host_device *host_dev;
|
|
struct usb_video_manager *hdl = &uvc_manager[usb_id];
|
|
|
|
device = &hdl->dev;
|
|
if (!device) {
|
|
return 0;
|
|
}
|
|
uvc = device_to_uvc(device);
|
|
if (!uvc) {
|
|
return 0;
|
|
}
|
|
host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return 0;
|
|
}
|
|
if (uvc->offline) {
|
|
uvc->offline(uvc->priv);
|
|
}
|
|
#if (STOP_TRANSFER == 0)
|
|
uvc->camera_open = 0;
|
|
#endif
|
|
uvc_host_close_camera(device);
|
|
if (uvc->ep_buffer) {
|
|
usb_h_free_ep_buffer(usb_id, uvc->ep_buffer);
|
|
uvc->ep_buffer = NULL;
|
|
}
|
|
/* free(uvc); */
|
|
if (hdl->buffer) {
|
|
free(hdl->buffer);
|
|
hdl->buffer = NULL;
|
|
}
|
|
#if !CAMERA_CLOSE_BY_IRQ
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
uvc->bak_stream_out = uvc_dummy_stream_out;
|
|
#else
|
|
uvc->stream_out = uvc_dummy_stream_out;
|
|
#endif
|
|
uvc->priv = NULL;
|
|
uvc->offline = NULL;
|
|
|
|
free(uvc);
|
|
uvc_host_inf[usb_id].dev.uvc = NULL;
|
|
hdl->open = 0;
|
|
atomic_set(&(device->ref), 0);
|
|
device->private_data = NULL;
|
|
return 0;
|
|
}
|
|
|
|
int uvc2usb_ioctl(void *fd, u32 cmd, void *arg)
|
|
{
|
|
#if 0
|
|
struct device *device = (struct device *)fd;
|
|
struct usb_host_device *host_dev = device_to_usbdev(device);
|
|
if (!host_dev) {
|
|
return -ENODEV;
|
|
}
|
|
usb_dev usb_id = usbpriv_to_usbid(usbdev_to_usbpriv(host_dev));
|
|
struct usb_uvc *uvc = device_to_uvc(device);
|
|
|
|
if (!uvc) {
|
|
return -ENODEV;
|
|
}
|
|
switch (cmd) {
|
|
case UVCIOC_SET_EVENT_LISTENER:
|
|
struct uvc_event_listener *listener = (struct uvc_event_listener *)arg;
|
|
uvc->event_priv = listener->priv;
|
|
uvc->event_handler = listener->handler;
|
|
break;
|
|
default:
|
|
return host_device_ioctl(host_dev, cmd, arg);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
|
|
u32 uvc_host_get_fmt(void)
|
|
{
|
|
return ((uvc_host_inf[uvc_host_online()].dev.uvc->format == UVC_VS_FORMAT_UNCOMPRESSED) ? 1 : 0);
|
|
}
|
|
u8 uvc_host_is_support_h264_fmt(void)
|
|
{
|
|
struct usb_uvc *uvc;
|
|
usb_dev usb_id;
|
|
for (u8 i = 0; i < USB_MAX_HW_NUM; ++i) {
|
|
usb_id = i;
|
|
uvc = device_to_uvc(device);
|
|
if (uvc && uvc->h264_format_index) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define JPEG_HEAD 0xE0FFD8FF
|
|
#define JPEG_HEAD1 0xC0FFD8FF
|
|
|
|
int net_jpeg_pkg_head_check(u32 head)
|
|
{
|
|
if (uvc_host_get_fmt()) {
|
|
return true;
|
|
}
|
|
|
|
if (head == JPEG_HEAD) {
|
|
return true;
|
|
} else if (head == JPEG_HEAD1) {
|
|
return true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int jpeg_pkg_head_check(u32 head)
|
|
{
|
|
if (uvc_host_get_fmt()) {
|
|
return true;
|
|
}
|
|
|
|
if (head == JPEG_HEAD) {
|
|
return true;
|
|
} else if (head == JPEG_HEAD1) {
|
|
return true;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif // USB_HOST_UVC
|