📄 uvc_driver.c
字号:
struct usb_interface *intf = streaming->intf; struct usb_host_interface *alts = &intf->altsetting[0]; unsigned char *_buffer, *buffer = alts->extra; int _buflen, buflen = alts->extralen; unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; __u32 *interval; __u16 psize; int ret; /* Skip the standard interface descriptors. */ while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) { buflen -= buffer[0]; buffer += buffer[0]; } if (buflen <= 2) return -EINVAL; /* Parse the header descriptor. */ if (buffer[2] == VS_OUTPUT_HEADER) { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " "%d OUTPUT HEADER descriptor is not supported.\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } else if (buffer[2] == VS_INPUT_HEADER) { p = buflen >= 5 ? buffer[3] : 0; n = buflen >= 12 ? buffer[12] : 0; if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d INPUT HEADER descriptor is " "invalid.\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } streaming->input.bNumFormats = p; streaming->input.bEndpointAddress = buffer[6]; streaming->input.bmInfo = buffer[7]; streaming->input.bTerminalLink = buffer[8]; streaming->input.bStillCaptureMethod = buffer[9]; streaming->input.bTriggerSupport = buffer[10]; streaming->input.bTriggerUsage = buffer[11]; streaming->input.bControlSize = n; streaming->input.bmaControls = kmalloc(p*n, GFP_KERNEL); if (streaming->input.bmaControls == NULL) return -ENOMEM; memcpy(streaming->input.bmaControls, &buffer[13], p*n); } else { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " "%d HEADER descriptor not found.\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } buflen -= buffer[0]; buffer += buffer[0]; _buffer = buffer; _buflen = buflen; /* Count the format and frame descriptors. */ while (_buflen > 2) { switch (_buffer[2]) { case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_MJPEG: nformats++; break; case VS_FORMAT_MPEG2TS: case VS_FORMAT_DV: case VS_FORMAT_FRAME_BASED: case VS_FORMAT_STREAM_BASED: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " "interface %d FORMAT %u is not supported.\n", dev->udev->devnum, alts->desc.bInterfaceNumber, _buffer[2]); break; case VS_FRAME_UNCOMPRESSED: case VS_FRAME_MJPEG: nframes++; if (_buflen > 25) nintervals += _buffer[25] ? _buffer[25] : 3; break; case VS_FRAME_FRAME_BASED: nframes++; if (_buflen > 21) nintervals += _buffer[21] ? _buffer[21] : 3; break; } _buflen -= _buffer[0]; _buffer += _buffer[0]; } if (nformats == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " "%d has no supported formats defined.\n", dev->udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } size = nformats * sizeof *format + nframes * sizeof *frame + nintervals * sizeof *interval; format = kzalloc(size, GFP_KERNEL); if (format == NULL) return -ENOMEM; frame = (struct uvc_frame*)&format[nformats]; interval = (__u32*)&frame[nframes]; streaming->format = format; streaming->nformats = nformats; /* Parse the format descriptors. */ while (buflen > 2) { switch (buffer[2]) { case VS_FORMAT_UNCOMPRESSED: case VS_FORMAT_MJPEG: format->frame = frame; ret = uvc_parse_format(dev, streaming, format, &interval, buffer, buflen); if (ret < 0) return ret; frame += format->nframes; format++; buflen -= ret; buffer += ret; continue; default: break; } buflen -= buffer[0]; buffer += buffer[0]; } /* Parse the alternate settings to find the maximum bandwidth. */ for (i = 0; i < intf->num_altsetting; ++i) { struct usb_host_endpoint *ep; alts = &intf->altsetting[i]; ep = uvc_find_endpoint(alts, streaming->input.bEndpointAddress); if (ep == NULL) continue; psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } return 0;}__u8 bProcessingUnit;__u8 bExtensionUnit;__u8 bInputTerminal;__u8 bControlSelectorUnit;__u8 bExtUnitId;static int uvc_parse_control(struct uvc_device *dev){ struct usb_device *udev = dev->udev; struct uvc_streaming *streaming; struct uvc_entity *unit, *term; struct usb_interface *intf; struct usb_host_interface *alts = dev->intf->cur_altsetting; unsigned char *buffer = alts->extra; int buflen = alts->extralen; unsigned int i, n, p; __u16 type; /* Parse the default alternate setting only, as the UVC specification * defines a single alternate setting, the default alternate setting * zero. */ while (buflen > 2) { switch (buffer[2]) { case VC_HEADER: n = buflen >= 12 ? buffer[11] : 0; if (buflen < 12 || buflen < 12 + n) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d HEADER error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } dev->uvc_version = le16_to_cpup((__le16*)&buffer[3]); dev->clock_frequency = le32_to_cpup((__le32*)&buffer[7]); /* Parse all USB Video Streaming interfaces. */ for (i = 0; i < n; ++i) { intf = usb_ifnum_to_if(udev, buffer[12+i]); if (intf == NULL) { uvc_trace(UVC_TRACE_DESCR, "device %d " "interface %d doesn't exists\n", udev->devnum, i); continue; } if (usb_interface_claimed(intf)) { uvc_trace(UVC_TRACE_DESCR, "device %d " "interface %d is already claimed\n", udev->devnum, i); continue; } usb_driver_claim_interface(&uvc_driver.driver, intf, (void*)-1); streaming = kzalloc(sizeof *streaming, GFP_KERNEL); if (streaming == NULL) continue; mutex_init(&streaming->mutex); streaming->intf = intf; //usb_get_intf(intf); //[wlq] streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; if (uvc_parse_streaming(dev, streaming) < 0) { // usb_put_intf(intf); // [wlq] kfree(streaming); continue; } list_add_tail(&streaming->list, &dev->streaming); } break; case VC_INPUT_TERMINAL: if (buflen < 8) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } /* Make sure the terminal type MSB is not null, otherwise it could be * confused with a unit. */ type = le16_to_cpup((__le16*)&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL %d has invalid " "type 0x%04x, skipping\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber, buffer[3], type); continue; } n = 0; if (type == ITT_CAMERA) { if (buflen < 15 || buflen < 15 + buffer[14]) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d INPUT_TERMINAL error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } n = buffer[14]; } term = kzalloc(sizeof *term + n, GFP_KERNEL); if (term == NULL) return -ENOMEM; term->id = buffer[3]; term->type = type; if (term->type == ITT_CAMERA) { term->camera.bControlSize = n; term->camera.bmControls = (__u8*)term + sizeof *term; term->camera.wObjectiveFocalLengthMin = le16_to_cpup((__le16*)&buffer[8]); term->camera.wObjectiveFocalLengthMax = le16_to_cpup((__le16*)&buffer[10]); term->camera.wOcularFocalLength = le16_to_cpup((__le16*)&buffer[12]); memcpy(term->camera.bmControls, &buffer[15], n); } if (buffer[7] != 0) usb_string(udev, buffer[7], term->name, sizeof term->name); else if (term->type == ITT_CAMERA) sprintf(term->name, "Camera %u", buffer[3]); else sprintf(term->name, "Input %u", buffer[3]); list_add_tail(&term->list, &dev->entities); uvc_trace(UVC_TRACE_CALLS, "[wlq-uVc] vmuvc_parse_control, Found Input Terminal.\n"); bInputTerminal = 1; //[wlq-uVc] break; case VC_OUTPUT_TERMINAL: if (buflen < 9) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d OUTPUT_TERMINAL error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } /* Make sure the terminal type MSB is not null, otherwise it could be * confused with a unit. */ type = le16_to_cpup((__le16*)&buffer[4]); if ((type & 0xff00) == 0) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d OUTPUT_TERMINAL %d has invalid " "type 0x%04x, skipping\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber, buffer[3], type); continue; } term = kzalloc(sizeof *term, GFP_KERNEL); if (term == NULL) return -ENOMEM; term->id = buffer[3]; term->type = type; term->output.bSourceID = buffer[7]; if (buffer[8] != 0) usb_string(udev, buffer[8], term->name, sizeof term->name); else sprintf(term->name, "Output %u", buffer[3]); list_add_tail(&term->list, &dev->entities); break; case VC_SELECTOR_UNIT: p = buflen >= 5 ? buffer[4] : 0; if (buflen < 5 || buflen < 6 + p) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d SELECTOR_UNIT error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } unit = kzalloc(sizeof *unit + p, GFP_KERNEL); if (unit == NULL) return -ENOMEM; unit->id = buffer[3]; unit->type = buffer[2]; unit->selector.bNrInPins = buffer[5]; unit->selector.baSourceID = (__u8*)unit + sizeof *unit; memcpy(unit->selector.baSourceID, &buffer[5], p); if (buffer[5+p] != 0) usb_string(udev, buffer[5+p], unit->name, sizeof unit->name); else sprintf(unit->name, "Selector %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); uvc_trace(UVC_TRACE_CALLS, "[wlq-uVc] vmuvc_parse_control, Found Control Selector Unit.\n"); bControlSelectorUnit = 1; // [wlq-uVc] break; case VC_PROCESSING_UNIT: n = buflen >= 8 ? buffer[7] : 0; if (buflen < 8 + n) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d PROCESSING_UNIT error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } unit = kzalloc(sizeof *unit + n, GFP_KERNEL); if (unit == NULL) return -ENOMEM; unit->id = buffer[3]; unit->type = buffer[2]; unit->processing.bSourceID = buffer[4]; unit->processing.wMaxMultiplier = le16_to_cpup((__le16*)&buffer[5]); unit->processing.bControlSize = buffer[7]; unit->processing.bmControls = (__u8*)unit + sizeof *unit; memcpy(unit->processing.bmControls, &buffer[8], n); unit->processing.bmVideoStandards = buffer[9+n]; if (buffer[8+n] != 0) usb_string(udev, buffer[8+n], unit->name, sizeof unit->name); else sprintf(unit->name, "Processing %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); uvc_trace(UVC_TRACE_CALLS, "[wlq-uVc] vmuvc_parse_control, Found Processing Unit.\n"); bProcessingUnit = 1; //[wlq-uVc] break; case VC_EXTENSION_UNIT: p = buflen >= 22 ? buffer[21] : 0; n = buflen >= 24 + p ? buffer[22+p] : 0; if (buflen < 24 + p + n) { uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " "interface %d EXTENSION_UNIT error\n", udev->devnum, dev->intf->cur_altsetting->desc.bInterfaceNumber); return -EINVAL; } unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL); if (unit == NULL) return -ENOMEM; bExtUnitId = unit->id = buffer[3]; unit->type = buffer[2]; memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; unit->extension.bNrInPins = le16_to_cpup((__le16*)&buffer[21]); unit->extension.baSourceID = (__u8*)unit + sizeof *unit; memcpy(unit->extension.baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; unit->extension.bmControls = (__u8*)unit + sizeof *unit + p; memcpy(unit->extension.bmControls, &buffer[23+p], n); if (buffer[23+p+n] != 0) usb_string(udev, buffer[23+p+n], unit->name, sizeof unit->name); else sprintf(unit->name, "Extension %u", buffer[3]); list_add_tail(&unit->list, &dev->entities); uvc_trace(UVC_TRACE_CALLS, "[wlq-uVc] vmuvc_parse_control, Found Extension Unit.\n"); bExtensionUnit = 1; //[wlq-uVc] break; default: uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE " "descriptor (%u)\n", buffer[2]); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -