UVC camera driver (iii) configure the camera, real time data acquisition

Previous analysis of the hardware model and the descriptor UVC camera, for a usb camera, the internal roughly divided into a VC interfaces and a VS interfaces, VC internal interface has many unit and a terminal to "control" the camera, for example, we can Process unit setting white balance, exposure and the like. For Interface VS, the VS standard interfaces often contain many settings, each set contains a real-time transport endpoint, although they may be the same endpoint address, but they have different maximum transmission packet size, the Class specific VS interface, comprising a plurality Format, each comprising a plurality Format Frame, Format refers YUYV MJPG like, Frame 480 is a variety of resolution 640 * 480 * 320 and the like. These information is obtained by analyzing the descriptor.
 

VideoStreaming Requests

  Reference UVC 1.5 Class specification 4.3 
Write pictures described here

We need to control transmission and communication VS, Probe and commit provided, the request format with reference to FIG.

bmRequestType request type, the reference standard USB protocol
bRequest subclasses. 8-A is defined in the Table
the CS, Control Selector defined in Table A-16, for example, a probe or the commit
the wIndex high byte is zero, the low byte interface number
wLength and data, like standard USB protocol, data length and data
parameter setting procedure requires the host and the USB device to negotiate, the negotiation process is substantially as shown below: 
 

Host first desired settings sent to the USB device (PROBE)
device will Host the desired settings can be modified within the capacity of its own, the return to the Host (PROBE)
Host considered setting feasible, Commit submission (COMMIT)
Set interface is currently set to one set 
   
what data you negotiate? These data define where? Reference Table 4-75, which use which contains a Frame Frame which the frame frequency, the first transmission packet size, and the like. 
Reference Code:
 

static int myuvc_try_streaming_params(struct myuvc_streaming_control *ctrl)
{
    __u8 *data;
    __u16 size;
    int ret;
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;

    memset(ctrl, 0, sizeof *ctrl);

    ctrl->bmHint = 1;   /* dwFrameInterval */
    ctrl->bFormatIndex = 1;
    ctrl->bFrameIndex  = 1;
    ctrl->dwFrameInterval = 333333;
    ctrl->dwClockFrequency = 48000000;
    ctrl->wCompQuality = 61;
    size = 34;
    data = kzalloc(size, GFP_KERNEL);
    if (data == NULL)
        return -ENOMEM;

    *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
    data[2] = ctrl->bFormatIndex;
    data[3] = ctrl->bFrameIndex;
    *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
    *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
    *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
    *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
    *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
    *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
    put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
    put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);

    if (size == 34) {
        put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
        data[30] = ctrl->bmFramingInfo;
        data[31] = ctrl->bPreferedVersion;
        data[32] = ctrl->bMinVersion;
        data[33] = ctrl->bMaxVersion;
    }

    pipe = usb_sndctrlpipe(myuvc_udev, 0);
    type |= USB_DIR_OUT;

    ret = usb_control_msg(myuvc_udev, pipe, 0x01, type, 0x01 << 8,
            0 << 8 | myuvc_streaming_intf, data, size, 5000);

    kfree (date);

    return (right <0)? right: 0;
}

static int myuvc_get_streaming_params(struct myuvc_streaming_control *ctrl)
{
    __u8 *data;
    __u16 size;
    int ret;
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;

    size = 34;
    data = kmalloc(size, GFP_KERNEL);
    if (data == NULL)
        return -ENOMEM;

    pipe = usb_rcvctrlpipe(myuvc_udev, 0);
    type |= USB_DIR_IN;

    ret = usb_control_msg(myuvc_udev, pipe, 0x81, type, 0x01 << 8,
            0 << 8 | myuvc_streaming_intf, data, size, 5000);

    if (ret < 0)
        goto done;

    ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
    ctrl->bFormatIndex = data[2];
    ctrl->bFrameIndex = data[3];
    ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
    ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
    ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
    ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
    ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
    ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
    ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
    ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);

    if (size == 34) {
        ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
        ctrl->bmFramingInfo = data[30];
        ctrl->bPreferedVersion = data[31];
        ctrl->bMinVersion = data[32];
        ctrl->bMaxVersion = data[33];
    } else {
        //ctrl->dwClockFrequency = video->dev->clock_frequency;
        ctrl->bmFramingInfo = 0;
        ctrl->bPreferedVersion = 0;
        ctrl->bMinVersion = 0;
        ctrl->bMaxVersion = 0;
    }

done:
    kfree(data);

    return (right <0)? right: 0;
}

static int myuvc_set_streaming_params(struct myuvc_streaming_control *ctrl)
{
    __u8 *data;
    __u16 size;
    int ret;
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;

    size = 34;
    data = kzalloc(size, GFP_KERNEL);
    if (data == NULL)
        return -ENOMEM;

    *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
    data[2] = ctrl->bFormatIndex;
    data[3] = ctrl->bFrameIndex;
    *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
    *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
    *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
    *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
    *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
    *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
    put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
    put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);

    if (size == 34) {
        put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
        data[30] = ctrl->bmFramingInfo;
        data[31] = ctrl->bPreferedVersion;
        data[32] = ctrl->bMinVersion;
        data[33] = ctrl->bMaxVersion;
    }

    pipe = usb_sndctrlpipe(myuvc_udev, 0);
    type |= USB_DIR_OUT;

    ret = usb_control_msg(myuvc_udev, pipe, 0x01, type, 0x02 << 8,
            0 << 8 | myuvc_streaming_intf, data, size, 5000);

    kfree (date);

    return (right <0)? right: 0;

}

VideoControl Requests
  Here we analyze VC interfaces in the Processing Unit Control Requests brightness, for example: 
 


static void myuvc_set_le_value(__s32 value, __u8 *data)
{
    int bits = 16;
    int offset = 0;
    __u8 mask;

    data += offset / 8;
    offset &= 7;

    for (; bits > 0; data++) {
        mask = ((1LL << bits) - 1) << offset;
        *data = (*data & ~mask) | ((value << offset) & mask);
        value >>= offset ? offset : 8;
        bits -= 8 - offset;
        offset = 0;
    }
}

static __s32 myuvc_get_le_value(const __u8 *data)
{
    int bits = 16;
    int offset = 0;
    __s32 value = 0;
    __u8 mask;

    data += offset / 8;
    offset &= 7;
    mask = ((1LL << bits) - 1) << offset;

    for (; bits > 0; data++) {
        __u8 byte = *data & mask;
        value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
        bits -= 8 - (offset > 0 ? offset : 0);
        offset -= 8;
        mask = (1 << bits) - 1;
    }

    /* Sign-extend the value if needed. */
    value |= -(value & (1 << (16 - 1)));

    return value;
}

/* 参考:uvc_query_v4l2_ctrl */    
int myuvc_vidioc_queryctrl (struct file *file, void *fh,
                struct v4l2_queryctrl *ctrl)
{
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;
    int ret;
    u8 data[2];

    if (ctrl->id != V4L2_CID_BRIGHTNESS)
        return -EINVAL;

    memset(ctrl, 0, sizeof *ctrl);
    ctrl->id   = V4L2_CID_BRIGHTNESS;
    ctrl->type = V4L2_CTRL_TYPE_INTEGER;
    strcpy(ctrl->name, "MyUVC_BRIGHTNESS");
    ctrl->flags = 0;

    pipe = usb_rcvctrlpipe(udev, 0);
    type |= USB_DIR_IN;

    / * These values are determined to initiate a USB * /
    RET = usb_control_msg (the udev, pipe, GET_MIN, type, PU_BRIGHTNESS_CONTROL <<. 8,
            ProcessingUnitID. 8 << | myuvc_control_intf, Data, 2, 5000);
    IF (RET = 2!)
        Return - the EIO;
    Ctrl-> Minimum = myuvc_get_le_value (Data); / * * Note signedness /


    ret = usb_control_msg(udev, pipe, GET_MAX, type,  PU_BRIGHTNESS_CONTROL << 8,
            ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
    if (ret != 2)
        return -EIO;
    ctrl->maximum = myuvc_get_le_value(data);   /* Note signedness */

    ret = usb_control_msg(udev, pipe, GET_RES, type, PU_BRIGHTNESS_CONTROL << 8,
             ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
    if (ret != 2)
        return -EIO;
    ctrl->step = myuvc_get_le_value(data);  /* Note signedness */

    ret = usb_control_msg(udev, pipe, GET_DEF, type, PU_BRIGHTNESS_CONTROL << 8,
            ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
    if (ret != 2)
        return -EIO;
    ctrl->default_value = myuvc_get_le_value(data); /* Note signedness */

    printk("Brightness: min =%d, max = %d, step = %d, default = %d\n", ctrl->minimum, ctrl->maximum, ctrl->step, ctrl->default_value);

    return 0;
}

/* 参考 : uvc_ctrl_get */
int myuvc_vidioc_g_ctrl (struct file *file, void *fh,
                struct v4l2_control *ctrl)
{
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;
    int ret;
    u8 data[2];

    if (ctrl->id != V4L2_CID_BRIGHTNESS)
        return -EINVAL;

    pipe = usb_rcvctrlpipe(udev, 0);
    type |= USB_DIR_IN;

    ret = usb_control_msg(udev, pipe, GET_CUR, type, PU_BRIGHTNESS_CONTROL << 8,
            ProcessingUnitID << 8 | myuvc_control_intf, data, 2, 5000);
    if (ret != 2)
        return -EIO;
    ctrl->value = myuvc_get_le_value(data); /* Note signedness */

    return 0;
}

/* 参考: uvc_ctrl_set/uvc_ctrl_commit */
int myuvc_vidioc_s_ctrl (struct file *file, void *fh,
                struct v4l2_control *ctrl)
{
    __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
    unsigned int pipe;
    int ret;
    u8 data[2];

    if (ctrl->id != V4L2_CID_BRIGHTNESS)
        return -EINVAL;

    myuvc_set_le_value(ctrl->value, data);

    pipe = usb_sndctrlpipe(udev, 0);
    type |= USB_DIR_OUT;

    ret = usb_control_msg(udev, pipe, SET_CUR, type, PU_BRIGHTNESS_CONTROL << 8,
            ProcessingUnitID  << 8 | myuvc_control_intf, data, 2, 5000);
    if (ret != 2)
        return -EIO;

    0 return;
}


Data acquisition
  data acquisition, and we need to end the communication interfaces provided in the VS standard real-time data acquisition, distribution, set, then URB. 
  640 * 320 resolution images, for example, each pixel 16bit, so an image space 640 * 320 * 2 bytes, for the first time my transmission imaging, 3060 bytes. Note that, in the camera driver Buffer limits the number of a maximum of 32 URB the UVC standard, so the data can be carried as a URB 3060 * 32, has been calculated, a plurality of image data needs to be transmitted URB. Therefore, the user space Buffer, it may be included in the copy of the image data to one URB data in two images, you do not need to put processed before a second frame of image data is discarded, that would result in loss of image data.

static int myuvc_alloc_init_urbs(void)
{
    u16 psize;
    u32 size;
    int npackets;
    int i,j;
    struct urb *urb;
    //struct urb *urb;

    psize = 3060; / * maximum number of bytes can be transmitted in real time to a transport endpoint * /
    size = 614400; / * length of a maximum data * /
    npackets = DIV_ROUND_UP (size, PSize);
    IF (npackets> 32)
        npackets = 32;
    myprintk ( "D npackets PSize% D% \ n-", PSize, npackets);
    size = PSize * npackets;
    for (I = 0; I <. 5; I ++) { 
        / * * 1. dispensing usb_buffers /
        urb_buffer [I] = usb_alloc_coherent (
            myuvc_udev, size,
            GFP_KERNEL | __GFP_NOWARN, & urb_dma [I]);

        /* 2. 分配urb */
        myurb[i] = usb_alloc_urb(npackets, GFP_KERNEL);

        if (!urb_buffer[i] || !myurb[i])
        {
            //myuvc_uninit_urbs();
            myprintk("alloc buffer or urb failed\n");
            return -ENOMEM;
        }
    }

    /* 3. 设置urb */ 
    for (i = 0; i < 5; ++i) {
        urb = myurb[i];
        urb->dev = myuvc_udev;
        urb->context = NULL;
        urb->pipe = usb_rcvisocpipe(myuvc_udev, 0x81);
        urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
        urb->interval = 1;
        urb->transfer_buffer = urb_buffer[i];
        urb->transfer_dma = urb_dma[i];
        urb->complete = myuvc_video_complete;
        urb->number_of_packets = npackets;
        urb->transfer_buffer_length = size;

        for (j = 0; j < npackets; ++j) {
            urb->iso_frame_desc[j].offset = j * psize;
            urb->iso_frame_desc[j].length = psize;
        }
    }  
    return 0;
}

static void myuvc_video_complete(struct urb *urb)
{
    u8 *src;
    //u8 *dest;
    int ret, i;
    int len;
    int maxlen;
//    int nbytes;
//    struct myuvc_buffer *buf;
    myprintk("video complete\n");
    switch (urb->status) {
    case 0:
        break;

    default:
        myprintk("Non-zero status (%d) in video "
            "completion handler.\n", urb->status);
        return;
    }

    for (i = 0; i < urb->number_of_packets; ++i) {
        if (urb->iso_frame_desc[i].status < 0) {
            myprintk("USB isochronous frame "
                "lost (%d).\n", urb->iso_frame_desc[i].status);
            continue;
        }

        src  = urb->transfer_buffer + urb->iso_frame_desc[i].offset;

        //dest = myuvc_queue.mem + buf->buf.m.offset + buf->buf.bytesused;

        urb- = len> iso_frame_desc [I] .actual_length;
        myprintk ( "len% D \ n-", urb-> iso_frame_desc [I] .actual_length);
        / * determine whether the data is valid * /
        / * the URB Data meanings:
         * Data [ 0]: header length
         * data [1]: error status
         * /
        IF (len <2 || the src [0] <2 || the src [0]> len)
            Continue;

        /* Skip payloads marked with the error bit ("error frames"). */
        if (src[1] & UVC_STREAM_ERR) {
            myprintk("Dropping payload (error bit set).\n");
            continue;
        }

        / * Data length after the head was removed * /
        len - the src = [0];

        / * Buffer can also stored number data * /
        // the maxlen = buf -> to buf.length - buf -> buf.bytesused;
        // nbytes = min (len, the maxlen);

        / * Copy the data * /
        // the memcpy (dest, the src the src + [0], nbytes);
        //buf->buf.bytesused + = nbytes;

        / * Is determined whether all the data of one frame has been received * /
        IF (len> the maxlen) {
            // buf -> State = VIDEOBUF_DONE;
        }

        /* Mark the buffer as done if the EOF marker is set. */
        if (src[1] & UVC_STREAM_EOF) {
            myprintk("Frame complete (EOF found).\n");
            if (len == 0)
                myprintk("EOF in empty payload.\n");
            //buf->state = VIDEOBUF_DONE;
        }

    }

    / * Resubmission URB * /


    if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
        myprintk("Failed to resubmit video URB (%d).\n", ret);
    }
}
--------------------- 
 

Guess you like

Origin blog.csdn.net/u010783226/article/details/93299554