doubao_chat/apps/common/usb/device/uvc.c

3285 lines
124 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "system/includes.h"
#include "device/usb_stack.h"
#include "usb_config.h"
#include "os/os_api.h"
#include "app_config.h"
#if TCFG_USB_SLAVE_UVC_ENABLE
#include "slave_uvc.h"
#include "video/video_ioctl.h"
#include "video/video.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"
struct usb_uvc_camera {
u32 itf_base: 8;
u32 tx_broken: 1;
u32 is_new_frame: 1;
u32 reserved: 22;
u16 width[FMT_MAX_RESO_NUM * 2];
u16 height[FMT_MAX_RESO_NUM * 2];
int (*video_open)(int idx, int fmt, int frame_id, int fps);
int (*video_reqbuf)(int idx, void *buf, u32 len, u32 *frame_end);
int (*video_close)(int idx);
int (*processing_unit_response)(struct uvc_unit_ctrl *ctl_req);
int (*private_cmd_response)(u16 cmd, u16 data);
u32 uvc_status;
u32 last_len;
u8 *stream_buf;
u8 *ep_dma_buffer;
};
static struct usb_uvc_camera *uvc_handle[USB_MAX_HW_NUM];
#if USB_MALLOC_ENABLE
#else
static struct usb_uvc_camera _uvc_handle[USB_MAX_HW_NUM];
static u8 _stream_buf[UVC_PKT_SPILT * UVC_FIFO_TXMAXP];
#endif
typedef void (*pUVC_SETUP_HOOK)(usb_dev, struct usb_device_t *, struct usb_ctrlrequest *);
static u32 uvc_vc_itf_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
static u32 uvc_vs_itf_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
static u32 uvc_vc_itf_recv_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
static u32 uvc_vs_itf_recv_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
static void usb_video_open_camera(usb_dev usb_id);
static void usb_video_close_camera(usb_dev usb_id);
void uvc_vc_pu_wBacklightCompensation_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wBrightness_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wContrast_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wGain_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bPowerLineFrequency_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wHue_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wSaturation_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wSharpness_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wGamma_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wWhiteBalanceTemperature_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bWhiteBalanceTemperatureAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_white_balance_component_control_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bWhiteBalanceComponentAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wMultiplierStep_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_wMultiplierLimit_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bHueAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bVideoStandard_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vc_pu_bStatus_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vs_probe_commit_ctl_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
void uvc_vs_still_probe_commit_ctl_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req);
#define UVC_TEST_ENABLE 0
#define UVC_REQ_BUF_IN_THREAD 0
#ifdef CONFIG_VIDEO_IMAGE_W
#define UVC_YUV_DATA_WIDTH CONFIG_VIDEO_IMAGE_W
#define UVC_YUV_DATA_HEIGHT CONFIG_VIDEO_IMAGE_H
#else
#define UVC_YUV_DATA_WIDTH 640
#define UVC_YUV_DATA_HEIGHT 480
#endif
/*------------------------------- uvc descriptor -------------------------------*/
/*********************************************************/
/*
Video Class
*/
/*********************************************************/
static const u8 uvc_interface_desc_header[] = {
/// Interface Association Descriptor IAD descriptor
USB_DT_INTERFACE_ASSOCIATION_SIZE, //bLength
USB_DT_INTERFACE_ASSOCIATION, //bDescriptorType
0x00, //bFirstInterface:0
0x02, //bInterfaceCount:0x02
USB_CLASS_VIDEO, //bFunctionClass:USB_CLASS_VIDEO
SC_VIDEO_INTERFACE_COLLECTION, //bFunctionSubClass:SC_VIDEO_INTERFACE_COLLECTION
UVC_PC_PROTOCOL_UNDEFINED, //bFunctionProtocol:Not used. Must be set to UVC_PC_PROTOCOL_UNDEFINED
VIDEO_STR_INDEX, //iFunction !! must match iInterface in VC Interface descriptor. Index of a string descriptor that describes this interface
};
static const u8 uvc_vc_interface_desc[] = {
///standard VC interface descriptor: /*0x08*/
USB_DT_INTERFACE_SIZE, //Length
USB_DT_INTERFACE, //DescriptorType:Inerface
0x00, //InterfaceNum:0 !!
0x00, //AlternateSetting:0
0x01, //NumEndpoint:1 非零端点数目(interrupt endpoint)
USB_CLASS_VIDEO, //InterfaceClass:USB_CLASS_VIDEO
SC_VIDEOCONTROL, //InterfaceSubClass:SC_VIDEOCONTROL
UVC_PC_PROTOCOL_UNDEFINED, //bFunctionProtocol:Not used. Must be set to UVC_PC_PROTOCOL_UNDEFINED
VIDEO_STR_INDEX, //iInterface
///class-specific VC interface descriptor /*0x11*/
/* 0x0e, //Length */
0x0d,
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_HEADER, //DescriptorSubType:vc_header subtype
0x00, 0x01, //bcdUVC:VC Device Class v1.00
0x4d, 0x00, //TotalLength of class-specific VC interface descriptors
DW1BYTE(UVC_DWCLOCKFREQUENCY),
DW2BYTE(UVC_DWCLOCKFREQUENCY),
DW3BYTE(UVC_DWCLOCKFREQUENCY),
DW4BYTE(UVC_DWCLOCKFREQUENCY), //dwClockFreq
/* 0x02, //InCollection: Num of streaming interfaces */
/* 0x01, //InterfaceNr(1) - VS #1 id VideoStreaming interface 1 belongs to this VideoControl interface */
/* 0x02, //InterfaceNr(2) - VS #2 id VideoStreaming interface 1 belongs to this VideoControl interface */
0x01, //InCollection: Num of streaming interfaces
0x01, //InterfaceNr(0) - VS #0 id VideoStreaming interface 1 belongs to this VideoControl interface
};
static const u8 uvc_terminal_desc[] = {
//Video Input Terminal Descriptor
0x12, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_INPUT_TERMINAL, //DescriptorSubType:vc_input_terminal subtype
UVC_IT_TERMINALID, //bTerminalID:0x01
LOBYTE(ITT_CAMERA), HIBYTE(ITT_CAMERA), //TerminalType:itt_camera type
0x00, //AssocTerminal
0x00, //iTerminal
0x00, 0x00, //wObjectiveFocalLengthMin
0x00, 0x00, //wObjectiveFocalLengthMax
0x00, 0x00, //wOcularFocalLength
0x03, //bControlSize
0x00, 0x00, 0x00, //bmControls
///Processing Unit descriptor
0x0B, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_PROCESSING_UNIT, //DescriptorSubType:vc_processing_unit subtype
UVC_PU_TERMINALID, //UnitID:0x03
UVC_IT_TERMINALID, //SourceID:this input pin of this unit is connected to the input pin of unit with ID 0x01
0x00, 0x00, //MaxMultiplier
0x02, //ControlSize
0x00, 0x00, //mControls: Brightness control supported
0x00, //iProcessing
///Video Extension Unit descriptor(Camera)
0x1A, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_EXTENSION_UNIT, //DescriptorSubType:vc_Extension_unit
UVC_EXT_TERMINALID1, //TerminalID:0x04
UVC_GUID_UNIT_EXTENSION1,//guidExtensionCode
0x08,//0x03, //NumControl ??
0x01, //NrlnPins
UVC_PU_TERMINALID, //SourceID
0x01, //ControlSize
0x00, //mControls
0x00,
///Video Extension Unit descriptor(Camera)
0x1A, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_EXTENSION_UNIT, //DescriptorSubType:vc_Extension_unit
UVC_EXT_TERMINALID2, //TerminalID:0x04
UVC_GUID_UNIT_EXTENSION2,//guidExtensionCode
0x08,//0x03, //NumControl ??
0x01, //NrlnPins
UVC_EXT_TERMINALID1, //SourceID
0x01, //ControlSize
0x00, //mControls
0x00,
///Output Terminal descriptor
0x09, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VC_OUTPUT_TERMINAL, //DescriptorSubType:vc_output_terminal subtype
UVC_OT_TERMINALID1, //bTerminalID:0x02
LOBYTE(TT_STREAMING), HIBYTE(TT_STREAMING),//wTerminalType:usb streaming terminal
0x00, //AssocTerminal
UVC_EXT_TERMINALID2, //SourceID: the input pin of this unit is connected to the output pin of unit 3
0x00, //Terminal
};
static const u8 uvc_standard_intr_endpoint_desc[] = {
///standard Interrupt Endpoint descriptor:
USB_DT_ENDPOINT_SIZE, //Length
USB_DT_ENDPOINT, //DescriptorType:enp descriptor
USB_DIR_IN | VIDEO_STATUS_EP_IN, //Endp_addr:IN endpoint 3
USB_ENDPOINT_XFER_INT, //Attributes :Interrupt transfer type
LOBYTE(VIDEO_STATUS_TXMAXP), HIBYTE(VIDEO_STATUS_TXMAXP), //MaxPacketSize:8byte status packet
0x1, //Interval:
///class-specific Interrupt Endpoint descriptor
0x05, //Length
USB_DT_CS_ENDPOINT, //DescriptorType:cs_endpoint descriptor
USB_ENDPOINT_XFER_INT, //DescriptorSubType:ep_interrupt
LOBYTE(VIDEO_STATUS_TXMAXP), HIBYTE(VIDEO_STATUS_TXMAXP), //MaxPacketSize:8byte status packet
};
static const u8 uvc_vs_interface_desc[] = {
#if UVC_ISO_MODE
///standard VS interface descriptor:(Interface 2, Alternate Setting 1):
USB_DT_INTERFACE_SIZE, //Length
USB_DT_INTERFACE, //DescriptorType:Inerface
0x01, //InterfaceNum:1 !!
0x00, //AlternateSetting
0x00, //NumEndpoint:1 非零端点数目
USB_CLASS_VIDEO, //0x0E, //InterfaceClass:USB_CLASS_VIDEO
SC_VIDEOSTREAMING, //0x02, //InterfaceSubClass:SC_VIDEOSTREAMING
UVC_PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
0x00, //iInterface
#else
///standard VS interface descriptor:(Interface 1, Alternate Setting 0):
USB_DT_INTERFACE_SIZE, //Length
USB_DT_INTERFACE, //DescriptorType:Inerface
0x01, //InterfaceNum:1 !!
0x00, //AlternateSetting
0x01, //NumEndpoint:1 非零端点数目
USB_CLASS_VIDEO, //0x0E, //InterfaceClass:USB_CLASS_VIDEO
SC_VIDEOSTREAMING, //0x02, //InterfaceSubClass:SC_VIDEOSTREAMING
UVC_PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
0x00, //iInterface
///standard VS Iso Video Data Endpoint descriptor:
USB_DT_ENDPOINT_SIZE, //Length
USB_DT_ENDPOINT, //0x05, //DescriptorType:Endpoint
USB_DIR_IN | UVC_STREAM_EP_IN, //EndpointAddr:IN endpoint 2
USB_ENDPOINT_XFER_BULK,
LOBYTE(UVC_FIFO_TXMAXP),
HIBYTE(UVC_FIFO_TXMAXP) | ((UVC_PKT_SPILT - 1) << 3),//MaxPacketSize:MAX packet size
0, //Interval:one frame interval
#endif
};
static const u8 uvc_vs_interface_alternate_desc[] = {
///standard VS interface descriptor:(Interface 2, Alternate Setting 1):
USB_DT_INTERFACE_SIZE, //Length
USB_DT_INTERFACE, //DescriptorType:Inerface
0x01, //InterfaceNum:1 !!
0x01, //AlternateSetting
0x01, //NumEndpoint:1 非零端点数目
USB_CLASS_VIDEO, //0x0E, //InterfaceClass:USB_CLASS_VIDEO
SC_VIDEOSTREAMING, //0x02, //InterfaceSubClass:SC_VIDEOSTREAMING
UVC_PC_PROTOCOL_UNDEFINED, //InterfaceProtocol
0x00, //iInterface
///standard VS Iso Video Data Endpoint descriptor:
USB_DT_ENDPOINT_SIZE, //Length
USB_DT_ENDPOINT, //0x05, //DescriptorType:Endpoint
USB_DIR_IN | UVC_STREAM_EP_IN, //EndpointAddr:IN endpoint 2
USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC,
LOBYTE(UVC_FIFO_TXMAXP),
HIBYTE(UVC_FIFO_TXMAXP) | ((UVC_PKT_SPILT - 1) << 3),//MaxPacketSize:MAX packet size
ISO_EP_INTERVAL, //Interval:one frame interval
};
static const u8 uvc_vs_inf_input_header_desc[] = {
//VS Input Header descriptor
0x0f, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VS_INPUT_HEADER, //DescriptorSubType:VS_INPUT_HEADER
1, //Numformats:One format descriptor follows
0, 0, //TotalLength of class-specific VS interface descriptors
USB_DIR_IN | UVC_STREAM_EP_IN, //endpoint_addr: addr of iso endpoint used for video data
0x00, //info :no dynamic format change supported
UVC_OT_TERMINALID1, //TerminalLink: this videostreaming interface supplies terminal ID 4(Output Terminal)
0, //StillCaptureMethod :not support still image capture
0, //TriggerSupport:none
0, //TriggerUsage:none
0x02, //ControlSize
0x00, //Controls:No VideoStreaming specific controls are supported
0x00, //Controls:No VideoStreaming specific controls are supported
};
#if UVC_FORMAT_MJPG
static const u8 uvc_mjpeg_format_desc[] = {
///class-specific VS Format descriptor
0x0b, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VS_FORMAT_MJPEG, //DescriptorSubType:VS_FORMAT_MJPEG
0x01, //FormatIndex:first format descriptor
0x05, //NumFrameDescriptors: Three frame descriptor for this format follows
0x00, //flags: NO uses fixed size samples
0x01, //defaultFrameIndex :1
0, //AspectRatioX: non interlaced stream 16:9 = 1280 * 720
0, //AspectRatioY :non interlaced stream 16:9 = 1280 * 720
0x00, //InterfaceFlags:non interlaced stream
0x00, //CopyProtect:
};
static const u8 uvc_mjpeg_frame_desc[] = {
///class-specific VS Frame descriptor
0x1e + 4, //Length
USB_DT_CS_INTERFACE, //DescriptorType:cs_interface
VS_FRAME_MJPEG, //DescriptorSubType:VS_FRAME_MJPEG
0x01, //FrameIndex:Num 1 Frame descriptor
0x00, //bmCapabilities:
LOBYTE(MJPG_WWIDTH_0), HIBYTE(MJPG_WWIDTH_0),
LOBYTE(MJPG_WHEIGHT_0), HIBYTE(MJPG_WHEIGHT_0),
DW1BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 40),
DW2BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 40),
DW3BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 40),
DW4BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 40), //MinBitRate: min bit rate in bits/s
DW1BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 240),
DW2BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 240),
DW3BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 240),
DW4BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 240), //MaxBitRate :max bit rate in bits/s
DW1BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 2),
DW2BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 2),
DW3BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 2),
DW4BYTE(MJPG_WWIDTH_0 *MJPG_WHEIGHT_0 * 2), //MaxVideoFrameBufSIZE : in bytes一帧数据或者still帧的最大空间
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS), //DefaultFrameInterval : 33333300ns(30fps) 默认的帧间隔
0x02, //FrameIntervalType: discrete frame interval,
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS),
DW1BYTE(FRAME_FPS * 2),
DW2BYTE(FRAME_FPS * 2),
DW3BYTE(FRAME_FPS * 2),
DW4BYTE(FRAME_FPS * 2),
};
#endif
#if UVC_FORMAT_YUY2 || UVC_FORMAT_NV12 || UVC_FORMAT_I420
static const u8 uvc_yuv_format_desc[] = {
0x1B,//bLength
USB_DT_CS_INTERFACE,//bDescriptorType
VS_FORMAT_UNCOMPRESSED,//bDescriptorSubtype
2, //bFormatIndex
5,//bNumFrameDescriptors
#if UVC_FORMAT_YUY2
UVC_GUID_FORMAT_YUY2,
0x10,//bBitsPerPixel
#elif UVC_FORMAT_NV12
UVC_GUID_FORMAT_NV12,
0x0c,//bBitsPerPixel
#elif UVC_FORMAT_I420
UVC_GUID_FORMAT_I420,
0x0c,//bBitsPerPixel
#endif
1,//bDefaultFrameIndex
0,//bAspectRatioX
0,//bAspectRatioY
0,//bmInterlaceFlags
0,//bCopyProtect
};
static const u8 uvc_yuv_frame_desc[] = {
///class-specific VS Frame descriptor /*0xE0*/ /*0x8C*/
0x1E + 4, //Length
USB_DT_CS_INTERFACE, //0x24, //DescriptorType:cs_interface
VS_FRAME_UNCOMPRESSED, //0x05, //DescriptorSubType:VS_FRAME_MJPEG
0x01, //FrameIndex:Num 1 Frame descriptor
0x00, //bmCapabilities:
LOBYTE(YUV_WWIDTH_0), HIBYTE(YUV_WWIDTH_0),
LOBYTE(YUV_WHEIGHT_0), HIBYTE(YUV_WHEIGHT_0),
DW1BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW2BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW3BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW4BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8), //MinBitRate: min bit rate in bits/s
DW1BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW2BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW3BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8),
DW4BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2 * 30 * 8), //MaxBitRate :max bit rate in bits/s
#if UVC_FORMAT_YUY2
DW1BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2),
DW2BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2),
DW3BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2),
DW4BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 2), //0x00, 0x58, 0x02, 0x00, //MaxVideoFrameBufSIZE : in bytes一帧数据或者still帧的最大空间
#elif UVC_FORMAT_NV12
DW1BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW2BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW3BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW4BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
#elif UVC_FORMAT_I420
DW1BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW2BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW3BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
DW4BYTE(YUV_WWIDTH_0 *YUV_WHEIGHT_0 * 3 / 2),
#endif
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS), //DefaultFrameInterval : 33333300ns(30fps) 默认的帧间隔
0x02, //FrameIntervalType: discrete frame interval,支持下面的四种帧间隔
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS),
DW1BYTE(FRAME_FPS * 2),
DW2BYTE(FRAME_FPS * 2),
DW3BYTE(FRAME_FPS * 2),
DW4BYTE(FRAME_FPS * 2),
};
#endif
static const u8 uvc_color_matching_desc[] = {
///Video Color Matching descriptor: /*0x178*/ /*0x11C*/
0x06, //Length
USB_DT_CS_INTERFACE, //0x24, //DescriptorType:cs_interface
VS_COLORFORMAT, //0x0d, //DescriptorSubType:VS_ColorFormat
0x01, //ColorPrimaries 0: Unspecified (Image characteristics unknown) 1: BT.709, sRGB (default) 2: BT.470-2 (M) 3: BT.470-2 (B, G) 4: SMPTE 170M 5: SMPTE 240M 6-255: Reserved
0x01, //TransferCharacter 0: Unspecified (Image characteristics unknown) 1: BT.709 (default) 2: BT.470-2 M 3: BT.470-2 B, G
0x04, //MatrixCoeffcients
};
static u8 uvc_slave_probe_commit_control[USB_MAX_HW_NUM][26] = {
{
0x00, 0x00, //bmHint
0x01, //FormatIndex
0x01, //FrameIndex
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS), //dwFrameInterval Frame interval in 100 ns units.
0x00, 0x00, //KeyFrameRate
0x00, 0x00, //PFrameRate
0x00, 0x00, //CompQuanlity
0x00, 0x00, //CompWindowsSize
0x00, 0x00, //0x32,0x00, //Delay
DW1BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW2BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW3BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW4BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0), //MaxVideoFrameSize
#if UVC_ISO_MODE
DW1BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW2BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW3BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW4BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT), //MaxPayLoadTransferSize
#else
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2), //MaxPayLoadTransferSize
#endif
},
{
0x00, 0x00, //bmHint
0x01, //FormatIndex
0x01, //FrameIndex
DW1BYTE(FRAME_FPS),
DW2BYTE(FRAME_FPS),
DW3BYTE(FRAME_FPS),
DW4BYTE(FRAME_FPS), //dwFrameInterval Frame interval in 100 ns units.
0x00, 0x00, //KeyFrameRate
0x00, 0x00, //PFrameRate
0x00, 0x00, //CompQuanlity
0x00, 0x00, //CompWindowsSize
0x00, 0x00, //0x32,0x00, //Delay
DW1BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW2BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW3BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0),
DW4BYTE(MJPG_WHEIGHT_0 * MJPG_WWIDTH_0), //MaxVideoFrameSize
#if UVC_ISO_MODE
DW1BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW2BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW3BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW4BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT), //MaxPayLoadTransferSize
#else
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2), //MaxPayLoadTransferSize
#endif
},
};
static u8 uvc_slave_stillprobe_commit_control[USB_MAX_HW_NUM][11] = {
{
0x01,
0x01,
0x01,
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
#if UVC_ISO_MODE
DW1BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW2BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW3BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW4BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT), //MaxPayLoadTransferSize
#else
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2), //MaxPayLoadTransferSize
#endif
},
{
0x01,
0x01,
0x01,
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
#if UVC_ISO_MODE
DW1BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW2BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW3BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT),
DW4BYTE(UVC_FIFO_TXMAXP * UVC_PKT_SPILT), //MaxPayLoadTransferSize
#else
DW1BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW2BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW3BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2),
DW4BYTE(MJPG_WHEIGHT_0 *MJPG_WWIDTH_0 * 2), //MaxPayLoadTransferSize
#endif
},
};
static const u8 videoStringDescriptor[] = {
22, //该描述符的长度为22字节
0x03, //字符串描述符的类型编码为0x03
'U', 0x00, //u
'S', 0x00, //s
'B', 0x00, //b
' ', 0x00, //
'C', 0x00, //c
'A', 0x00, //a
'M', 0x00, //m
'E', 0x00, //e
'R', 0x00, //r
'A', 0x00, //a
};
static void uvc_reset_handle(struct usb_device_t *usb_device, u32 itf)
{
const usb_dev usb_id = usb_device2id(usb_device);
if (uvc_handle[usb_id]) {
#if UVC_ISO_MODE
usb_g_ep_config(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, uvc_handle[usb_id]->ep_dma_buffer, (UVC_FIFO_TXMAXP | ((UVC_PKT_SPILT - 1) << 11)));
uvc_handle[usb_id]->tx_broken = 1;
uvc_handle[usb_id]->last_len = 0;
#else
usb_g_ep_config(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, uvc_handle[usb_id]->ep_dma_buffer, UVC_FIFO_TXMAXP);
#endif
}
}
u32 uvc_desc_config(usb_dev usb_id, u8 *ptr, u32 *inf)
{
int i;
u8 *tptr = ptr;
u16 width, height;
u8 *frame_num;
int yuv_fmt_enable;
u32 total_len = 0;
u8 *tptr_vs;
u8 fmt_idx = 0;
if (!uvc_handle[usb_id] || !ptr || !inf) {
return 0;
}
#if UVC_FORMAT_YUY2 || UVC_FORMAT_NV12 || UVC_FORMAT_I420
if (uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM] && uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM]) {
yuv_fmt_enable = 1;
} else {
yuv_fmt_enable = 0;
}
#else
yuv_fmt_enable = 0;
#endif
log_info("video interface num: %d", *inf + 1);
memcpy(tptr, (u8 *)uvc_interface_desc_header, sizeof(uvc_interface_desc_header));
tptr[2] = *inf;
tptr += sizeof(uvc_interface_desc_header);
memcpy(tptr, (u8 *)uvc_vc_interface_desc, sizeof(uvc_vc_interface_desc));
tptr[2] = *inf;
tptr[21] = *inf + 1;
total_len = 0x0d + sizeof(uvc_terminal_desc);
tptr[14] = LOBYTE(total_len);
tptr[15] = HIBYTE(total_len);
tptr += sizeof(uvc_vc_interface_desc);
memcpy(tptr, (u8 *)uvc_terminal_desc, sizeof(uvc_terminal_desc));
#if VS_IT_CONTROLS_ENABLE
tptr[15] = 0xff;
tptr[16] = 0xff;
tptr[17] = 0x1f;
#endif
#if VS_PU_CONTROLS_ENABLE
tptr[0x12 + 8] = 0xff;
tptr[0x12 + 9] = 0xff;
#endif
tptr += sizeof(uvc_terminal_desc);
memcpy(tptr, (u8 *)uvc_standard_intr_endpoint_desc, sizeof(uvc_standard_intr_endpoint_desc));
tptr += sizeof(uvc_standard_intr_endpoint_desc);
memcpy(tptr, (u8 *)uvc_vs_interface_desc, sizeof(uvc_vs_interface_desc));
tptr[2] = *inf + 1;
tptr += sizeof(uvc_vs_interface_desc);
memcpy(tptr, (u8 *)uvc_vs_inf_input_header_desc, sizeof(uvc_vs_inf_input_header_desc));
#if UVC_FORMAT_I420 && UVC_FORMAT_MJPG
tptr[12] = 1;
#endif
tptr_vs = tptr;
tptr += sizeof(uvc_vs_inf_input_header_desc);
total_len = sizeof(uvc_vs_inf_input_header_desc);
#if UVC_FORMAT_MJPG
memcpy(tptr, (u8 *)uvc_mjpeg_format_desc, sizeof(uvc_mjpeg_format_desc));
tptr[3] = ++fmt_idx;
frame_num = &tptr[4];
*frame_num = 0;
total_len += sizeof(uvc_mjpeg_format_desc);
tptr += sizeof(uvc_mjpeg_format_desc);
for (i = 0; i < FMT_MAX_RESO_NUM; i++) {
if (uvc_handle[usb_id]->width[i] == 0 || uvc_handle[usb_id]->height[i] == 0) {
break;
}
(*frame_num)++;
memcpy(tptr, (u8 *)uvc_mjpeg_frame_desc, sizeof(uvc_mjpeg_frame_desc));
tptr[3] = i + 1;
width = uvc_handle[usb_id]->width[i];
height = uvc_handle[usb_id]->height[i];
tptr[5] = LOBYTE(width);
tptr[6] = HIBYTE(width);
tptr[7] = LOBYTE(height);
tptr[8] = HIBYTE(height);
tptr[9] = DW1BYTE(width * height * 2 * 15 * 8);
tptr[10] = DW2BYTE(width * height * 2 * 15 * 8);
tptr[11] = DW3BYTE(width * height * 2 * 15 * 8);
tptr[12] = DW4BYTE(width * height * 2 * 15 * 8); //MinBitRate
tptr[13] = DW1BYTE(width * height * 2 * 30 * 8);
tptr[14] = DW2BYTE(width * height * 2 * 30 * 8);
tptr[15] = DW3BYTE(width * height * 2 * 30 * 8);
tptr[16] = DW4BYTE(width * height * 2 * 30 * 8); //MaxBitRate
tptr[17] = DW1BYTE(width * height * 2);
tptr[18] = DW2BYTE(width * height * 2);
tptr[19] = DW3BYTE(width * height * 2);
tptr[20] = DW4BYTE(width * height * 2); //MaxVideoFrameBufSize
tptr += sizeof(uvc_mjpeg_frame_desc);
total_len += sizeof(uvc_mjpeg_frame_desc);
}
#endif
#if UVC_FORMAT_YUY2 || UVC_FORMAT_NV12 || UVC_FORMAT_I420
if (yuv_fmt_enable) {
memcpy(tptr, (u8 *)uvc_yuv_format_desc, sizeof(uvc_yuv_format_desc));
tptr[3] = ++fmt_idx;
frame_num = &tptr[4];
*frame_num = 0;
tptr += sizeof(uvc_yuv_format_desc);
total_len += sizeof(uvc_yuv_format_desc);
for (i = 0; i < FMT_MAX_RESO_NUM; i++) {
if (uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + i] == 0 ||
uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + i] == 0) {
break;
}
(*frame_num)++;
memcpy(tptr, (u8 *)uvc_yuv_frame_desc, sizeof(uvc_yuv_frame_desc));
tptr[3] = i + 1;
width = uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + i];
height = uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + i];
tptr[5] = LOBYTE(width);
tptr[6] = HIBYTE(width);
tptr[7] = LOBYTE(height);
tptr[8] = HIBYTE(height);
#if UVC_FORMAT_YUY2
tptr[9] = DW1BYTE(width * height * 2 * 15 * 8);
tptr[10] = DW2BYTE(width * height * 2 * 15 * 8);
tptr[11] = DW3BYTE(width * height * 2 * 15 * 8);
tptr[12] = DW4BYTE(width * height * 2 * 15 * 8); //MinBitRate
tptr[13] = DW1BYTE(width * height * 2 * 30 * 8);
tptr[14] = DW2BYTE(width * height * 2 * 30 * 8);
tptr[15] = DW3BYTE(width * height * 2 * 30 * 8);
tptr[16] = DW4BYTE(width * height * 2 * 30 * 8); //MaxBitRate
tptr[17] = DW1BYTE(width * height * 2);
tptr[18] = DW2BYTE(width * height * 2);
tptr[19] = DW3BYTE(width * height * 2);
tptr[20] = DW4BYTE(width * height * 2); //MaxVideoFrameBufSize
#elif UVC_FORMAT_NV12
tptr[9] = DW1BYTE(width * height * 3 / 2 * 15 * 8);
tptr[10] = DW2BYTE(width * height * 3 / 2 * 15 * 8);
tptr[11] = DW3BYTE(width * height * 3 / 2 * 15 * 8);
tptr[12] = DW4BYTE(width * height * 3 / 2 * 15 * 8); //MinBitRate
tptr[13] = DW1BYTE(width * height * 3 / 2 * 30 * 8);
tptr[14] = DW2BYTE(width * height * 3 / 2 * 30 * 8);
tptr[15] = DW3BYTE(width * height * 3 / 2 * 30 * 8);
tptr[16] = DW4BYTE(width * height * 3 / 2 * 30 * 8); //MaxBitRate
tptr[17] = DW1BYTE(width * height * 3 / 2);
tptr[18] = DW2BYTE(width * height * 3 / 2);
tptr[19] = DW3BYTE(width * height * 3 / 2);
tptr[20] = DW4BYTE(width * height * 3 / 2); //MaxVideoFrameBufSize
#elif UVC_FORMAT_I420
tptr[9] = DW1BYTE(width * height * 3 / 2 * 15 * 8);
tptr[10] = DW2BYTE(width * height * 3 / 2 * 15 * 8);
tptr[11] = DW3BYTE(width * height * 3 / 2 * 15 * 8);
tptr[12] = DW4BYTE(width * height * 3 / 2 * 15 * 8); //MinBitRate
tptr[13] = DW1BYTE(width * height * 3 / 2 * 30 * 8);
tptr[14] = DW2BYTE(width * height * 3 / 2 * 30 * 8);
tptr[15] = DW3BYTE(width * height * 3 / 2 * 30 * 8);
tptr[16] = DW4BYTE(width * height * 3 / 2 * 30 * 8); //MaxBitRate
tptr[17] = DW1BYTE(width * height * 3 / 2);
tptr[18] = DW2BYTE(width * height * 3 / 2);
tptr[19] = DW3BYTE(width * height * 3 / 2);
tptr[20] = DW4BYTE(width * height * 3 / 2); //MaxVideoFrameBufSize
#endif
tptr += sizeof(uvc_yuv_frame_desc);
total_len += sizeof(uvc_yuv_frame_desc);
}
}
#endif
memcpy(tptr, (u8 *)uvc_color_matching_desc, sizeof(uvc_color_matching_desc));
tptr += sizeof(uvc_color_matching_desc);
total_len += sizeof(uvc_color_matching_desc);
//fill uvc_vs_inf_input_header_desc
tptr_vs[3] = fmt_idx;
tptr_vs[4] = LOBYTE(total_len);
tptr_vs[5] = HIBYTE(total_len);
#if UVC_ISO_MODE
memcpy(tptr, (u8 *)uvc_vs_interface_alternate_desc, sizeof(uvc_vs_interface_alternate_desc));
tptr[2] = *inf + 1;
tptr += sizeof(uvc_vs_interface_alternate_desc);
#endif
if (usb_set_interface_hander(usb_id, *inf, uvc_vc_itf_handle) != *inf) {
ASSERT(0, "uvc set vc interface handle fail");
}
if (usb_set_interface_hander(usb_id, *inf + 1, uvc_vs_itf_handle) != *inf + 1) {
ASSERT(0, "uvc set vs interface handle fail")
}
if (usb_set_reset_hander(usb_id, *inf, uvc_reset_handle) != *inf) {
ASSERT(0, "uvc set reset handle fail")
}
uvc_handle[usb_id]->itf_base = *inf;
*inf += 2;
return (u32)(tptr - ptr);
}
const u8 *uvc_get_string()
{
return videoStringDescriptor;
}
/*------------------------------- uvc setup -------------------------------*/
static u32 uvc_vc_itf_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
const usb_dev usb_id = usb_device2id(usb_device);
usb_device->wDataLength = req->wLength;
usb_device->bDataOverFlag = 0;
log_info("%x %x %x %x\n", req->bRequest,
req->wIndex,
req->wLength,
req->wValue);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
switch (req->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
log_info("standard request\n");
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case USB_TYPE_CLASS:
if (LOBYTE(req->wIndex) == uvc_handle[usb_id]->itf_base) { //vc interface class specificed request
log_info("vc interface request\n");
switch (HIBYTE(req->wIndex)) {
#if VS_IT_CONTROLS_ENABLE
case UVC_IT_TERMINALID:
usb_device->wDataLength = req->wLength;
#if 1
goto __req_default;
#endif
switch (HIBYTE(req->wValue)) {
case CT_SCANNING_MODE_CONTROL:
break;
case CT_AE_MODE_CONTROL:
break;
case CT_AE_PRIORITY_CONTROL:
break;
case CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
break;
case CT_EXPOSURE_TIME_RELATIVE_CONTROL:
break;
case CT_FOCUS_ABSOLUTE_CONTROL:
break;
case CT_FOCUS_RELATIVE_CONTROL:
break;
case CT_FOCUS_AUTO_CONTROL:
break;
case CT_IRIS_ABSOLUTE_CONTROL:
break;
case CT_IRIS_RELATIVE_CONTROL:
break;
case CT_ZOOM_ABSOLUTE_CONTROL:
break;
case CT_ZOOM_RELATIVE_CONTROL:
break;
case CT_PANTILT_ABSOLUTE_CONTROL:
break;
case CT_PANTILT_RELATIVE_CONTROL:
break;
case CT_ROLL_ABSOLUTE_CONTROL:
break;
case CT_ROLL_RELATIVE_CONTROL:
break;
case CT_PRIVACY_CONTROL:
break;
}
break;
#endif
#if VS_PU_CONTROLS_ENABLE
case UVC_PU_TERMINALID:
usb_device->wDataLength = req->wLength;
if (uvc_handle[usb_id]->processing_unit_response && req->bRequest != UVC_SET_CUR) {
struct uvc_unit_ctrl unit_ctrl_req;
unit_ctrl_req.request = req->bRequest;
unit_ctrl_req.unit = HIBYTE(req->wValue);
unit_ctrl_req.data = usb_device->setup_ptr;
unit_ctrl_req.len = req->wLength;
int err = uvc_handle[usb_id]->processing_unit_response(&unit_ctrl_req);
if (!err) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
if (unit_ctrl_req.len != req->wLength) {
if (unit_ctrl_req.len < req->wLength) {
usb_device->wDataLength = unit_ctrl_req.len;
usb_device->bDataOverFlag = 1;
}
}
break;
}
}
switch (HIBYTE(req->wValue)) {
case PU_BACKLIGHT_COMPENSATION_CONTROL: //背光对比
uvc_vc_pu_wBacklightCompensation_handle(usb_id, usb_device, req);
break;
case PU_BRIGHTNESS_CONTROL: //亮度
uvc_vc_pu_wBrightness_handle(usb_id, usb_device, req);
break;
case PU_CONTRAST_CONTROL: //对比度
uvc_vc_pu_wContrast_handle(usb_id, usb_device, req);
break;
case PU_GAIN_CONTROL:
uvc_vc_pu_wGain_handle(usb_id, usb_device, req);
break;
case PU_POWER_LINE_FREQUENCY_CONTROL:
uvc_vc_pu_bPowerLineFrequency_handle(usb_id, usb_device, req);
break;
case PU_HUE_CONTROL: //色调
uvc_vc_pu_wHue_handle(usb_id, usb_device, req);
break;
case PU_SATURATION_CONTROL: //饱和度
uvc_vc_pu_wSaturation_handle(usb_id, usb_device, req);
break;
case PU_SHARPNESS_CONTROL: //清晰度,锐度
uvc_vc_pu_wSharpness_handle(usb_id, usb_device, req);
break;
case PU_GAMMA_CONTROL: //伽马
uvc_vc_pu_wGamma_handle(usb_id, usb_device, req);
break;
case PU_WHITE_BALANCE_TEMPERATURE_CONTROL: //白平衡
uvc_vc_pu_wWhiteBalanceTemperature_handle(usb_id, usb_device, req);
break;
case PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
uvc_vc_pu_bWhiteBalanceTemperatureAuto_handle(usb_id, usb_device, req);
break;
case PU_WHITE_BALANCE_COMPONENT_CONTROL:
uvc_vc_pu_white_balance_component_control_handle(usb_id, usb_device, req);
break;
case PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
uvc_vc_pu_bWhiteBalanceComponentAuto_handle(usb_id, usb_device, req);
break;
case PU_DIGITAL_MULTIPLIER_CONTROL:
uvc_vc_pu_wMultiplierStep_handle(usb_id, usb_device, req);
break;
case PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL:
uvc_vc_pu_wMultiplierLimit_handle(usb_id, usb_device, req);
break;
case PU_HUE_AUTO_CONTROL:
uvc_vc_pu_bHueAuto_handle(usb_id, usb_device, req);
break;
case PU_ANALOG_VIDEO_STANDARD_CONTROL:
uvc_vc_pu_bVideoStandard_handle(usb_id, usb_device, req);
break;
case PU_ANALOG_LOCK_STATUS_CONTROL:
uvc_vc_pu_bStatus_handle(usb_id, usb_device, req);
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
#endif
case UVC_EXT_TERMINALID1:
case UVC_EXT_TERMINALID2:
switch (req->bRequest) {
case UVC_GET_CUR:
*(u16 *)usb_device->setup_buffer = 0x000a;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
*(u16 *)usb_device->setup_buffer = 0x0008;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
*(u16 *)usb_device->setup_buffer = 0x0010;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
*(u16 *)usb_device->setup_buffer = 0x0001;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->setup_buffer[0] = 0x03;
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_LEN:
if (HIBYTE(req->wValue) == 2 || HIBYTE(req->wValue) == 3) {
*(u16 *)usb_device->setup_buffer = 0x0002;
} else {
*(u16 *)usb_device->setup_buffer = 0x0004;
}
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
goto __req_default;
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
} else {
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
case USB_TYPE_VENDOR:
goto __req_default;
break;
default:
log_info("requeset type dose not exist\n");
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
usb_set_setup_recv(usb_device, uvc_vc_itf_recv_handle);
}
//log_info("%d\n", req->wLength);
return 0;
__req_default:
if (req->bRequest & 0x80) { //UVC_GET_XXX
memset(usb_device->setup_ptr, 0, req->wLength);
usb_device->wDataLength = 0;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
} else if (req->bRequest == UVC_SET_CUR) {
usb_device->wDataLength = req->wLength;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = 0;
usb_set_setup_recv(usb_device, uvc_vc_itf_recv_handle);
}
return 0;
}
static u32 uvc_vs_itf_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
const usb_dev usb_id = usb_device2id(usb_device);
u8 *probe_commit = uvc_slave_probe_commit_control[usb_id];
u8 *stillprobe_commit = uvc_slave_stillprobe_commit_control[usb_id];
u32 frame_size = probe_commit[3] - 1;
usb_device->wDataLength = req->wLength;
usb_device->bDataOverFlag = 0;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
switch (req->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
log_info("standard request\n");
if (req->bRequest == USB_REQ_SET_INTERFACE) {
if (req->wIndex == uvc_handle[usb_id]->itf_base + 1) { //mjpeg vs interface number
log_info("uvc set vs_interface %d alternate setting to %d\n", req->wIndex, req->wValue);
if (req->wValue) {
usb_video_open_camera(usb_id);
} else {
usb_video_close_camera(usb_id);
}
} else {
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
break;
case USB_TYPE_CLASS:
if (LOBYTE(req->wIndex) == uvc_handle[usb_id]->itf_base + 1) { //vs interface class specificed request
log_info("vs interface request\n");
switch (HIBYTE(req->wValue)) {
case UVC_VS_PROBE_CONTROL:
case UVC_VS_COMMIT_CONTROL:
uvc_vs_probe_commit_ctl_handle(usb_id, usb_device, req);
break;
case UVC_VS_STILL_PROBE_CONTROL:
case UVC_VS_STILL_COMMIT_CONTROL:
uvc_vs_still_probe_commit_ctl_handle(usb_id, usb_device, req);
break;
}
} else {
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
case USB_TYPE_VENDOR:
goto __req_default;
break;
default:
log_info("requeset type dose not exist\n");
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
usb_set_setup_recv(usb_device, uvc_vs_itf_recv_handle);
}
//log_info("%d\n", req->wLength);
return 0;
__req_default:
if (req->bRequest & 0x80) { //UVC_GET_XXX
memset(usb_device->setup_ptr, 0, req->wLength);
usb_device->wDataLength = 0;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
} else if (req->bRequest == UVC_SET_CUR) {
usb_device->wDataLength = req->wLength;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = 0;
usb_set_setup_recv(usb_device, uvc_vs_itf_recv_handle);
}
return 0;
}
static u32 uvc_vc_itf_recv_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 rx_len = req->wLength;
int err;
const usb_dev usb_id = usb_device2id(usb_device);
usb_device->setup_ptr = usb_device->setup_buffer;
rx_len = usb_read_count0(usb_id);
usb_read_ep0(usb_id, usb_device->setup_ptr, rx_len);
if (LOBYTE(req->wIndex) == uvc_handle[usb_id]->itf_base) {
err = -1;
if (HIBYTE(req->wIndex) == UVC_PU_TERMINALID &&
uvc_handle[usb_id]->processing_unit_response) {
struct uvc_unit_ctrl unit_ctrl_req;
unit_ctrl_req.request = req->bRequest;
unit_ctrl_req.unit = HIBYTE(req->wValue);
unit_ctrl_req.data = usb_device->setup_ptr;
unit_ctrl_req.len = req->wLength;
err = uvc_handle[usb_id]->processing_unit_response(&unit_ctrl_req);
}
if (err && uvc_handle[usb_id]->uvc_status) {
((pUVC_SETUP_HOOK)uvc_handle[usb_id]->uvc_status)(usb_id, usb_device, req);
}
} else {
log_info("interface invalid\n");
}
uvc_handle[usb_id]->uvc_status = 0;
return USB_EP0_STAGE_SETUP;
}
static u32 uvc_vs_itf_recv_handle(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 rx_len = req->wLength;
int err;
const usb_dev usb_id = usb_device2id(usb_device);
usb_device->setup_ptr = usb_device->setup_buffer;
rx_len = usb_read_count0(usb_id);
usb_read_ep0(usb_id, usb_device->setup_ptr, rx_len);
if (LOBYTE(req->wIndex) == uvc_handle[usb_id]->itf_base + 1) {
if (uvc_handle[usb_id]->uvc_status) {
((pUVC_SETUP_HOOK)uvc_handle[usb_id]->uvc_status)(usb_id, usb_device, req);
}
} else {
log_info("interface invalid\n");
}
uvc_handle[usb_id]->uvc_status = 0;
return USB_EP0_STAGE_SETUP;
}
int uvc_setup_private(usb_dev usb_id, struct usb_device_t *usb_devie, struct usb_ctrlrequest *req)
{
uvc_handle[usb_id]->private_cmd_response(req->bRequest, req->wValue);
return 0;
}
/*------------------------------- uvc main -------------------------------*/
volatile u8 g_still_image_flag;
#define UVC_CAMERA_MAGIC 0x5aa555aa
enum {
UVC_CUR,
UVC_MIN,
UVC_MAX,
UVC_DEF,
};
struct video_arg_info {
//cur min max default
u16 wBacklightCompensation[4];//number
u16 wBrightness[4];//Signed number
u16 wContrast[4];//Number
u16 wGain[4];//Number
u8 bPowerLineFrequency[4];//0: Disabled 1: 50 Hz 2: 60 Hz
u16 wHue[4];//Signed number
u16 wSaturation[4];
u16 wSharpness[4];
u16 wGamma[4];
u16 wWhiteBalanceTemperature[4];
u8 bWhiteBalanceTemperatureAuto[4];
u32 pu_white_balance_component_control[4];//wWhiteBalanceBlue wWhiteBalanceRed
u8 bWhiteBalanceComponentAuto[4];
u16 wMultiplierStep[4];
u16 wMultiplierLimit[4];
u8 bHueAuto[4];
u8 bVideoStandard[4];//0: None 1: NTSC – 525/60 2: PAL – 625/50 4: SECAM – 625/50 4: NTSC – 625/50 5: PAL – 525/60 6-255: Reserved. Do not use
u8 bStatus[4];//0: Video Decoder is locked. 1: Video Decoder is not locked. 2-255: Reserved. Do not use.
};
static struct video_arg_info video_ctl_value[USB_MAX_HW_NUM];
static void usb_video_feature_init(usb_dev usb_id)
{
log_info("sizeof(video_ctl_value[%d]) = %lu\n", usb_id, sizeof(video_ctl_value[usb_id]));
video_ctl_value[usb_id].wBacklightCompensation[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wBacklightCompensation[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wBacklightCompensation[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wBacklightCompensation[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wBrightness[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wBrightness[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wBrightness[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wBrightness[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wContrast[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wContrast[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wContrast[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wContrast[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wGain[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wGain[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wGain[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wGain[UVC_CUR] = 0x80;
video_ctl_value[usb_id].bPowerLineFrequency[UVC_MAX] = 0x02;
video_ctl_value[usb_id].bPowerLineFrequency[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bPowerLineFrequency[UVC_DEF] = 0x00;
video_ctl_value[usb_id].bPowerLineFrequency[UVC_CUR] = 0x00;
video_ctl_value[usb_id].wHue[UVC_MAX] = 180;
video_ctl_value[usb_id].wHue[UVC_MIN] = -180;
video_ctl_value[usb_id].wHue[UVC_DEF] = 0;
video_ctl_value[usb_id].wHue[UVC_CUR] = 0;
video_ctl_value[usb_id].wSaturation[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wSaturation[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wSaturation[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wSaturation[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wSharpness[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wSharpness[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wSharpness[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wSharpness[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wGamma[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wGamma[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wGamma[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wGamma[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_CUR] = 0x80;
video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_MAX] = 1;
video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_DEF] = 0;
video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_CUR] = 0;
video_ctl_value[usb_id].pu_white_balance_component_control[UVC_MAX] = 0x00ff00ff;
video_ctl_value[usb_id].pu_white_balance_component_control[UVC_MIN] = 0x00;
video_ctl_value[usb_id].pu_white_balance_component_control[UVC_DEF] = 0x00800080;
video_ctl_value[usb_id].pu_white_balance_component_control[UVC_CUR] = 0x00800080;
video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_MAX] = 1;
video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_DEF] = 0;
video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_CUR] = 0;
video_ctl_value[usb_id].wMultiplierStep[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wMultiplierStep[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wMultiplierStep[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wMultiplierStep[UVC_CUR] = 0x80;
video_ctl_value[usb_id].wMultiplierLimit[UVC_MAX] = 0x00ff;
video_ctl_value[usb_id].wMultiplierLimit[UVC_MIN] = 0x00;
video_ctl_value[usb_id].wMultiplierLimit[UVC_DEF] = 0x80;
video_ctl_value[usb_id].wMultiplierLimit[UVC_CUR] = 0x80;
video_ctl_value[usb_id].bHueAuto[UVC_MAX] = 1;
video_ctl_value[usb_id].bHueAuto[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bHueAuto[UVC_DEF] = 0;
video_ctl_value[usb_id].bHueAuto[UVC_CUR] = 0;
video_ctl_value[usb_id].bVideoStandard[UVC_MAX] = 0;
video_ctl_value[usb_id].bVideoStandard[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bVideoStandard[UVC_DEF] = 0;
video_ctl_value[usb_id].bVideoStandard[UVC_CUR] = 0;
video_ctl_value[usb_id].bStatus[UVC_MAX] = 1;
video_ctl_value[usb_id].bStatus[UVC_MIN] = 0x00;
video_ctl_value[usb_id].bStatus[UVC_DEF] = 1;
video_ctl_value[usb_id].bStatus[UVC_CUR] = 1;
}
typedef struct uvc_payload_hdr {
u8 bfh_val;
u32 frame_cnt;
u32 scr;
u16 sof_cnt;
} UVC_PLD_HDR;
static UVC_PLD_HDR pld_hdr[USB_MAX_HW_NUM];
/* static u32 IsNewFrame; */
static void fill_payload_head(u8 *tx_addr, UVC_PLD_HDR *hdr)
{
u32 frame_cnt = 0, scr = 0;
u16 sof_count = 0;
/// Stream Head
tx_addr[0x00] = 0x0C;//Head Length
tx_addr[0x01] = hdr->bfh_val; //BFH[0] [7:0]={EOH,ERR,STI,RES,SCR,PTS,EOF,FID}
/* tx_addr[0x1] &= ~(BIT(2) | BIT(3) | BIT(5) | BIT(6)); */
frame_cnt = hdr->frame_cnt;
tx_addr[0x02] = frame_cnt ;//PTS[7:0]
tx_addr[0x03] = (frame_cnt >> 8); //PTS[15:8]
tx_addr[0x04] = (frame_cnt >> 16) ; //PTS[23:16]
tx_addr[0x05] = (frame_cnt >> 24) ; //PTS[31:24]
scr = hdr->scr;
tx_addr[0x06] = DW1BYTE(scr);//SCR[7:0]
tx_addr[0x07] = DW2BYTE(scr);//SCR[15:8]
tx_addr[0x08] = DW3BYTE(scr);//SCR[23:16]
tx_addr[0x09] = DW4BYTE(scr);//SCR[31:24]
sof_count = hdr->sof_cnt;
tx_addr[0x0A] = LOBYTE(sof_count); //SCR[42:32] 1KHz SOF token counter
tx_addr[0x0B] = HIBYTE(sof_count); //SCR[47:42] res set to 0.
}
static void uvc_g_bulk_transfer(struct usb_device_t *usb_device, u32 ep)
{
u32 len = 0;
u32 IsEOFFrame = 0;
u8 *tx_addr;
const usb_dev usb_id = usb_device2id(usb_device);
/* putchar('i'); */
if (uvc_handle[usb_id] == NULL) {
return;
}
tx_addr = uvc_handle[usb_id]->stream_buf;
if (uvc_handle[usb_id]->video_reqbuf) {
if (uvc_handle[usb_id]->is_new_frame == 0) {
len = uvc_handle[usb_id]->video_reqbuf(usb_id, tx_addr, UVC_FIFO_TXMAXP, &IsEOFFrame);
if (IsEOFFrame) {
uvc_handle[usb_id]->is_new_frame = 1;
} else {
uvc_handle[usb_id]->is_new_frame = 0;
}
} else {
len = uvc_handle[usb_id]->video_reqbuf(usb_id, &tx_addr[0x0c], UVC_FIFO_TXMAXP - 0x0c, &IsEOFFrame);
if (len) {
pld_hdr[usb_id].sof_cnt = musb_read_sofframe(usb_id);
pld_hdr[usb_id].frame_cnt++;
pld_hdr[usb_id].bfh_val &= ~UVC_EOF;
fill_payload_head(tx_addr, &pld_hdr[usb_id]);
pld_hdr[usb_id].bfh_val ^= UVC_FID;
len += 12;
uvc_handle[usb_id]->is_new_frame = 0;
}
}
}
usb_g_bulk_write(usb_id, UVC_STREAM_EP_IN, tx_addr, len);
}
static void uvc_g_iso_transfer(struct usb_device_t *usb_device, u32 ep)
{
u32 len = 0;
u32 IsEOFFrame = 0;
u8 undo_tx = 0;
u32 len2;
u8 *tx_addr;
const usb_dev usb_id = usb_device2id(usb_device);
/*putchar('i');*/
if (uvc_handle[usb_id] == NULL) {
return;
}
tx_addr = uvc_handle[usb_id]->stream_buf;
pld_hdr[usb_id].sof_cnt = musb_read_sofframe(usb_id);
if (!uvc_handle[usb_id]->tx_broken) {
if (uvc_handle[usb_id]->video_reqbuf) {//请求uvc从机的JPEG或YUV数据帧
len = uvc_handle[usb_id]->video_reqbuf(usb_id, &tx_addr[0x0c], UVC_PKT_SPILT * UVC_FIFO_TXMAXP - 0x0c, &IsEOFFrame);
if (IsEOFFrame) {
pld_hdr[usb_id].bfh_val |= UVC_EOF;
pld_hdr[usb_id].frame_cnt++;
fill_payload_head(tx_addr, &pld_hdr[usb_id]);
pld_hdr[usb_id].bfh_val ^= UVC_FID;
} else {
pld_hdr[usb_id].bfh_val &= ~UVC_EOF;
fill_payload_head(tx_addr, &pld_hdr[usb_id]);
}
}
len = len > 0 ? len + 12 : 0;
} else {
len = uvc_handle[usb_id]->last_len;
}
len2 = usb_g_iso_write(usb_id, UVC_STREAM_EP_IN, tx_addr, len);//请求完成则发往USB
if (len && !len2) {
uvc_handle[usb_id]->tx_broken = 1;
uvc_handle[usb_id]->last_len = len;
} else {
uvc_handle[usb_id]->tx_broken = 0;
}
}
//void uvc_g_video_transfer(usb_dev usb_id, u32 ep)
//{
//#if UVC_ISO_MODE
// uvc_g_iso_transfer(usb_id, ep);
//#else
// uvc_g_bulk_transfer(usb_id, ep);
//#endif
//}
extern struct usb_ep_addr_t *usb_ep_addr[USB_MAX_HW_NUM];
static void uvc_start_stream(usb_dev usb_id)
{
if (uvc_handle[usb_id] == NULL) {
return;
}
#if UVC_ISO_MODE
usb_g_ep_config(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_ISOC, 1, uvc_handle[usb_id]->ep_dma_buffer, (UVC_FIFO_TXMAXP | ((UVC_PKT_SPILT - 1) << 11)));
usb_g_set_intr_hander(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, uvc_g_iso_transfer);
pld_hdr[usb_id].bfh_val |= UVC_EOF;
fill_payload_head(uvc_handle[usb_id]->stream_buf, &pld_hdr[usb_id]);
usb_g_iso_write(usb_id, UVC_STREAM_EP_IN, uvc_handle[usb_id]->stream_buf, 0x0c);
uvc_handle[usb_id]->tx_broken = 1;
uvc_handle[usb_id]->last_len = 0x0c;
#else
usb_g_ep_config(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, uvc_handle[usb_id]->ep_dma_buffer, UVC_FIFO_TXMAXP);
usb_g_set_intr_hander(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, uvc_g_bulk_transfer);
pld_hdr[usb_id].bfh_val |= UVC_EOF;
fill_payload_head(uvc_handle[usb_id]->stream_buf, &pld_hdr[usb_id]);
usb_g_bulk_write(usb_id, UVC_STREAM_EP_IN, uvc_handle[usb_id]->stream_buf, 0x0c);
#endif
}
static void usb_video_open_camera(usb_dev usb_id)
{
log_info("open camera success\n");
u32 fps;
g_still_image_flag = 0;
pld_hdr[usb_id].frame_cnt = 0;
pld_hdr[usb_id].sof_cnt = musb_read_sofframe(usb_id);
pld_hdr[usb_id].bfh_val = 0x80;
memcpy(&fps, &uvc_slave_probe_commit_control[usb_id][4], 4);
log_info("%d %d %d\n", g_still_image_flag, uvc_slave_probe_commit_control[usb_id][3] - 1, 10000000 / fps);
if (uvc_handle[usb_id] && uvc_handle[usb_id]->video_open) {
/*printf("%s %p\n", __func__, uvc_handle[usb_id]->video_open);*/
uvc_handle[usb_id]->video_open(usb_id, uvc_slave_probe_commit_control[usb_id][2] - 1, //Format Index
uvc_slave_probe_commit_control[usb_id][3] - 1, //Frame Index
10000000 / fps);
}
uvc_start_stream(usb_id);
}
static void usb_video_close_camera(usb_dev usb_id)
{
log_info("close camera success\n");
usb_clr_intr_txe(usb_id, UVC_STREAM_EP_IN);
usb_g_set_intr_hander(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, NULL);
if (uvc_handle[usb_id] && uvc_handle[usb_id]->video_close) {
uvc_handle[usb_id]->video_close(usb_id);
}
}
typedef struct _USB_VIDEO_STATUS_VAR {
u8 bStateType;
u8 bOriginator;
u8 bEvent;
u8 bSelector_Value;//当为视频控制接口时,表示控制的类型;当为视频流接口时,表示BUTTON值
u8 bAttribute;
u8 bValue;
} sUSB_VIDEO_STATUS_VAR;
static sUSB_VIDEO_STATUS_VAR g_video_status;
static void usb_video_status(u8 *pStatus, u8 interface_type)
{
u8 res = 0;
puts("usb_video_status\n");
}
void usb_video_shutter(usb_dev usb_id)
{
#if 0
g_video_status.bStateType = VIDEO_CTL_INTFACE_TYPE;
g_video_status.bOriginator = 0x01;
g_video_status.bEvent = 0x00;
g_video_status.bSelector_Value = 0x01;
usb_video_status((u8 *)&g_video_status, VIDEO_CTL_INTFACE_TYPE);
g_still_image_flag = 1;
while (g_still_image_flag);
g_video_status.bSelector_Value = 0x00;
usb_video_status((u8 *)&g_video_status, VIDEO_CTL_INTFACE_TYPE);
#else
log_info("shutter start....\n");
g_still_image_flag = 1;
log_info("shutter end....\r\n");
#endif
}
/*
Table 4-3 Defined Bits Containing Capabilities of the Control
D0 1=Supports GET value requests Capability
D1 1=Supports SET value requests Capability
D2 1=Disabled due to automatic mode (under device control) State
D3 1= Autoupdate Control (see section 2.4.2.2 "Status Interrupt Endpoint") Capability
D4 1= Asynchronous Control (see sections 2.4.2.2 "Status Interrupt Endpoint" and 2.4.4, “Control Transfer and Request Processing”) Capability
D7..D5 Reserved (Set to 0)
*/
void uvc_vc_pu_wBacklightCompensation_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBacklightCompensation[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBacklightCompensation[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBacklightCompensation[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBacklightCompensation[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wBacklightCompensation_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wBacklightCompensation[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wBrightness_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBrightness[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBrightness[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBrightness[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wBrightness[UVC_DEF], req->wLength);
usb_device->wDataLength = req->wLength;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wBrightness_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wBrightness[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wContrast_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wContrast[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wContrast[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wContrast[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wContrast[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wContrast_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wContrast[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wGain_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGain[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGain[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGain[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGain[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wGain_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wGain[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bPowerLineFrequency_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bPowerLineFrequency[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bPowerLineFrequency[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_bPowerLineFrequency_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].bPowerLineFrequency[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wHue_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wHue[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wHue[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wHue[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wHue[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wHue_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wHue[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wSaturation_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSaturation[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSaturation[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSaturation[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSaturation[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wSaturation_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wSaturation[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wSharpness_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSharpness[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSharpness[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSharpness[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wSharpness[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wSharpness_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wSharpness[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wGamma_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGamma[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGamma[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGamma[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x0a;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wGamma[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wGamma_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wGamma[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wWhiteBalanceTemperature_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wWhiteBalanceTemperature_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wWhiteBalanceTemperature[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bWhiteBalanceTemperatureAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_bWhiteBalanceTemperatureAuto_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].bWhiteBalanceTemperatureAuto[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_white_balance_component_control_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].pu_white_balance_component_control[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].pu_white_balance_component_control[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].pu_white_balance_component_control[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].pu_white_balance_component_control[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_white_balance_component_control_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].pu_white_balance_component_control[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bWhiteBalanceComponentAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_bWhiteBalanceComponentAuto_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].bWhiteBalanceComponentAuto[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wMultiplierStep_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierStep[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierStep[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierStep[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierStep[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wMultiplierStep_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wMultiplierStep[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_wMultiplierLimit_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierLimit[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierLimit[UVC_MIN], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierLimit[UVC_MAX], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
value = 0x01;
memcpy(usb_device->setup_ptr, &value, req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].wMultiplierLimit[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_wMultiplierLimit_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].wMultiplierLimit[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bHueAuto_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bHueAuto[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bHueAuto[UVC_DEF], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vc_pu_bHueAuto_handle;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
memcpy(&video_ctl_value[usb_id].bHueAuto[UVC_CUR], usb_device->setup_ptr, req->wLength);
} else {
log_info("setup state err\n");
}
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bVideoStandard_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bVideoStandard[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_SET_CUR:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vc_pu_bStatus_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 value;
log_info("%s() %d\n", __func__, __LINE__);
switch (req->bRequest) {
case UVC_GET_CUR:
memcpy(usb_device->setup_ptr, &video_ctl_value[usb_id].bStatus[UVC_CUR], req->wLength);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_MAX:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_RES:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_DEF:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
case UVC_SET_CUR:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
}
void uvc_vs_probe_commit_ctl_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 i, len = 0;
switch (req->bRequest) {
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vs_probe_commit_ctl_handle;
return;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
uvc_slave_probe_commit_control[usb_id][0] = usb_device->setup_ptr[0]; //bmHint
uvc_slave_probe_commit_control[usb_id][1] = usb_device->setup_ptr[1];
uvc_slave_probe_commit_control[usb_id][2] = usb_device->setup_ptr[2]; //bFormatIndex
uvc_slave_probe_commit_control[usb_id][3] = usb_device->setup_ptr[3]; //bFrameIndex
uvc_slave_probe_commit_control[usb_id][4] = usb_device->setup_ptr[4]; //dwFrameInterval
uvc_slave_probe_commit_control[usb_id][5] = usb_device->setup_ptr[5];
uvc_slave_probe_commit_control[usb_id][6] = usb_device->setup_ptr[6];
uvc_slave_probe_commit_control[usb_id][7] = usb_device->setup_ptr[7];
#if !UVC_ISO_MODE
if (HIBYTE(req->wValue) == VS_COMMIT_CONTROL) {
usb_video_close_camera(usb_id);
usb_video_open_camera(usb_id);
}
#endif
} else {
log_info("setup state err\n");
}
break;
case UVC_GET_CUR:
len = sizeof(uvc_slave_probe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < len; i++) {
usb_device->setup_ptr[i] = uvc_slave_probe_commit_control[usb_id][i];
}
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
case UVC_GET_DEF:
len = sizeof(uvc_slave_probe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < usb_device->wDataLength; i++) {
usb_device->setup_ptr[i] = uvc_slave_probe_commit_control[usb_id][i];
}
usb_device->setup_ptr[2] = 1;
usb_device->setup_ptr[3] = 1;
usb_device->setup_ptr[4] = DW1BYTE(FRAME_FPS);
usb_device->setup_ptr[5] = DW2BYTE(FRAME_FPS);
usb_device->setup_ptr[6] = DW3BYTE(FRAME_FPS);
usb_device->setup_ptr[7] = DW4BYTE(FRAME_FPS);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
len = sizeof(uvc_slave_probe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < usb_device->wDataLength; i++) {
usb_device->setup_ptr[i] = uvc_slave_probe_commit_control[usb_id][i];
}
usb_device->setup_ptr[2] = 1;
usb_device->setup_ptr[3] = 5;
usb_device->setup_ptr[4] = DW1BYTE(FRAME_FPS * 2);
usb_device->setup_ptr[5] = DW2BYTE(FRAME_FPS * 2);
usb_device->setup_ptr[6] = DW3BYTE(FRAME_FPS * 2);
usb_device->setup_ptr[7] = DW4BYTE(FRAME_FPS * 2);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
len = sizeof(uvc_slave_probe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
memset(usb_device->setup_ptr, 0, usb_device->wDataLength);
usb_device->setup_ptr[2] = 1;
usb_device->setup_ptr[3] = 1;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_LEN:
len = req->wLength;
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
*(u32 *)usb_device->setup_ptr = sizeof(uvc_slave_probe_commit_control[usb_id]);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
}
log_info("vs probe commit control data\n");
if (usb_device->bsetup_phase == USB_EP0_STAGE_IN) {
log_info_hexdump(usb_device->setup_ptr, usb_device->wDataLength);
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
log_info_hexdump(uvc_slave_probe_commit_control[usb_id], sizeof(uvc_slave_probe_commit_control[usb_id]));
}
}
void uvc_vs_still_probe_commit_ctl_handle(usb_dev usb_id, struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
u32 i, len = 0;
switch (req->bRequest) {
case UVC_SET_CUR:
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_set_setup_phase(usb_device, USB_EP0_STAGE_OUT);
uvc_handle[usb_id]->uvc_status = (u32)uvc_vs_still_probe_commit_ctl_handle;
return;
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
uvc_slave_stillprobe_commit_control[usb_id][0] = usb_device->setup_ptr[0]; //bFormatIndex
uvc_slave_stillprobe_commit_control[usb_id][1] = usb_device->setup_ptr[1]; //bFrameIndex
uvc_slave_stillprobe_commit_control[usb_id][2] = usb_device->setup_ptr[2]; //bCompressionIndex
} else {
log_info("setup state err\n");
}
break;
case UVC_GET_CUR:
len = sizeof(uvc_slave_stillprobe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < usb_device->wDataLength; i++) {
usb_device->setup_ptr[i] = uvc_slave_stillprobe_commit_control[usb_id][i];
}
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MIN:
case UVC_GET_DEF:
len = sizeof(uvc_slave_stillprobe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < usb_device->wDataLength; i++) {
usb_device->setup_ptr[i] = uvc_slave_stillprobe_commit_control[usb_id][i];
}
usb_device->setup_ptr[0] = 1; //bFormatIndex
usb_device->setup_ptr[1] = 1; //bFrameIndex
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_MAX:
len = sizeof(uvc_slave_stillprobe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
for (i = 0; i < usb_device->wDataLength; i++) {
usb_device->setup_ptr[i] = uvc_slave_stillprobe_commit_control[usb_id][i];
}
usb_device->setup_ptr[0] = 1;
usb_device->setup_ptr[1] = 5; //bFrameIndex
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_RES:
len = sizeof(uvc_slave_stillprobe_commit_control[usb_id]);
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
memset(usb_device->setup_ptr, 0, usb_device->wDataLength);
usb_device->setup_ptr[0] = 1;
usb_device->setup_ptr[1] = 1;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_LEN:
len = req->wLength;
usb_device->wDataLength = req->wLength > len ? len : req->wLength;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
*(u32 *)usb_device->setup_ptr = sizeof(uvc_slave_stillprobe_commit_control[usb_id]);
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
case UVC_GET_INFO:
usb_device->wDataLength = 1;
if (usb_device->wDataLength < req->wLength) {
usb_device->bDataOverFlag = 1;
}
usb_device->setup_ptr[0] = 0x03;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_IN);
break;
}
log_info("vs still probe commit control data\n");
if (usb_device->bsetup_phase == USB_EP0_STAGE_IN) {
log_info_hexdump(usb_device->setup_ptr, usb_device->wDataLength);
} else if (usb_device->bsetup_phase == USB_EP0_STAGE_OUT) {
log_info_hexdump(uvc_slave_stillprobe_commit_control[usb_id], sizeof(uvc_slave_stillprobe_commit_control[usb_id]));
}
}
void uvc_set_camera_info(usb_dev usb_id, const struct usb_camera *info)
{
int i;
u16 width, height;
u8 jpg_terminate = 0, yuv_terminate = 0;
if (uvc_handle[usb_id] != NULL) {
uvc_handle[usb_id]->video_open = info->video_open;
uvc_handle[usb_id]->video_reqbuf = info->video_reqbuf;
uvc_handle[usb_id]->video_close = info->video_close;
uvc_handle[usb_id]->processing_unit_response = info->processing_unit_response;
uvc_handle[usb_id]->private_cmd_response = info->private_cmd_response;
for (i = 0; i < FMT_MAX_RESO_NUM; i++) {
uvc_handle[usb_id]->width[i] = 0;
uvc_handle[usb_id]->height[i] = 0;
if (info->jpg_info && i < info->jpg_info->num) {
width = info->jpg_info->reso[i].width;
height = info->jpg_info->reso[i].height;
if (!jpg_terminate && (width && height)) {
uvc_handle[usb_id]->width[i] = width;
uvc_handle[usb_id]->height[i] = height;
} else {
jpg_terminate = 1;
}
}
uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + i] = 0;
uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + i] = 0;
if (info->yuv_info && i < info->yuv_info->num) {
width = info->yuv_info->reso[i].width;
height = info->yuv_info->reso[i].height;
if (!yuv_terminate && (width && height)) {
uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + i] = width;
uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + i] = height;
} else {
yuv_terminate = 1;
}
}
}
}
}
static int uvc_video_open(int idx, int fmt, int frame_id, int fps);
static int uvc_video_req_buf(int idx, void *buf, u32 len, u32 *frame_end);
static int uvc_video_close(int idx);
u32 uvc_register(usb_dev usb_id)
{
u32 err = 0;
if (uvc_handle[usb_id] == NULL) {
#if USB_MALLOC_ENABLE
uvc_handle[usb_id] = malloc(sizeof(struct usb_uvc_camera));
if (uvc_handle[usb_id] == NULL) {
return (u32) - 1;
}
memset(uvc_handle[usb_id], 0, sizeof(struct usb_uvc_camera));
uvc_handle[usb_id]->stream_buf = malloc(UVC_PKT_SPILT * UVC_FIFO_TXMAXP);
if (uvc_handle[usb_id]->stream_buf == NULL) {
free(uvc_handle[usb_id]);
uvc_handle[usb_id] = NULL;
err = (u32) - 1;
goto __err_exit;
}
#else
uvc_handle[usb_id] = &_uvc_handle[usb_id];
memset(uvc_handle[usb_id], 0, sizeof(struct usb_uvc_camera));
uvc_handle[usb_id]->stream_buf = _stream_buf;
#endif
uvc_handle[usb_id]->ep_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, UVC_STREAM_EP_IN | USB_DIR_IN, UVC_FIFO_TXMAXP * UVC_PKT_SPILT);
}
usb_video_feature_init(usb_id);
struct usb_camera camera = {0};
const struct uvc_reso_info yuv_fmt = {
/* .num = 2, */
.num = 1,
.reso = {
{UVC_YUV_DATA_WIDTH, UVC_YUV_DATA_HEIGHT},
/* {320, 240}, */
},
};
const struct uvc_reso_info jpg_fmt = {
/* .num = 2, */
.num = 1,
.reso = {
{UVC_YUV_DATA_WIDTH, UVC_YUV_DATA_HEIGHT},
/* {320, 240}, */
},
};
camera.video_open = uvc_video_open;
camera.video_reqbuf = uvc_video_req_buf;
camera.video_close = uvc_video_close;
#if UVC_FORMAT_MJPG
camera.jpg_info = &jpg_fmt;
#endif
#if UVC_FORMAT_I420
camera.yuv_info = &yuv_fmt;
#endif
uvc_set_camera_info(usb_id, &camera);
return 0;
__err_exit:
if (uvc_handle[usb_id]->stream_buf) {
free(uvc_handle[usb_id]->stream_buf);
}
free(uvc_handle[usb_id]);
uvc_handle[usb_id] = NULL;
return (u32) - 1;
}
u32 uvc_release(usb_dev usb_id)
{
if (uvc_handle[usb_id]) {
if (uvc_handle[usb_id]->video_close) {
uvc_handle[usb_id]->video_close(usb_id);
}
if (uvc_handle[usb_id]->ep_dma_buffer) {
usb_free_ep_dmabuffer(usb_id, uvc_handle[usb_id]->ep_dma_buffer);
uvc_handle[usb_id]->ep_dma_buffer = NULL;
}
#if USB_MALLOC_ENABLE
if (uvc_handle[usb_id]->stream_buf) {
free(uvc_handle[usb_id]->stream_buf);
}
free(uvc_handle[usb_id]);
#else
uvc_handle[usb_id]->stream_buf = NULL;
#endif
uvc_handle[usb_id] = NULL;
}
return 0;
}
/*------------------------------- uvc video interface -------------------------------*/
#define UVC_YUV_DATA_SOURCE "video0.2"
struct uvc_video_data {
int pid;
u8 *buf;
u32 len;
u8 *reqbuf;
u16 reqlen;
u16 send_len;
OS_SEM wait_sem;
OS_SEM req_sem;
u8 cur_fmt_id;
u8 cur_frame_id;
u8 init;
u8 end;
u8 err;
volatile u8 exit;
volatile u8 complete;
spinlock_t lock;
u32 cur_fps;
u32 offset;
u16 width;
u16 height;
};
static struct uvc_video_data uvc_video_info;
#if UVC_BUF_USE_STATIC
static u8 uvc_yuv_buf[UVC_YUV_DATA_WIDTH * UVC_YUV_DATA_HEIGHT * 3 / 2] ALIGNE(32);
#endif
#if UVC_FORMAT_MJPG
static const char mjpg_fmt = 0;
#if UVC_FORMAT_YUY2 || UVC_FORMAT_NV12 || UVC_FORMAT_I420
static const char yuv_fmt = 1;
#else
static const char yuv_fmt = -1;
#endif
#else
static const char mjpg_fmt = -1;
#if UVC_FORMAT_YUY2 || UVC_FORMAT_NV12 || UVC_FORMAT_I420
static const char yuv_fmt = 0;
#else
static const char yuv_fmt = -1;
#endif
#endif
__attribute__((weak)) void *get_static_yuv_buf(void)
{
return NULL;
}
static u32 uvc_send_buf(void *priv, u8 *buf, u32 len)
{
struct uvc_video_data *video_info = (struct uvc_video_data *)priv;
int ret;
int remain;
u32 offset = 0;
if (!video_info->reqlen || video_info->end) {
return 0;
}
remain = len;
while (remain > 0) {
if (video_info->exit) {
break;
}
ret = os_sem_pend(&video_info->wait_sem, 100);//先等待USB中断来请求数据包
if (ret) {
video_info->reqlen = 0;
log_error("wait uvc request err !!!\n");
return 0;
}
if (video_info->complete) {
continue;
}
spin_lock(&video_info->lock);
video_info->reqbuf = (u8 *)(buf + offset);//赋值数据包地址
video_info->send_len = video_info->reqlen;//赋值数据包大小
if (video_info->send_len > remain) {
video_info->send_len = remain;
}
offset += video_info->send_len;
remain -= video_info->send_len;
if (remain <= 0) {
video_info->end = true;
}
#if UVC_REQ_BUF_IN_THREAD
os_sem_post(&video_info->req_sem);//发送数据包信号量
#else
video_info->complete = 1;
#endif
spin_unlock(&video_info->lock);
}
#if UVC_REQ_BUF_IN_THREAD
video_info->reqlen = 0;
#endif
return offset;
}
static void uvc_yuv_task(void *priv)
{
int err;
struct video_format f = {0};
struct yuv_image yuv = {0};
struct uvc_video_data *video_info = (struct uvc_video_data *)priv;
void *dev;
/*
*step 1
*/
dev = dev_open(UVC_YUV_DATA_SOURCE, NULL);
if (!dev) {
log_error("uvc open video err !!!!\n\n");
video_info->err = true;
return;
}
/********************YUV内部加外部双BUF,上层处理时间可长一些************************/
/*
*step 2
*/
f.type = VIDEO_BUF_TYPE_VIDEO_OVERLAY;
f.pixelformat = VIDEO_PIX_FMT_YUV420;
err = dev_ioctl(dev, VIDIOC_SET_FMT, (u32)&f);
if (err) {
video_info->err = true;
log_error("uvc set video format err !!!!\n\n");
goto error;
}
/*
*step 3
*/
//BUFF配置1:使用外部BUFF,上层处理时间最大为摄像头的帧率时间 - 15ms,GC0308默认驱动处理最大时间35m
yuv.addr = (u8 *)video_info->buf;
yuv.size = video_info->len;
err = dev_ioctl(dev, VIDIOC_SET_OVERLAY, (u32)&yuv);
if (err) {
video_info->err = true;
log_error("uvc set vieo overly err !!!!\n\n");
goto error;
}
while (1) {
if (video_info->exit) {
break;
}
/*
*step 4
*/
err = dev_ioctl(dev, VIDIOC_GET_OVERLAY, (u32)&yuv);
if (!err) {
//do something in this step
/*
*step 5
*/
dev_ioctl(dev, VIDIOC_SET_HDWARE_STATE, 0);
uvc_send_buf(priv, yuv.addr, yuv.size);//注册YUV回调函数
dev_ioctl(dev, VIDIOC_SET_HDWARE_STATE, 1);
dev_ioctl(dev, VIDIOC_CLEAR_OVERLAY, 0);
}
}
error:
/*
*step 6
*/
dev_close(dev);
}
static void uvc_mjpeg_task(void *priv)
{
//TODO
}
#if !UVC_REQ_BUF_IN_THREAD
static int uvc_video_yuv_open(void)
{
if (NULL == get_static_yuv_buf()) {
uvc_video_info.buf = malloc(uvc_video_info.width * uvc_video_info.height * 3 / 2);
if (!uvc_video_info.buf) {
log_error("uvc_video_info.buf malloc err !!!\n");
return -1;
}
} else {
uvc_video_info.buf = get_static_yuv_buf();
}
uvc_video_info.len = uvc_video_info.width * uvc_video_info.height * 3 / 2;
uvc_video_info.err = false;
uvc_video_info.end = false;
uvc_video_info.exit = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
uvc_video_info.complete = 0;
os_sem_create(&uvc_video_info.wait_sem, 0);
os_sem_create(&uvc_video_info.req_sem, 0);
if (thread_fork("UVC_YUV_TASK", 8, 512, 0, &uvc_video_info.pid, uvc_yuv_task, (void *)&uvc_video_info) < 0) {
if (uvc_video_info.buf && NULL == get_static_yuv_buf()) {
free(uvc_video_info.buf);
}
uvc_video_info.buf = NULL;
return -1;
}
uvc_video_info.init = true;
return 0;
}
static int uvc_video_yuv_close(void)
{
os_sem_set(&uvc_video_info.wait_sem, 0);
os_sem_post(&uvc_video_info.wait_sem);
thread_kill(&uvc_video_info.pid, KILL_WAIT);
uvc_video_info.init = false;
uvc_video_info.end = false;
uvc_video_info.err = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
os_sem_del(&uvc_video_info.wait_sem, 0);
os_sem_del(&uvc_video_info.req_sem, 0);
if (uvc_video_info.buf && NULL == get_static_yuv_buf()) {
free(uvc_video_info.buf);
}
uvc_video_info.buf = NULL;
return 0;
}
static int uvc_video_mjpeg_open(void)
{
uvc_video_info.buf = malloc(uvc_video_info.width / 320 * 30 * 1024);
if (!uvc_video_info.buf) {
log_error("uvc_video_info.buf malloc err !!!\n");
return -1;
}
uvc_video_info.len = uvc_video_info.width / 320 * 30 * 1024;
uvc_video_info.err = false;
uvc_video_info.end = false;
uvc_video_info.exit = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
uvc_video_info.complete = 0;
os_sem_create(&uvc_video_info.wait_sem, 0);
os_sem_create(&uvc_video_info.req_sem, 0);
#if UVC_FORMAT_MJPG
#ifdef PRODUCT_NET_SERVER_ENABLE
if (build_camera_data_conn(uvc_send_buf, &uvc_video_info) == FALSE) {
free(uvc_video_info.buf);
os_sem_del(&uvc_video_info.wait_sem, 0);
os_sem_del(&uvc_video_info.req_sem, 0);
return -1;
}
#else
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
extern int user_video_rec0_open(int dev);
set_video_rt_cb(uvc_send_buf, &uvc_video_info);//注册JPEG回调函数
user_video_rec0_open(0);//打开摄像头
#endif
#endif
uvc_video_info.init = true;
return 0;
}
static int uvc_video_mjpeg_close(void)
{
#if UVC_FORMAT_MJPG
os_sem_set(&uvc_video_info.wait_sem, 0);
os_sem_post(&uvc_video_info.wait_sem);
#ifdef PRODUCT_NET_SERVER_ENABLE
delete_camera_data_conn();
#else
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
extern int user_video_rec0_close(void);
set_video_rt_cb(NULL, NULL);//设置回调函数为空
user_video_rec0_close();//关闭摄像头
#endif
#endif
uvc_video_info.init = false;
uvc_video_info.end = false;
uvc_video_info.err = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
os_sem_del(&uvc_video_info.wait_sem, 0);
os_sem_del(&uvc_video_info.req_sem, 0);
if (uvc_video_info.buf) {
free(uvc_video_info.buf);
uvc_video_info.buf = NULL;
}
return 0;
}
#endif
static int uvc_video_open(int idx, int fmt, int frame_id, int fps)
{
usb_dev usb_id = idx;
int ret;
u16 width, height;
#if UVC_TEST_ENABLE
uvc_video_info.offset = 0;
return 0;
#else /*UVC_TEST_ENABLE == 0*/
if (uvc_handle[usb_id] == NULL) {
return -1;
}
if (uvc_video_info.init) {
return 0;
}
uvc_video_info.cur_fmt_id = 0xff;
uvc_video_info.cur_frame_id = 0xff;
uvc_video_info.cur_fps = 0xffffffff;
if (fmt == yuv_fmt) {
uvc_video_info.cur_fmt_id = fmt;
uvc_video_info.cur_frame_id = frame_id;
uvc_video_info.cur_fps = fps;
uvc_video_info.width = uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + frame_id];
uvc_video_info.height = uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + frame_id];
#if UVC_REQ_BUF_IN_THREAD
width = uvc_handle[usb_id]->width[FMT_MAX_RESO_NUM + frame_id];
height = uvc_handle[usb_id]->height[FMT_MAX_RESO_NUM + frame_id];
log_info("uvc resolution %d x %d\n", width, height);
if (NULL == get_static_yuv_buf()) {
uvc_video_info.buf = malloc(width * height * 3 / 2);
if (!uvc_video_info.buf) {
log_error("uvc_video_info.buf malloc err !!!\n");
return -1;
}
} else {
uvc_video_info.buf = get_static_yuv_buf();
}
uvc_video_info.len = width * height * 3 / 2;
uvc_video_info.err = false;
uvc_video_info.end = false;
uvc_video_info.exit = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
uvc_video_info.complete = 0;
os_sem_create(&uvc_video_info.wait_sem, 0);
os_sem_create(&uvc_video_info.req_sem, 0);
ret = thread_fork("UVC_YUV_TASK", 8, 512, 0, &uvc_video_info.pid, uvc_yuv_task, (void *)&uvc_video_info);
if (ret < 0) {
if (uvc_video_info.buf && NULL == get_static_yuv_buf()) {
free(uvc_video_info.buf);
}
uvc_video_info.buf = NULL;
return ret;
}
uvc_video_info.init = true;
#else
int msg[3] = {(int)uvc_video_yuv_open, 1, 0};
os_taskq_post_type("sys_timer", Q_CALLBACK, 3, msg);
#endif
} else if (fmt == mjpg_fmt) {
uvc_video_info.cur_fmt_id = fmt;
uvc_video_info.cur_frame_id = frame_id;
uvc_video_info.cur_fps = fps;
uvc_video_info.width = uvc_handle[usb_id]->width[frame_id];
uvc_video_info.height = uvc_handle[usb_id]->height[frame_id];
#if UVC_REQ_BUF_IN_THREAD
width = uvc_handle[usb_id]->width[frame_id];
height = uvc_handle[usb_id]->height[frame_id];
log_info("uvc resolution %d x %d\n", width, height);
uvc_video_info.buf = malloc(width / 320 * 30 * 1024);
if (!uvc_video_info.buf) {
log_error("uvc_video_info.buf malloc err !!!\n");
return -1;
}
uvc_video_info.len = width / 320 * 30 * 1024;
uvc_video_info.err = false;
uvc_video_info.end = false;
uvc_video_info.exit = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
uvc_video_info.complete = 0;
os_sem_create(&uvc_video_info.wait_sem, 0);
os_sem_create(&uvc_video_info.req_sem, 0);
//暂时使用jpeg实时流的接口
#if UVC_FORMAT_MJPG
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
extern int user_video_rec0_open(int dev);
set_video_rt_cb(uvc_send_buf, &uvc_video_info);//注册JPEG回调函数
user_video_rec0_open(0);
#else
ret = thread_fork("UVC_MJPEG_TASK", 8, 2048, 0, &uvc_video_info.pid, uvc_mjpeg_task, (void *)&uvc_video_info);
if (ret < 0) {
if (uvc_video_info.buf) {
free(uvc_video_info.buf);
uvc_video_info.buf = NULL;
}
return ret;
}
#endif
uvc_video_info.init = true;
#else
int msg[3] = {(int)uvc_video_mjpeg_open, 1, 0};
os_taskq_post_type("sys_timer", Q_CALLBACK, 3, msg);
#endif
}
return 0;
#endif
}
static int uvc_video_req_buf(int idx, void *buf, u32 len, u32 *frame_end)
{
usb_dev usb_id = idx;
const u32 size = UVC_YUV_DATA_WIDTH * UVC_YUV_DATA_HEIGHT;
u32 y_len, u_len, v_len;
u32 bottom, top;
u32 len2 = len;
u32 b_offset = 0;
u32 frame_offset = 0;
#if UVC_TEST_ENABLE
#if !UVC_FORMAT_MJPG && UVC_FORMAT_I420
frame_offset = uvc_video_info.offset;
bottom = 0;
top = size;
if (frame_offset < top) {
y_len = frame_offset + len2 > top ? top - frame_offset : len2;
memset((u8 *)buf + b_offset, 0x51, y_len);
frame_offset += y_len;
len2 -= y_len;
b_offset += y_len;
}
bottom = size;
top = size + size / 4;
if (frame_offset >= bottom && frame_offset < top) {
u_len = frame_offset + len2 > top ? top - frame_offset : len2;
memset((u8 *)buf + b_offset, 0x5a, u_len);
frame_offset += u_len;
len2 -= u_len;
b_offset += u_len;
}
bottom = size + size / 4;
top = size + size / 4 + size / 4;
if (frame_offset >= bottom && frame_offset < top) {
v_len = frame_offset + len2 > top ? top - frame_offset : len2;
memset((u8 *)buf + b_offset, 0xef, v_len);
frame_offset += v_len;
len2 -= v_len;
b_offset += v_len;
}
if (frame_offset >= size * 3 / 2) {
*frame_end = 1;
frame_offset = 0;
} else {
*frame_end = 0;
}
uvc_video_info.offset = frame_offset;
return len - len2;
#else
*frame_end = 0;
return 0;
#endif
#else /*UVC_TEST_ENABLE == 0*/
int ret;
if (uvc_video_info.cur_fmt_id == yuv_fmt || uvc_video_info.cur_fmt_id == mjpg_fmt) {
if (uvc_video_info.exit) {
*frame_end = 0;
return 0;
}
uvc_video_info.reqlen = len;
if (!uvc_video_info.init || uvc_video_info.err) {
*frame_end = 0;
/* log_error("err : uvc yuv not open or open video err !!!!\n"); */
return 0;
}
#if UVC_REQ_BUF_IN_THREAD
if (!os_sem_query(&uvc_video_info.wait_sem)) {
os_sem_post(&uvc_video_info.wait_sem);
} else {
*frame_end = 0;
return 0;
}
ret = os_sem_pend(&uvc_video_info.req_sem, 10);
if (ret) {
*frame_end = 0;
return 0;
}
#else
spin_lock(&uvc_video_info.lock);
if (!uvc_video_info.complete) {
spin_unlock(&uvc_video_info.lock);
os_sem_set(&uvc_video_info.wait_sem, 0);
os_sem_post(&uvc_video_info.wait_sem);
*frame_end = 0;
return 0;
}
#endif
memcpy(buf, uvc_video_info.reqbuf, uvc_video_info.send_len);
if (uvc_video_info.end) {
*frame_end = 1;
} else {
*frame_end = 0;
}
uvc_video_info.end = false;
len2 = uvc_video_info.send_len;
uvc_video_info.complete = 0;
#if !UVC_REQ_BUF_IN_THREAD
spin_unlock(&uvc_video_info.lock);
os_sem_set(&uvc_video_info.wait_sem, 0);
os_sem_post(&uvc_video_info.wait_sem);
#endif
} else {
len2 = 0;
*frame_end = 0;
}
return len2;
#endif
}
static int uvc_video_close(int idx)
{
usb_dev usb_id = idx;
#if UVC_TEST_ENABLE
return 0;
#else /*UVC_TEST_ENABLE == 0*/
if (uvc_video_info.init == false) {
return 0;
}
if (uvc_video_info.cur_fmt_id == yuv_fmt) {
uvc_video_info.exit = true;
#if UVC_REQ_BUF_IN_THREAD
if (!os_sem_query(&uvc_video_info.wait_sem)) {
os_sem_post(&uvc_video_info.wait_sem);
}
thread_kill(&uvc_video_info.pid, KILL_WAIT);
uvc_video_info.init = false;
uvc_video_info.end = false;
uvc_video_info.err = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
os_sem_del(&uvc_video_info.wait_sem, 0);
os_sem_del(&uvc_video_info.req_sem, 0);
if (uvc_video_info.buf && NULL == get_static_yuv_buf()) {
free(uvc_video_info.buf);
}
uvc_video_info.buf = NULL;
#else
int msg[3] = {(int)uvc_video_yuv_close, 1, 0};
os_taskq_post_type("sys_timer", Q_CALLBACK, 3, msg);
#endif
} else if (uvc_video_info.cur_fmt_id == mjpg_fmt) {
uvc_video_info.exit = true;
#if UVC_REQ_BUF_IN_THREAD
if (!os_sem_query(&uvc_video_info.wait_sem)) {
os_sem_post(&uvc_video_info.wait_sem);
}
#if UVC_FORMAT_MJPG
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
extern int user_video_rec0_close(void);
set_video_rt_cb(NULL, NULL);
user_video_rec0_close();
#else
thread_kill(&uvc_video_info.pid, KILL_WAIT);
#endif
uvc_video_info.init = false;
uvc_video_info.end = false;
uvc_video_info.err = false;
uvc_video_info.reqbuf = NULL;
uvc_video_info.reqlen = 0;
os_sem_del(&uvc_video_info.wait_sem, 0);
os_sem_del(&uvc_video_info.req_sem, 0);
if (uvc_video_info.buf) {
free(uvc_video_info.buf);
uvc_video_info.buf = NULL;
}
#else
int msg[3] = {(int)uvc_video_mjpeg_close, 1, 0};
os_taskq_post_type("sys_timer", Q_CALLBACK, 3, msg);
#endif
}
uvc_video_info.init = false;
uvc_video_info.cur_fmt_id = 0xff;
uvc_video_info.cur_frame_id = 0xff;
uvc_video_info.cur_fps = 0xffffffff;
return 0;
#endif
}
#ifdef PRODUCT_NET_SERVER_ENABLE
void product_camera_reconnect(void)
{
build_camera_data_conn(uvc_send_buf, &uvc_video_info);
}
#endif
#endif