#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 #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