119b602bcSIthamar R. Adema/*
251a01ea0SJérôme Duval * Copyright 2011, Gabriel Hartmann, gabriel.hartmann@gmail.com.
326a912cdSJérôme Duval * Copyright 2011, J��r��me Duval, korli@users.berlios.de.
419b602bcSIthamar R. Adema * Copyright 2009, Ithamar Adema, <ithamar.adema@team-embedded.nl>.
519b602bcSIthamar R. Adema * Distributed under the terms of the MIT License.
619b602bcSIthamar R. Adema */
719b602bcSIthamar R. Adema
802af02f9SJérôme Duval
919b602bcSIthamar R. Adema#include "UVCCamDevice.h"
1051a01ea0SJérôme Duval#include "UVCDeframer.h"
1102af02f9SJérôme Duval
1219b602bcSIthamar R. Adema#include <stdio.h>
1351a01ea0SJérôme Duval#include <stdlib.h>
1451a01ea0SJérôme Duval#include <ParameterWeb.h>
1551a01ea0SJérôme Duval#include <media/Buffer.h>
1622f4c339SJérôme Duval
1702af02f9SJérôme Duval
1819b602bcSIthamar R. Ademausb_webcam_support_descriptor kSupportedDevices[] = {
1919b602bcSIthamar R. Adema	// ofcourse we support a generic UVC device...
20a46e462dSPhilippe Houdoin	{{ CC_VIDEO, SC_VIDEOCONTROL, 0, 0, 0 }, "Generic UVC", "Video Class", "??" },
2119b602bcSIthamar R. Adema	// ...whilst the following IDs were 'stolen' from a recent Linux driver:
2219b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x045e, 0x00f8, }, "Microsoft",     "Lifecam NX-6000",                 "??" },
2319b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x045e, 0x0723, }, "Microsoft",     "Lifecam VX-7000",                 "??" },
2419b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c1, }, "Logitech",      "QuickCam Fusion",                 "??" },
2519b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c2, }, "Logitech",      "QuickCam Orbit MP",               "??" },
2619b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c3, }, "Logitech",      "QuickCam Pro for Notebook",       "??" },
2719b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c5, }, "Logitech",      "QuickCam Pro 5000",               "??" },
2819b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c6, }, "Logitech",      "QuickCam OEM Dell Notebook",      "??" },
2919b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x046d, 0x08c7, }, "Logitech",      "QuickCam OEM Cisco VT Camera II", "??" },
30a46e462dSPhilippe Houdoin	{{ 0, 0, 0, 0x046d, 0x0821, }, "Logitech",      "HD Pro Webcam C910",              "??" },
3119b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x05ac, 0x8501, }, "Apple",         "Built-In iSight",                 "??" },
3219b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x05e3, 0x0505, }, "Genesys Logic", "USB 2.0 PC Camera",               "??" },
3319b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x0e8d, 0x0004, }, "N/A",           "MT6227",                          "??" },
3419b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x174f, 0x5212, }, "Syntek",        "(HP Spartan)",                    "??" },
3519b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x174f, 0x5931, }, "Syntek",        "(Samsung Q310)",                  "??" },
3619b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x174f, 0x8a31, }, "Syntek",        "Asus F9SG",                       "??" },
3719b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x174f, 0x8a33, }, "Syntek",        "Asus U3S",                        "??" },
3819b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x17ef, 0x480b, }, "N/A",           "Lenovo Thinkpad SL500",           "??" },
3919b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x18cd, 0xcafe, }, "Ecamm",         "Pico iMage",                      "??" },
4019b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x19ab, 0x1000, }, "Bodelin",       "ProScopeHR",                      "??" },
4119b602bcSIthamar R. Adema	{{ 0, 0, 0, 0x1c4f, 0x3000, }, "SiGma Micro",   "USB Web Camera",                  "??" },
4219b602bcSIthamar R. Adema	{{ 0, 0, 0, 0, 0}, NULL, NULL, NULL }
4319b602bcSIthamar R. Adema};
4419b602bcSIthamar R. Adema
457a87728eSJérôme Duval/* Table 2-1 Compression Formats of USB Video Payload Uncompressed */
4626a912cdSJérôme Duvalusbvc_guid kYUY2Guid = {0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
4726a912cdSJérôme Duval	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
4826a912cdSJérôme Duvalusbvc_guid kNV12Guid = {0x4e, 0x56, 0x31, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80,
4926a912cdSJérôme Duval	0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71};
5002af02f9SJérôme Duval
5102af02f9SJérôme Duvalstatic void
5226a912cdSJérôme Duvalprint_guid(const usbvc_guid guid)
5319b602bcSIthamar R. Adema{
54f2df488aSJérôme Duval	if (!memcmp(guid, kYUY2Guid, sizeof(usbvc_guid)))
55f2df488aSJérôme Duval		printf("YUY2");
56f2df488aSJérôme Duval	else if (!memcmp(guid, kNV12Guid, sizeof(usbvc_guid)))
57f2df488aSJérôme Duval		printf("NV12");
58f2df488aSJérôme Duval	else {
59f2df488aSJérôme Duval		printf("%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
60f2df488aSJérôme Duval			"%02x:%02x:%02x:%02x", guid[0], guid[1], guid[2], guid[3], guid[4],
61f2df488aSJérôme Duval			guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11],
62f2df488aSJérôme Duval			guid[12], guid[13], guid[14], guid[15]);
63f2df488aSJérôme Duval	}
6419b602bcSIthamar R. Adema}
6519b602bcSIthamar R. Adema
6619b602bcSIthamar R. Adema
6751a01ea0SJérôme DuvalUVCCamDevice::UVCCamDevice(CamDeviceAddon& _addon, BUSBDevice* _device)
6822f4c339SJérôme Duval	: CamDevice(_addon, _device),
6922f4c339SJérôme Duval	fHeaderDescriptor(NULL),
7051a01ea0SJérôme Duval	fInterruptIn(NULL),
7151a01ea0SJérôme Duval	fUncompressedFormatIndex(1),
7251a01ea0SJérôme Duval	fUncompressedFrameIndex(1)
7319b602bcSIthamar R. Adema{
7451a01ea0SJérôme Duval	fDeframer = new UVCDeframer(this);
7522f4c339SJérôme Duval	SetDataInput(fDeframer);
7667eb6cdeSJérôme Duval
7726a912cdSJérôme Duval	const BUSBConfiguration* config;
7826a912cdSJérôme Duval	const BUSBInterface* interface;
7926a912cdSJérôme Duval	usb_descriptor* generic;
8019b602bcSIthamar R. Adema	uint8 buffer[1024];
8119b602bcSIthamar R. Adema
8251a01ea0SJérôme Duval	generic = (usb_descriptor*)buffer;
8319b602bcSIthamar R. Adema
8426a912cdSJérôme Duval	for (uint32 i = 0; i < _device->CountConfigurations(); i++) {
8526a912cdSJérôme Duval		config = _device->ConfigurationAt(i);
86f254805bSFrançois Revol		if (config == NULL)
87f254805bSFrançois Revol			continue;
88d7b15506SJérôme Duval		_device->SetConfiguration(config);
8926a912cdSJérôme Duval		for (uint32 j = 0; j < config->CountInterfaces(); j++) {
9026a912cdSJérôme Duval			interface = config->InterfaceAt(j);
91f254805bSFrançois Revol			if (interface == NULL)
92f254805bSFrançois Revol				continue;
9319b602bcSIthamar R. Adema
9426a912cdSJérôme Duval			if (interface->Class() == CC_VIDEO && interface->Subclass()
9526a912cdSJérôme Duval				== SC_VIDEOCONTROL) {
9626a912cdSJérôme Duval				printf("UVCCamDevice: (%lu,%lu): Found Video Control "
9726a912cdSJérôme Duval					"interface.\n", i, j);
9819b602bcSIthamar R. Adema
9919b602bcSIthamar R. Adema				// look for class specific interface descriptors and parse them
10026a912cdSJérôme Duval				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
10126a912cdSJérôme Duval					sizeof(buffer)) == B_OK; k++) {
102d7b15506SJérôme Duval					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
103d7b15506SJérôme Duval						| USB_DESCRIPTOR_INTERFACE))
104d7b15506SJérôme Duval						continue;
105d7b15506SJérôme Duval					fControlIndex = interface->Index();
106d7b15506SJérôme Duval					_ParseVideoControl((const usbvc_class_descriptor*)generic,
107d7b15506SJérôme Duval						generic->generic.length);
10826a912cdSJérôme Duval				}
109d7b15506SJérôme Duval				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
11051a01ea0SJérôme Duval					const BUSBEndpoint* e = interface->EndpointAt(i);
111d7b15506SJérôme Duval					if (e && e->IsInterrupt() && e->IsInput()) {
112d7b15506SJérôme Duval						fInterruptIn = e;
113d7b15506SJérôme Duval						break;
114d7b15506SJérôme Duval					}
115d7b15506SJérôme Duval				}
11619b602bcSIthamar R. Adema				fInitStatus = B_OK;
11726a912cdSJérôme Duval			} else if (interface->Class() == CC_VIDEO && interface->Subclass()
11826a912cdSJérôme Duval				== SC_VIDEOSTREAMING) {
119d7b15506SJérôme Duval				printf("UVCCamDevice: (%lu,%lu): Found Video Streaming "
120d7b15506SJérôme Duval					"interface.\n", i, j);
12119b602bcSIthamar R. Adema
12219b602bcSIthamar R. Adema				// look for class specific interface descriptors and parse them
12326a912cdSJérôme Duval				for (uint32 k = 0; interface->OtherDescriptorAt(k, generic,
12426a912cdSJérôme Duval					sizeof(buffer)) == B_OK; k++) {
125d7b15506SJérôme Duval					if (generic->generic.descriptor_type != (USB_REQTYPE_CLASS
126d7b15506SJérôme Duval						| USB_DESCRIPTOR_INTERFACE))
127d7b15506SJérôme Duval						continue;
128d7b15506SJérôme Duval					fStreamingIndex = interface->Index();
129d7b15506SJérôme Duval					_ParseVideoStreaming((const usbvc_class_descriptor*)generic,
130d7b15506SJérôme Duval						generic->generic.length);
131d7b15506SJérôme Duval				}
13267eb6cdeSJérôme Duval
133d7b15506SJérôme Duval				for (uint32 k = 0; k < interface->CountEndpoints(); k++) {
13451a01ea0SJérôme Duval					const BUSBEndpoint* e = interface->EndpointAt(i);
135d7b15506SJérôme Duval					if (e && e->IsIsochronous() && e->IsInput()) {
136d7b15506SJérôme Duval						fIsoIn = e;
137d7b15506SJérôme Duval						break;
13826a912cdSJérôme Duval					}
13926a912cdSJérôme Duval				}
14019b602bcSIthamar R. Adema			}
14119b602bcSIthamar R. Adema		}
14219b602bcSIthamar R. Adema	}
14319b602bcSIthamar R. Adema}
14419b602bcSIthamar R. Adema
14502af02f9SJérôme Duval
146d7b15506SJérôme DuvalUVCCamDevice::~UVCCamDevice()
147d7b15506SJérôme Duval{
14851a01ea0SJérôme Duval	free(fHeaderDescriptor);
149d7b15506SJérôme Duval}
150d7b15506SJérôme Duval
151d7b15506SJérôme Duval
15202af02f9SJérôme Duvalvoid
153d7b15506SJérôme DuvalUVCCamDevice::_ParseVideoStreaming(const usbvc_class_descriptor* _descriptor,
15426a912cdSJérôme Duval	size_t len)
15519b602bcSIthamar R. Adema{
15651a01ea0SJérôme Duval	switch (_descriptor->descriptorSubtype) {
15719b602bcSIthamar R. Adema		case VS_INPUT_HEADER:
15826a912cdSJérôme Duval		{
15951a01ea0SJérôme Duval			const usbvc_input_header_descriptor* descriptor
16051a01ea0SJérôme Duval				= (const usbvc_input_header_descriptor*)_descriptor;
16126a912cdSJérôme Duval			printf("VS_INPUT_HEADER:\t#fmts=%d,ept=0x%x\n", descriptor->numFormats,
16226a912cdSJérôme Duval				descriptor->endpointAddress);
16326a912cdSJérôme Duval			if (descriptor->info & 1)
16426a912cdSJérôme Duval				printf("\tDynamic Format Change supported\n");
16526a912cdSJérôme Duval			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
16626a912cdSJérôme Duval			printf("\tstill capture method=%d\n", descriptor->stillCaptureMethod);
16726a912cdSJérôme Duval			if (descriptor->triggerSupport) {
16826a912cdSJérôme Duval				printf("\ttrigger button fixed to still capture=%s\n",
16926a912cdSJérôme Duval					descriptor->triggerUsage ? "no" : "yes");
17026a912cdSJérôme Duval			}
17151a01ea0SJérôme Duval			const uint8* controls = descriptor->controls;
17226a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->numFormats; i++,
17326a912cdSJérôme Duval				controls += descriptor->controlSize) {
17419b602bcSIthamar R. Adema				printf("\tfmt%d: %s %s %s %s - %s %s\n", i,
17526a912cdSJérôme Duval					(*controls & 1) ? "wKeyFrameRate" : "",
17626a912cdSJérôme Duval					(*controls & 2) ? "wPFrameRate" : "",
17726a912cdSJérôme Duval					(*controls & 4) ? "wCompQuality" : "",
17826a912cdSJérôme Duval					(*controls & 8) ? "wCompWindowSize" : "",
17926a912cdSJérôme Duval					(*controls & 16) ? "<Generate Key Frame>" : "",
18026a912cdSJérôme Duval					(*controls & 32) ? "<Update Frame Segment>" : "");
18119b602bcSIthamar R. Adema			}
18219b602bcSIthamar R. Adema			break;
18326a912cdSJérôme Duval		}
18419b602bcSIthamar R. Adema		case VS_FORMAT_UNCOMPRESSED:
18567eb6cdeSJérôme Duval		{
18651a01ea0SJérôme Duval			const usbvc_format_descriptor* descriptor
18751a01ea0SJérôme Duval				= (const usbvc_format_descriptor*)_descriptor;
18851a01ea0SJérôme Duval			fUncompressedFormatIndex = descriptor->formatIndex;
18926a912cdSJérôme Duval			printf("VS_FORMAT_UNCOMPRESSED:\tbFormatIdx=%d,#frmdesc=%d,guid=",
19026a912cdSJérôme Duval				descriptor->formatIndex, descriptor->numFrameDescriptors);
19126a912cdSJérôme Duval			print_guid(descriptor->uncompressed.format);
19226a912cdSJérôme Duval			printf("\n\t#bpp=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
19326a912cdSJérôme Duval				descriptor->uncompressed.bytesPerPixel,
19426a912cdSJérôme Duval				descriptor->uncompressed.defaultFrameIndex,
19526a912cdSJérôme Duval				descriptor->uncompressed.aspectRatioX,
19626a912cdSJérôme Duval				descriptor->uncompressed.aspectRatioY);
19719b602bcSIthamar R. Adema			printf("\tbmInterlaceFlags:\n");
19826a912cdSJérôme Duval			if (descriptor->uncompressed.interlaceFlags & 1)
19926a912cdSJérôme Duval				printf("\tInterlaced stream or variable\n");
20026a912cdSJérôme Duval			printf("\t%d fields per frame\n",
20126a912cdSJérôme Duval				(descriptor->uncompressed.interlaceFlags & 2) ? 1 : 2);
20226a912cdSJérôme Duval			if (descriptor->uncompressed.interlaceFlags & 4)
20326a912cdSJérôme Duval				printf("\tField 1 first\n");
20419b602bcSIthamar R. Adema			printf("\tField Pattern: ");
20551a01ea0SJérôme Duval			switch ((descriptor->uncompressed.interlaceFlags & 0x30) >> 4) {
20619b602bcSIthamar R. Adema				case 0: printf("Field 1 only\n"); break;
20719b602bcSIthamar R. Adema				case 1: printf("Field 2 only\n"); break;
20819b602bcSIthamar R. Adema				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
20919b602bcSIthamar R. Adema				case 3: printf("Random pattern of fields 1 and 2\n"); break;
21019b602bcSIthamar R. Adema			}
21126a912cdSJérôme Duval			if (descriptor->uncompressed.copyProtect)
21226a912cdSJérôme Duval				printf("\tRestrict duplication\n");
21319b602bcSIthamar R. Adema			break;
21426a912cdSJérôme Duval		}
21526a912cdSJérôme Duval		case VS_FRAME_MJPEG:
21619b602bcSIthamar R. Adema		case VS_FRAME_UNCOMPRESSED:
21726a912cdSJérôme Duval		{
21851a01ea0SJérôme Duval			const usbvc_frame_descriptor* descriptor
21951a01ea0SJérôme Duval				= (const usbvc_frame_descriptor*)_descriptor;
22051a01ea0SJérôme Duval			if (_descriptor->descriptorSubtype == VS_FRAME_UNCOMPRESSED) {
22126a912cdSJérôme Duval				printf("VS_FRAME_UNCOMPRESSED:");
22251a01ea0SJérôme Duval				fUncompressedFrames.AddItem(
22367eb6cdeSJérôme Duval					new usbvc_frame_descriptor(*descriptor));
22451a01ea0SJérôme Duval			} else {
22551a01ea0SJérôme Duval				printf("VS_FRAME_MJPEG:");
22651a01ea0SJérôme Duval				fMJPEGFrames.AddItem(new usbvc_frame_descriptor(*descriptor));
22751a01ea0SJérôme Duval			}
22826a912cdSJérôme Duval			printf("\tbFrameIdx=%d,stillsupported=%s,"
22926a912cdSJérôme Duval				"fixedframerate=%s\n", descriptor->frameIndex,
23026a912cdSJérôme Duval				(descriptor->capabilities & 1) ? "yes" : "no",
23126a912cdSJérôme Duval				(descriptor->capabilities & 2) ? "yes" : "no");
23219b602bcSIthamar R. Adema			printf("\twidth=%u,height=%u,min/max bitrate=%lu/%lu, maxbuf=%lu\n",
23326a912cdSJérôme Duval				descriptor->width, descriptor->height,
23426a912cdSJérôme Duval				descriptor->minBitRate, descriptor->maxBitRate,
23526a912cdSJérôme Duval				descriptor->maxVideoFrameBufferSize);
23667eb6cdeSJérôme Duval			printf("\tdefault frame interval: %lu, #intervals(0=cont): %d\n",
23726a912cdSJérôme Duval				descriptor->defaultFrameInterval, descriptor->frameIntervalType);
23826a912cdSJérôme Duval			if (descriptor->frameIntervalType == 0) {
23926a912cdSJérôme Duval				printf("min/max frame interval=%lu/%lu, step=%lu\n",
24026a912cdSJérôme Duval					descriptor->continuous.minFrameInterval,
24126a912cdSJérôme Duval					descriptor->continuous.maxFrameInterval,
24226a912cdSJérôme Duval					descriptor->continuous.frameIntervalStep);
24326a912cdSJérôme Duval			} else for (uint8 i = 0; i < descriptor->frameIntervalType; i++) {
24451a01ea0SJérôme Duval				printf("\tdiscrete frame interval: %lu\n",
24526a912cdSJérôme Duval					descriptor->discreteFrameIntervals[i]);
24626a912cdSJérôme Duval			}
24719b602bcSIthamar R. Adema			break;
24826a912cdSJérôme Duval		}
24919b602bcSIthamar R. Adema		case VS_COLORFORMAT:
25026a912cdSJérôme Duval		{
25151a01ea0SJérôme Duval			const usbvc_color_matching_descriptor* descriptor
25251a01ea0SJérôme Duval				= (const usbvc_color_matching_descriptor*)_descriptor;
25319b602bcSIthamar R. Adema			printf("VS_COLORFORMAT:\n\tbColorPrimaries: ");
25451a01ea0SJérôme Duval			switch (descriptor->colorPrimaries) {
25519b602bcSIthamar R. Adema				case 0: printf("Unspecified\n"); break;
25619b602bcSIthamar R. Adema				case 1: printf("BT.709,sRGB\n"); break;
25719b602bcSIthamar R. Adema				case 2: printf("BT.470-2(M)\n"); break;
25819b602bcSIthamar R. Adema				case 3: printf("BT.470-2(B,G)\n"); break;
25919b602bcSIthamar R. Adema				case 4: printf("SMPTE 170M\n"); break;
26019b602bcSIthamar R. Adema				case 5: printf("SMPTE 240M\n"); break;
26126a912cdSJérôme Duval				default: printf("Invalid (%d)\n", descriptor->colorPrimaries);
26219b602bcSIthamar R. Adema			}
26319b602bcSIthamar R. Adema			printf("\tbTransferCharacteristics: ");
26451a01ea0SJérôme Duval			switch (descriptor->transferCharacteristics) {
26519b602bcSIthamar R. Adema				case 0: printf("Unspecified\n"); break;
26619b602bcSIthamar R. Adema				case 1: printf("BT.709\n"); break;
26719b602bcSIthamar R. Adema				case 2: printf("BT.470-2(M)\n"); break;
26819b602bcSIthamar R. Adema				case 3: printf("BT.470-2(B,G)\n"); break;
26919b602bcSIthamar R. Adema				case 4: printf("SMPTE 170M\n"); break;
27019b602bcSIthamar R. Adema				case 5: printf("SMPTE 240M\n"); break;
27119b602bcSIthamar R. Adema				case 6: printf("Linear (V=Lc)\n"); break;
27219b602bcSIthamar R. Adema				case 7: printf("sRGB\n"); break;
27326a912cdSJérôme Duval				default: printf("Invalid (%d)\n",
27426a912cdSJérôme Duval					descriptor->transferCharacteristics);
27519b602bcSIthamar R. Adema			}
27619b602bcSIthamar R. Adema			printf("\tbMatrixCoefficients: ");
27751a01ea0SJérôme Duval			switch (descriptor->matrixCoefficients) {
27819b602bcSIthamar R. Adema				case 0: printf("Unspecified\n"); break;
27919b602bcSIthamar R. Adema				case 1: printf("BT.709\n"); break;
28019b602bcSIthamar R. Adema				case 2: printf("FCC\n"); break;
28119b602bcSIthamar R. Adema				case 3: printf("BT.470-2(B,G)\n"); break;
28219b602bcSIthamar R. Adema				case 4: printf("SMPTE 170M (BT.601)\n"); break;
28319b602bcSIthamar R. Adema				case 5: printf("SMPTE 240M\n"); break;
28426a912cdSJérôme Duval				default: printf("Invalid (%d)\n", descriptor->matrixCoefficients);
28519b602bcSIthamar R. Adema			}
28619b602bcSIthamar R. Adema			break;
28726a912cdSJérôme Duval		}
28819b602bcSIthamar R. Adema		case VS_OUTPUT_HEADER:
28926a912cdSJérôme Duval		{
29051a01ea0SJérôme Duval			const usbvc_output_header_descriptor* descriptor
29151a01ea0SJérôme Duval				= (const usbvc_output_header_descriptor*)_descriptor;
29226a912cdSJérôme Duval			printf("VS_OUTPUT_HEADER:\t#fmts=%d,ept=0x%x\n",
29326a912cdSJérôme Duval				descriptor->numFormats, descriptor->endpointAddress);
29426a912cdSJérôme Duval			printf("\toutput terminal id=%d\n", descriptor->terminalLink);
29551a01ea0SJérôme Duval			const uint8* controls = descriptor->controls;
29626a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->numFormats; i++,
29726a912cdSJérôme Duval				controls += descriptor->controlSize) {
29826a912cdSJérôme Duval				printf("\tfmt%d: %s %s %s %s\n", i,
29926a912cdSJérôme Duval					(*controls & 1) ? "wKeyFrameRate" : "",
30026a912cdSJérôme Duval					(*controls & 2) ? "wPFrameRate" : "",
30126a912cdSJérôme Duval					(*controls & 4) ? "wCompQuality" : "",
30226a912cdSJérôme Duval					(*controls & 8) ? "wCompWindowSize" : "");
30326a912cdSJérôme Duval			}
30419b602bcSIthamar R. Adema			break;
30526a912cdSJérôme Duval		}
30619b602bcSIthamar R. Adema		case VS_STILL_IMAGE_FRAME:
30726a912cdSJérôme Duval		{
30851a01ea0SJérôme Duval			const usbvc_still_image_frame_descriptor* descriptor
30951a01ea0SJérôme Duval				= (const usbvc_still_image_frame_descriptor*)_descriptor;
31026a912cdSJérôme Duval			printf("VS_STILL_IMAGE_FRAME:\t#imageSizes=%d,compressions=%d,"
31126a912cdSJérôme Duval				"ept=0x%x\n", descriptor->numImageSizePatterns,
31226a912cdSJérôme Duval				descriptor->NumCompressionPatterns(),
31326a912cdSJérôme Duval				descriptor->endpointAddress);
31426a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->numImageSizePatterns; i++) {
31526a912cdSJérôme Duval				printf("imageSize%d: %dx%d\n", i,
31626a912cdSJérôme Duval					descriptor->imageSizePatterns[i].width,
31726a912cdSJérôme Duval					descriptor->imageSizePatterns[i].height);
31826a912cdSJérôme Duval			}
31926a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->NumCompressionPatterns(); i++) {
32026a912cdSJérôme Duval				printf("compression%d: %d\n", i,
32126a912cdSJérôme Duval					descriptor->CompressionPatterns()[i]);
32226a912cdSJérôme Duval			}
32319b602bcSIthamar R. Adema			break;
32426a912cdSJérôme Duval		}
32519b602bcSIthamar R. Adema		case VS_FORMAT_MJPEG:
32667eb6cdeSJérôme Duval		{
32751a01ea0SJérôme Duval			const usbvc_format_descriptor* descriptor
32851a01ea0SJérôme Duval				= (const usbvc_format_descriptor*)_descriptor;
32951a01ea0SJérôme Duval			fMJPEGFormatIndex = descriptor->formatIndex;
33026a912cdSJérôme Duval			printf("VS_FORMAT_MJPEG:\tbFormatIdx=%d,#frmdesc=%d\n",
33126a912cdSJérôme Duval				descriptor->formatIndex, descriptor->numFrameDescriptors);
33226a912cdSJérôme Duval			printf("\t#flgs=%d,optfrmidx=%d,aspRX=%d,aspRY=%d\n",
33326a912cdSJérôme Duval				descriptor->mjpeg.flags,
33426a912cdSJérôme Duval				descriptor->mjpeg.defaultFrameIndex,
33526a912cdSJérôme Duval				descriptor->mjpeg.aspectRatioX,
33626a912cdSJérôme Duval				descriptor->mjpeg.aspectRatioY);
33726a912cdSJérôme Duval			printf("\tbmInterlaceFlags:\n");
33826a912cdSJérôme Duval			if (descriptor->mjpeg.interlaceFlags & 1)
33926a912cdSJérôme Duval				printf("\tInterlaced stream or variable\n");
34026a912cdSJérôme Duval			printf("\t%d fields per frame\n",
34126a912cdSJérôme Duval				(descriptor->mjpeg.interlaceFlags & 2) ? 1 : 2);
34226a912cdSJérôme Duval			if (descriptor->mjpeg.interlaceFlags & 4)
34326a912cdSJérôme Duval				printf("\tField 1 first\n");
34426a912cdSJérôme Duval			printf("\tField Pattern: ");
34551a01ea0SJérôme Duval			switch ((descriptor->mjpeg.interlaceFlags & 0x30) >> 4) {
34626a912cdSJérôme Duval				case 0: printf("Field 1 only\n"); break;
34726a912cdSJérôme Duval				case 1: printf("Field 2 only\n"); break;
34826a912cdSJérôme Duval				case 2: printf("Regular pattern of fields 1 and 2\n"); break;
34926a912cdSJérôme Duval				case 3: printf("Random pattern of fields 1 and 2\n"); break;
35026a912cdSJérôme Duval			}
35126a912cdSJérôme Duval			if (descriptor->mjpeg.copyProtect)
35226a912cdSJérôme Duval				printf("\tRestrict duplication\n");
35319b602bcSIthamar R. Adema			break;
35426a912cdSJérôme Duval		}
35519b602bcSIthamar R. Adema		case VS_FORMAT_MPEG2TS:
35619b602bcSIthamar R. Adema			printf("VS_FORMAT_MPEG2TS:\t\n");
35719b602bcSIthamar R. Adema			break;
35819b602bcSIthamar R. Adema		case VS_FORMAT_DV:
35919b602bcSIthamar R. Adema			printf("VS_FORMAT_DV:\t\n");
36019b602bcSIthamar R. Adema			break;
36119b602bcSIthamar R. Adema		case VS_FORMAT_FRAME_BASED:
36219b602bcSIthamar R. Adema			printf("VS_FORMAT_FRAME_BASED:\t\n");
36319b602bcSIthamar R. Adema			break;
36419b602bcSIthamar R. Adema		case VS_FRAME_FRAME_BASED:
36519b602bcSIthamar R. Adema			printf("VS_FRAME_FRAME_BASED:\t\n");
36619b602bcSIthamar R. Adema			break;
36719b602bcSIthamar R. Adema		case VS_FORMAT_STREAM_BASED:
36819b602bcSIthamar R. Adema			printf("VS_FORMAT_STREAM_BASED:\t\n");
36919b602bcSIthamar R. Adema			break;
37019b602bcSIthamar R. Adema		default:
37126a912cdSJérôme Duval			printf("INVALID STREAM UNIT TYPE=%d!\n",
37226a912cdSJérôme Duval				_descriptor->descriptorSubtype);
37319b602bcSIthamar R. Adema	}
37419b602bcSIthamar R. Adema}
37519b602bcSIthamar R. Adema
37602af02f9SJérôme Duval
37702af02f9SJérôme Duvalvoid
378d7b15506SJérôme DuvalUVCCamDevice::_ParseVideoControl(const usbvc_class_descriptor* _descriptor,
37926a912cdSJérôme Duval	size_t len)
38019b602bcSIthamar R. Adema{
38151a01ea0SJérôme Duval	switch (_descriptor->descriptorSubtype) {
38219b602bcSIthamar R. Adema		case VC_HEADER:
38326a912cdSJérôme Duval		{
38451a01ea0SJérôme Duval			if (fHeaderDescriptor != NULL) {
38551a01ea0SJérôme Duval				printf("ERROR: multiple VC_HEADER! Skipping...\n");
38667eb6cdeSJérôme Duval				break;
38751a01ea0SJérôme Duval			}
38851a01ea0SJérôme Duval			fHeaderDescriptor = (usbvc_interface_header_descriptor*)malloc(len);
38951a01ea0SJérôme Duval			memcpy(fHeaderDescriptor, _descriptor, len);
390f2df488aSJérôme Duval			printf("VC_HEADER:\tUVC v%x.%02x, clk %.5f MHz\n",
391d7b15506SJérôme Duval				fHeaderDescriptor->version >> 8,
392d7b15506SJérôme Duval				fHeaderDescriptor->version & 0xff,
393d7b15506SJérôme Duval				fHeaderDescriptor->clockFrequency / 1000000.0);
394d7b15506SJérôme Duval			for (uint8 i = 0; i < fHeaderDescriptor->numInterfacesNumbers; i++) {
39526a912cdSJérôme Duval				printf("\tStreaming Interface %d\n",
396d7b15506SJérôme Duval					fHeaderDescriptor->interfaceNumbers[i]);
39726a912cdSJérôme Duval			}
39819b602bcSIthamar R. Adema			break;
39926a912cdSJérôme Duval		}
40019b602bcSIthamar R. Adema		case VC_INPUT_TERMINAL:
40126a912cdSJérôme Duval		{
40251a01ea0SJérôme Duval			const usbvc_input_terminal_descriptor* descriptor
40351a01ea0SJérôme Duval				= (const usbvc_input_terminal_descriptor*)_descriptor;
40426a912cdSJérôme Duval			printf("VC_INPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
40526a912cdSJérôme Duval				"%d\n", descriptor->terminalID, descriptor->terminalType,
40626a912cdSJérôme Duval				descriptor->associatedTerminal);
40726a912cdSJérôme Duval			printf("\tDesc: %s\n",
40826a912cdSJérôme Duval				fDevice->DecodeStringDescriptor(descriptor->terminal));
409f2df488aSJérôme Duval			if (descriptor->terminalType == 0x201) {
41051a01ea0SJérôme Duval				const usbvc_camera_terminal_descriptor* desc
41151a01ea0SJérôme Duval					= (const usbvc_camera_terminal_descriptor*)descriptor;
412f2df488aSJérôme Duval				printf("\tObjectiveFocalLength Min/Max %d/%d\n",
413f2df488aSJérôme Duval					desc->objectiveFocalLengthMin,
414f2df488aSJérôme Duval					desc->objectiveFocalLengthMax);
415f2df488aSJérôme Duval				printf("\tOcularFocalLength %d\n", desc->ocularFocalLength);
416f2df488aSJérôme Duval				printf("\tControlSize %d\n", desc->controlSize);
417f2df488aSJérôme Duval			}
41819b602bcSIthamar R. Adema			break;
41926a912cdSJérôme Duval		}
42019b602bcSIthamar R. Adema		case VC_OUTPUT_TERMINAL:
42126a912cdSJérôme Duval		{
42251a01ea0SJérôme Duval			const usbvc_output_terminal_descriptor* descriptor
42351a01ea0SJérôme Duval				= (const usbvc_output_terminal_descriptor*)_descriptor;
42426a912cdSJérôme Duval			printf("VC_OUTPUT_TERMINAL:\tid=%d,type=%04x,associated terminal="
42526a912cdSJérôme Duval				"%d, src id=%d\n", descriptor->terminalID,
42626a912cdSJérôme Duval				descriptor->terminalType, descriptor->associatedTerminal,
42726a912cdSJérôme Duval				descriptor->sourceID);
42826a912cdSJérôme Duval			printf("\tDesc: %s\n",
42926a912cdSJérôme Duval				fDevice->DecodeStringDescriptor(descriptor->terminal));
43019b602bcSIthamar R. Adema			break;
43126a912cdSJérôme Duval		}
43219b602bcSIthamar R. Adema		case VC_SELECTOR_UNIT:
43326a912cdSJérôme Duval		{
43451a01ea0SJérôme Duval			const usbvc_selector_unit_descriptor* descriptor
43551a01ea0SJérôme Duval				= (const usbvc_selector_unit_descriptor*)_descriptor;
43626a912cdSJérôme Duval			printf("VC_SELECTOR_UNIT:\tid=%d,#pins=%d\n",
43726a912cdSJérôme Duval				descriptor->unitID, descriptor->numInputPins);
43819b602bcSIthamar R. Adema			printf("\t");
43926a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->numInputPins; i++)
44026a912cdSJérôme Duval				printf("%d ", descriptor->sourceID[i]);
44119b602bcSIthamar R. Adema			printf("\n");
44226a912cdSJérôme Duval			printf("\tDesc: %s\n",
44326a912cdSJérôme Duval				fDevice->DecodeStringDescriptor(descriptor->Selector()));
44419b602bcSIthamar R. Adema			break;
44526a912cdSJérôme Duval		}
44619b602bcSIthamar R. Adema		case VC_PROCESSING_UNIT:
44726a912cdSJérôme Duval		{
44851a01ea0SJérôme Duval			const usbvc_processing_unit_descriptor* descriptor
44951a01ea0SJérôme Duval				= (const usbvc_processing_unit_descriptor*)_descriptor;
45051a01ea0SJérôme Duval			fControlRequestIndex = fControlIndex + (descriptor->unitID << 8);
45151a01ea0SJérôme Duval			printf("VC_PROCESSING_UNIT:\t unit id=%d,src id=%d, digmul=%d\n",
45226a912cdSJérôme Duval				descriptor->unitID, descriptor->sourceID,
45326a912cdSJérôme Duval				descriptor->maxMultiplier);
45426a912cdSJérôme Duval			printf("\tbControlSize=%d\n", descriptor->controlSize);
45526a912cdSJérôme Duval			if (descriptor->controlSize >= 1) {
45626a912cdSJérôme Duval				if (descriptor->controls[0] & 1)
45726a912cdSJérôme Duval					printf("\tBrightness\n");
45826a912cdSJérôme Duval				if (descriptor->controls[0] & 2)
45926a912cdSJérôme Duval					printf("\tContrast\n");
46026a912cdSJérôme Duval				if (descriptor->controls[0] & 4)
46126a912cdSJérôme Duval					printf("\tHue\n");
46226a912cdSJérôme Duval				if (descriptor->controls[0] & 8)
46326a912cdSJérôme Duval					printf("\tSaturation\n");
46426a912cdSJérôme Duval				if (descriptor->controls[0] & 16)
46526a912cdSJérôme Duval					printf("\tSharpness\n");
46626a912cdSJérôme Duval				if (descriptor->controls[0] & 32)
46726a912cdSJérôme Duval					printf("\tGamma\n");
46826a912cdSJérôme Duval				if (descriptor->controls[0] & 64)
46926a912cdSJérôme Duval					printf("\tWhite Balance Temperature\n");
47026a912cdSJérôme Duval				if (descriptor->controls[0] & 128)
47126a912cdSJérôme Duval					printf("\tWhite Balance Component\n");
47219b602bcSIthamar R. Adema			}
47326a912cdSJérôme Duval			if (descriptor->controlSize >= 2) {
47426a912cdSJérôme Duval				if (descriptor->controls[1] & 1)
47526a912cdSJérôme Duval					printf("\tBacklight Compensation\n");
47626a912cdSJérôme Duval				if (descriptor->controls[1] & 2)
47726a912cdSJérôme Duval					printf("\tGain\n");
47826a912cdSJérôme Duval				if (descriptor->controls[1] & 4)
47926a912cdSJérôme Duval					printf("\tPower Line Frequency\n");
48026a912cdSJérôme Duval				if (descriptor->controls[1] & 8)
48126a912cdSJérôme Duval					printf("\t[AUTO] Hue\n");
48226a912cdSJérôme Duval				if (descriptor->controls[1] & 16)
48326a912cdSJérôme Duval					printf("\t[AUTO] White Balance Temperature\n");
48426a912cdSJérôme Duval				if (descriptor->controls[1] & 32)
48526a912cdSJérôme Duval					printf("\t[AUTO] White Balance Component\n");
48626a912cdSJérôme Duval				if (descriptor->controls[1] & 64)
48726a912cdSJérôme Duval					printf("\tDigital Multiplier\n");
48826a912cdSJérôme Duval				if (descriptor->controls[1] & 128)
48926a912cdSJérôme Duval					printf("\tDigital Multiplier Limit\n");
49019b602bcSIthamar R. Adema			}
49126a912cdSJérôme Duval			if (descriptor->controlSize >= 3) {
49226a912cdSJérôme Duval				if (descriptor->controls[2] & 1)
49326a912cdSJérôme Duval					printf("\tAnalog Video Standard\n");
49426a912cdSJérôme Duval				if (descriptor->controls[2] & 2)
49526a912cdSJérôme Duval					printf("\tAnalog Video Lock Status\n");
49619b602bcSIthamar R. Adema			}
49726a912cdSJérôme Duval			printf("\tDesc: %s\n",
49826a912cdSJérôme Duval				fDevice->DecodeStringDescriptor(descriptor->Processing()));
49926a912cdSJérôme Duval			if (descriptor->VideoStandards() & 2)
50026a912cdSJérôme Duval				printf("\tNTSC  525/60\n");
50126a912cdSJérôme Duval			if (descriptor->VideoStandards() & 4)
50226a912cdSJérôme Duval				printf("\tPAL   625/50\n");
50326a912cdSJérôme Duval			if (descriptor->VideoStandards() & 8)
50426a912cdSJérôme Duval				printf("\tSECAM 625/50\n");
50526a912cdSJérôme Duval			if (descriptor->VideoStandards() & 16)
50626a912cdSJérôme Duval				printf("\tNTSC  625/50\n");
50726a912cdSJérôme Duval			if (descriptor->VideoStandards() & 32)
50826a912cdSJérôme Duval				printf("\tPAL   525/60\n");
50919b602bcSIthamar R. Adema			break;
51026a912cdSJérôme Duval		}
51119b602bcSIthamar R. Adema		case VC_EXTENSION_UNIT:
51226a912cdSJérôme Duval		{
51351a01ea0SJérôme Duval			const usbvc_extension_unit_descriptor* descriptor
51451a01ea0SJérôme Duval				= (const usbvc_extension_unit_descriptor*)_descriptor;
51526a912cdSJérôme Duval			printf("VC_EXTENSION_UNIT:\tid=%d, guid=", descriptor->unitID);
51626a912cdSJérôme Duval			print_guid(descriptor->guidExtensionCode);
51726a912cdSJérôme Duval			printf("\n\t#ctrls=%d, #pins=%d\n", descriptor->numControls,
51826a912cdSJérôme Duval				descriptor->numInputPins);
51919b602bcSIthamar R. Adema			printf("\t");
52026a912cdSJérôme Duval			for (uint8 i = 0; i < descriptor->numInputPins; i++)
52126a912cdSJérôme Duval				printf("%d ", descriptor->sourceID[i]);
52219b602bcSIthamar R. Adema			printf("\n");
52326a912cdSJérôme Duval			printf("\tDesc: %s\n",
52426a912cdSJérôme Duval				fDevice->DecodeStringDescriptor(descriptor->Extension()));
52519b602bcSIthamar R. Adema			break;
52626a912cdSJérôme Duval		}
52719b602bcSIthamar R. Adema		default:
52826a912cdSJérôme Duval			printf("Unknown control %d\n", _descriptor->descriptorSubtype);
52919b602bcSIthamar R. Adema	}
53019b602bcSIthamar R. Adema}
53119b602bcSIthamar R. Adema
53202af02f9SJérôme Duval
53302af02f9SJérôme Duvalbool
53402af02f9SJérôme DuvalUVCCamDevice::SupportsIsochronous()
53519b602bcSIthamar R. Adema{
53619b602bcSIthamar R. Adema	return true;
53719b602bcSIthamar R. Adema}
53819b602bcSIthamar R. Adema
53902af02f9SJérôme Duval
54002af02f9SJérôme Duvalstatus_t
54102af02f9SJérôme DuvalUVCCamDevice::StartTransfer()
54219b602bcSIthamar R. Adema{
543d7b15506SJérôme Duval	if (_ProbeCommitFormat() != B_OK || _SelectBestAlternate() != B_OK)
544d7b15506SJérôme Duval		return B_ERROR;
54519b602bcSIthamar R. Adema	return CamDevice::StartTransfer();
54619b602bcSIthamar R. Adema}
54719b602bcSIthamar R. Adema
54802af02f9SJérôme Duval
54902af02f9SJérôme Duvalstatus_t
55002af02f9SJérôme DuvalUVCCamDevice::StopTransfer()
55119b602bcSIthamar R. Adema{
55222f4c339SJérôme Duval	_SelectIdleAlternate();
55319b602bcSIthamar R. Adema	return CamDevice::StopTransfer();
55419b602bcSIthamar R. Adema}
55519b602bcSIthamar R. Adema
55602af02f9SJérôme Duval
557d7b15506SJérôme Duvalstatus_t
55851a01ea0SJérôme DuvalUVCCamDevice::SuggestVideoFrame(uint32& width, uint32& height)
559d7b15506SJérôme Duval{
56051a01ea0SJérôme Duval	printf("UVCCamDevice::SuggestVideoFrame(%ld, %ld)\n", width, height);
56151a01ea0SJérôme Duval	// As in AcceptVideoFrame(), the suggestion should probably just be the
56251a01ea0SJérôme Duval	// first advertised uncompressed format, but current applications prefer
56351a01ea0SJérôme Duval	// 320x240, so this is tried first here as a suggestion.
564d7b15506SJérôme Duval	width = 320;
565d7b15506SJérôme Duval	height = 240;
56651a01ea0SJérôme Duval	if (!AcceptVideoFrame(width, height)) {
56751a01ea0SJérôme Duval		const usbvc_frame_descriptor* descriptor
56851a01ea0SJérôme Duval			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
56951a01ea0SJérôme Duval		width  = (*descriptor).width;
57051a01ea0SJérôme Duval		height = (*descriptor).height;
57151a01ea0SJérôme Duval	}
572d7b15506SJérôme Duval	return B_OK;
573d7b15506SJérôme Duval}
574d7b15506SJérôme Duval
575d7b15506SJérôme Duval
576d7b15506SJérôme Duvalstatus_t
57751a01ea0SJérôme DuvalUVCCamDevice::AcceptVideoFrame(uint32& width, uint32& height)
578d7b15506SJérôme Duval{
57951a01ea0SJérôme Duval	printf("UVCCamDevice::AcceptVideoFrame(%ld, %ld)\n", width, height);
58051a01ea0SJérôme Duval	if (width <= 0 || height <= 0) {
58151a01ea0SJérôme Duval		// Uncomment below when applications support dimensions other than 320x240
58251a01ea0SJérôme Duval		// This code selects the first listed available uncompressed frame format
58351a01ea0SJérôme Duval		/*
58451a01ea0SJérôme Duval		const usbvc_frame_descriptor* descriptor
58551a01ea0SJérôme Duval			= (const usbvc_frame_descriptor*)fUncompressedFrames.FirstItem();
58651a01ea0SJérôme Duval		width = (*descriptor).width;
58751a01ea0SJérôme Duval		height = (*descriptor).height;
58851a01ea0SJérôme Duval		SetVideoFrame(BRect(0, 0, width - 1, height - 1));
58951a01ea0SJérôme Duval		return B_OK;
59051a01ea0SJérôme Duval		*/
59167eb6cdeSJérôme Duval
59251a01ea0SJérôme Duval		width  = 320;
59351a01ea0SJérôme Duval		height = 240;
59451a01ea0SJérôme Duval	}
59567eb6cdeSJérôme Duval
59651a01ea0SJérôme Duval	for (int i = 0; i<fUncompressedFrames.CountItems(); i++) {
59751a01ea0SJérôme Duval		const usbvc_frame_descriptor* descriptor
59851a01ea0SJérôme Duval			= (const usbvc_frame_descriptor*)fUncompressedFrames.ItemAt(i);
59951a01ea0SJérôme Duval		if ((*descriptor).width == width && (*descriptor).height == height) {
60051a01ea0SJérôme Duval			fUncompressedFrameIndex = i;
60151a01ea0SJérôme Duval			SetVideoFrame(BRect(0, 0, width - 1, height - 1));
60251a01ea0SJérôme Duval			return B_OK;
60351a01ea0SJérôme Duval		}
60451a01ea0SJérôme Duval	}
60567eb6cdeSJérôme Duval
60651a01ea0SJérôme Duval	fprintf(stderr, "UVCCamDevice::AcceptVideoFrame() Invalid frame dimensions"
60751a01ea0SJérôme Duval		"\n");
60851a01ea0SJérôme Duval	return B_ERROR;
609d7b15506SJérôme Duval}
610d7b15506SJérôme Duval
611d7b15506SJérôme Duval
612d7b15506SJérôme Duvalstatus_t
613d7b15506SJérôme DuvalUVCCamDevice::_ProbeCommitFormat()
614d7b15506SJérôme Duval{
61551a01ea0SJérôme Duval	printf("UVCCamDevice::_ProbeCommitFormat()\n");
61651a01ea0SJérôme Duval	printf("UVCCamDevice::fStreamingIndex = %ld\n", fStreamingIndex);
61767eb6cdeSJérôme Duval
61851a01ea0SJérôme Duval	/*
61951a01ea0SJérôme Duval	char error;
62051a01ea0SJérôme Duval	printf("BEFORE ERROR CODE CHECK.\n");
62151a01ea0SJérôme Duval	fDevice->ControlTransfer(
62251a01ea0SJérôme Duval			USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
62351a01ea0SJérôme Duval			VS_STREAM_ERROR_CODE_CONTROL << 8, fStreamingIndex, 1, &error);
62451a01ea0SJérôme Duval	printf("Error code = Ox%x\n", error);
62551a01ea0SJérôme Duval	*/
62667eb6cdeSJérôme Duval
627d7b15506SJérôme Duval	usbvc_probecommit request;
628d7b15506SJérôme Duval	memset(&request, 0, sizeof(request));
62951a01ea0SJérôme Duval	request.hint = 1;
630d7b15506SJérôme Duval	request.SetFrameInterval(333333);
63151a01ea0SJérôme Duval	request.formatIndex = fUncompressedFormatIndex;
63251a01ea0SJérôme Duval	request.frameIndex = fUncompressedFrameIndex;
633d7b15506SJérôme Duval	size_t length = fHeaderDescriptor->version > 0x100 ? 34 : 26;
634d7b15506SJérôme Duval	size_t actualLength = fDevice->ControlTransfer(
635d7b15506SJérôme Duval		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
636d7b15506SJérôme Duval		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
637d7b15506SJérôme Duval	if (actualLength != length) {
638d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SET_CUR ProbeControl1"
639d7b15506SJérôme Duval			" failed %ld\n", actualLength);
640d7b15506SJérôme Duval		return B_ERROR;
641d7b15506SJérôme Duval	}
64267eb6cdeSJérôme Duval
64351a01ea0SJérôme Duval	/*
644d7b15506SJérôme Duval	usbvc_probecommit response;
645d7b15506SJérôme Duval	actualLength = fDevice->ControlTransfer(
646d7b15506SJérôme Duval		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_MAX,
647d7b15506SJérôme Duval		VS_PROBE_CONTROL << 8, fStreamingIndex, sizeof(response), &response);
648d7b15506SJérôme Duval	if (actualLength != sizeof(response)) {
649d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_ProbeFormat() GetMax ProbeControl"
650d7b15506SJérôme Duval			" failed\n");
651d7b15506SJérôme Duval		return B_ERROR;
652d7b15506SJérôme Duval	}
65367eb6cdeSJérôme Duval
654d7b15506SJérôme Duval	printf("usbvc_probecommit response.compQuality %d\n", response.compQuality);
655d7b15506SJérôme Duval	request.compQuality = response.compQuality;
65651a01ea0SJérôme Duval	*/
65767eb6cdeSJérôme Duval
65867eb6cdeSJérôme Duval
65951a01ea0SJérôme Duval	usbvc_probecommit response;
66051a01ea0SJérôme Duval	memset(&response, 0, sizeof(response));
66151a01ea0SJérôme Duval	actualLength = fDevice->ControlTransfer(
66251a01ea0SJérôme Duval		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_IN, GET_CUR,
66351a01ea0SJérôme Duval		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &response);
66467eb6cdeSJérôme Duval
66551a01ea0SJérôme Duval	/*
666d7b15506SJérôme Duval	actualLength = fDevice->ControlTransfer(
667d7b15506SJérôme Duval		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
668d7b15506SJérôme Duval		VS_PROBE_CONTROL << 8, fStreamingIndex, length, &request);
669d7b15506SJérôme Duval	if (actualLength != length) {
670d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur ProbeControl2"
671d7b15506SJérôme Duval			" failed\n");
672d7b15506SJérôme Duval		return B_ERROR;
673d7b15506SJérôme Duval	}
67451a01ea0SJérôme Duval	*/
675d7b15506SJérôme Duval
676d7b15506SJérôme Duval	actualLength = fDevice->ControlTransfer(
677d7b15506SJérôme Duval		USB_REQTYPE_CLASS | USB_REQTYPE_INTERFACE_OUT, SET_CUR,
678d7b15506SJérôme Duval		VS_COMMIT_CONTROL << 8, fStreamingIndex, length, &request);
679d7b15506SJérôme Duval	if (actualLength != length) {
680d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_ProbeFormat() SetCur CommitControl"
681d7b15506SJérôme Duval			" failed\n");
682d7b15506SJérôme Duval		return B_ERROR;
683d7b15506SJérôme Duval	}
68467eb6cdeSJérôme Duval
68567eb6cdeSJérôme Duval
686d7b15506SJérôme Duval	fMaxVideoFrameSize = response.maxVideoFrameSize;
68767eb6cdeSJérôme Duval	fMaxPayloadTransferSize = response.maxPayloadTransferSize;
688d7b15506SJérôme Duval	printf("usbvc_probecommit setup done maxVideoFrameSize:%ld"
689d7b15506SJérôme Duval		" maxPayloadTransferSize:%ld\n", fMaxVideoFrameSize,
690d7b15506SJérôme Duval		fMaxPayloadTransferSize);
69167eb6cdeSJérôme Duval
69251a01ea0SJérôme Duval	printf("UVCCamDevice::_ProbeCommitFormat()\n --> SUCCESSFUL\n");
693d7b15506SJérôme Duval	return B_OK;
694d7b15506SJérôme Duval}
695d7b15506SJérôme Duval
696d7b15506SJérôme Duval
697d7b15506SJérôme Duvalstatus_t
698d7b15506SJérôme DuvalUVCCamDevice::_SelectBestAlternate()
699d7b15506SJérôme Duval{
70051a01ea0SJérôme Duval	printf("UVCCamDevice::_SelectBestAlternate()\n");
70151a01ea0SJérôme Duval	const BUSBConfiguration* config = fDevice->ActiveConfiguration();
70251a01ea0SJérôme Duval	const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
703f254805bSFrançois Revol	if (streaming == NULL)
704f254805bSFrançois Revol		return B_BAD_INDEX;
70567eb6cdeSJérôme Duval
706d7b15506SJérôme Duval	uint32 bestBandwidth = 0;
707d7b15506SJérôme Duval	uint32 alternateIndex = 0;
708d7b15506SJérôme Duval	uint32 endpointIndex = 0;
70967eb6cdeSJérôme Duval
710d7b15506SJérôme Duval	for (uint32 i = 0; i < streaming->CountAlternates(); i++) {
71151a01ea0SJérôme Duval		const BUSBInterface* alternate = streaming->AlternateAt(i);
712d7b15506SJérôme Duval		for (uint32 j = 0; j < alternate->CountEndpoints(); j++) {
71351a01ea0SJérôme Duval			const BUSBEndpoint* endpoint = alternate->EndpointAt(j);
714d7b15506SJérôme Duval			if (!endpoint->IsIsochronous() || !endpoint->IsInput())
715d7b15506SJérôme Duval				continue;
716d7b15506SJérôme Duval			if (fMaxPayloadTransferSize > endpoint->MaxPacketSize())
717d7b15506SJérôme Duval				continue;
718d7b15506SJérôme Duval			if (bestBandwidth != 0
719d7b15506SJérôme Duval				&& bestBandwidth < endpoint->MaxPacketSize())
720d7b15506SJérôme Duval				continue;
721d7b15506SJérôme Duval			bestBandwidth = endpoint->MaxPacketSize();
722d7b15506SJérôme Duval			endpointIndex = j;
723d7b15506SJérôme Duval			alternateIndex = i;
724d7b15506SJérôme Duval		}
725d7b15506SJérôme Duval	}
72667eb6cdeSJérôme Duval
727d7b15506SJérôme Duval	if (bestBandwidth == 0) {
728d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
729d7b15506SJérôme Duval			" couldn't find a valid alternate\n");
730d7b15506SJérôme Duval		return B_ERROR;
731d7b15506SJérôme Duval	}
73267eb6cdeSJérôme Duval
733d7b15506SJérôme Duval	printf("UVCCamDevice::_SelectBestAlternate() %ld\n", bestBandwidth);
73451a01ea0SJérôme Duval	if (((BUSBInterface*)streaming)->SetAlternate(alternateIndex) != B_OK) {
735d7b15506SJérôme Duval		fprintf(stderr, "UVCCamDevice::_SelectBestAlternate()"
736d7b15506SJérôme Duval			" selecting alternate failed\n");
737d7b15506SJérôme Duval		return B_ERROR;
738d7b15506SJérôme Duval	}
73967eb6cdeSJérôme Duval
740d7b15506SJérôme Duval	fIsoIn = streaming->EndpointAt(endpointIndex);
74167eb6cdeSJérôme Duval
742d7b15506SJérôme Duval	return B_OK;
743d7b15506SJérôme Duval}
744d7b15506SJérôme Duval
745d7b15506SJérôme Duval
74622f4c339SJérôme Duvalstatus_t
74722f4c339SJérôme DuvalUVCCamDevice::_SelectIdleAlternate()
74822f4c339SJérôme Duval{
74951a01ea0SJérôme Duval	printf("UVCCamDevice::_SelectIdleAlternate()\n");
75051a01ea0SJérôme Duval	const BUSBConfiguration* config = fDevice->ActiveConfiguration();
75151a01ea0SJérôme Duval	const BUSBInterface* streaming = config->InterfaceAt(fStreamingIndex);
752f254805bSFrançois Revol	if (streaming == NULL)
753f254805bSFrançois Revol		return B_BAD_INDEX;
75451a01ea0SJérôme Duval	if (((BUSBInterface*)streaming)->SetAlternate(0) != B_OK) {
75522f4c339SJérôme Duval		fprintf(stderr, "UVCCamDevice::_SelectIdleAlternate()"
75622f4c339SJérôme Duval			" selecting alternate failed\n");
75722f4c339SJérôme Duval		return B_ERROR;
75822f4c339SJérôme Duval	}
75922f4c339SJérôme Duval
76067eb6cdeSJérôme Duval	fIsoIn = NULL;
76122f4c339SJérôme Duval
76267eb6cdeSJérôme Duval	return B_OK;
76319b602bcSIthamar R. Adema}
76419b602bcSIthamar R. Adema
76519b602bcSIthamar R. Adema
76667eb6cdeSJérôme Duvalvoid
76767eb6cdeSJérôme DuvalUVCCamDevice::_AddProcessingParameter(BParameterGroup* group,
76867eb6cdeSJérôme Duval	int32 index, const usbvc_processing_unit_descriptor* descriptor)
76919b602bcSIthamar R. Adema{
77067eb6cdeSJérôme Duval	BParameterGroup* subgroup;
77167eb6cdeSJérôme Duval	BContinuousParameter* p;
77267eb6cdeSJérôme Duval	uint16 wValue = 0; // Control Selector
77367eb6cdeSJérôme Duval	float minValue = 0.0;
77467eb6cdeSJérôme Duval	float maxValue = 100.0;
77567eb6cdeSJérôme Duval	if (descriptor->controlSize >= 1) {
77667eb6cdeSJérôme Duval		if (descriptor->controls[0] & 1) {
77767eb6cdeSJérôme Duval			// debug_printf("\tBRIGHTNESS\n");
77867eb6cdeSJérôme Duval			fBrightness = _AddParameter(group, &subgroup, index,
77967eb6cdeSJérôme Duval				PU_BRIGHTNESS_CONTROL, "Brightness");
78067eb6cdeSJérôme Duval		}
78167eb6cdeSJérôme Duval		if (descriptor->controls[0] & 2) {
78267eb6cdeSJérôme Duval			// debug_printf("\tCONSTRAST\n");
78367eb6cdeSJérôme Duval			fContrast = _AddParameter(group, &subgroup, index + 1,
78467eb6cdeSJérôme Duval				PU_CONTRAST_CONTROL, "Contrast");
78567eb6cdeSJérôme Duval		}
78667eb6cdeSJérôme Duval		if (descriptor->controls[0] & 4) {
78767eb6cdeSJérôme Duval			// debug_printf("\tHUE\n");
78867eb6cdeSJérôme Duval			fHue = _AddParameter(group, &subgroup, index + 2,
78967eb6cdeSJérôme Duval				PU_HUE_CONTROL, "Hue");
79067eb6cdeSJérôme Duval			if (descriptor->controlSize >= 2) {
79167eb6cdeSJérôme Duval				if (descriptor->controls[1] & 8) {
79267eb6cdeSJérôme Duval					fHueAuto = _AddAutoParameter(subgroup, index + 3,
79367eb6cdeSJérôme Duval						PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL);
79467eb6cdeSJérôme Duval				}
79567eb6cdeSJérôme Duval			}
79667eb6cdeSJérôme Duval		}
79767eb6cdeSJérôme Duval		if (descriptor->controls[0] & 8) {
79867eb6cdeSJérôme Duval			// debug_printf("\tSATURATION\n");
79967eb6cdeSJérôme Duval			fSaturation = _AddParameter(group, &subgroup, index + 4,
80067eb6cdeSJérôme Duval				PU_SATURATION_CONTROL, "Saturation");
80167eb6cdeSJérôme Duval		}
80267eb6cdeSJérôme Duval		if (descriptor->controls[0] & 16) {
80367eb6cdeSJérôme Duval			// debug_printf("\tSHARPNESS\n");
80467eb6cdeSJérôme Duval			fSharpness = _AddParameter(group, &subgroup, index + 5,
80567eb6cdeSJérôme Duval				PU_SHARPNESS_CONTROL, "Sharpness");
80667eb6cdeSJérôme Duval		}
80767eb6cdeSJérôme Duval		if (descriptor->controls[0] & 32) {
80867eb6cdeSJérôme Duval			// debug_printf("\tGamma\n");
80967eb6cdeSJérôme Duval			fGamma = _AddParameter(group, &subgroup, index + 6,
81067eb6cdeSJérôme Duval				PU_GAMMA_CONTROL, "Gamma");
81167eb6cdeSJérôme Duval		}
81267eb6cdeSJérôme Duval		if (descriptor->controls[0] & 64) {
81367eb6cdeSJérôme Duval			// debug_printf("\tWHITE BALANCE TEMPERATURE\n");
81467eb6cdeSJérôme Duval			fWBTemp = _AddParameter(group, &subgroup, index + 7,
81567eb6cdeSJérôme Duval				PU_WHITE_BALANCE_TEMPERATURE_CONTROL,