1/*
2 * Copyright 2016, Adrien Destugues, pulkomandy@pulkomandy.tk
3 * Distributed under terms of the MIT license.
4 */
5
6#include <stdio.h>
7
8#include <usb/USB_video.h>
9
10#include "listusb.h"
11
12
13void
14DumpVideoCSInterfaceDescriptorHeader(
15	const usb_videocontrol_header_descriptor* descriptor)
16{
17	printf("                    Type .............. 0x%02x\n",
18		descriptor->descriptor_type);
19	printf("                    Subtype ........... 0x%02x (Header)\n",
20		descriptor->descriptor_subtype);
21	printf("                    UVC Release ....... %d.%d\n",
22		descriptor->bcd_release_no >> 8, descriptor->bcd_release_no & 0xFF);
23	printf("                    Total Length ...... %u\n",
24		descriptor->total_length);
25	printf("                    Clock Frequency ... %" B_PRIu32 "\n",
26		descriptor->clock_frequency);
27	printf("                    Interfaces ........ ");
28
29	for (uint8 i = 0; i < descriptor->in_collection; i++)
30		printf("%u, ", descriptor->interface_numbers[i]);
31	printf("\n");
32}
33
34
35static const char*
36TerminalTypeName(uint16 terminalType)
37{
38	switch (terminalType) {
39		case USB_VIDEO_VENDOR_USB_IO:
40			return "Vendor specific";
41		case USB_VIDEO_STREAMING_USB_IO:
42			return "Streaming";
43
44		case USB_VIDEO_VENDOR_IN:
45			return "Vendor specific input";
46		case USB_VIDEO_CAMERA_IN:
47			return "Camera";
48		case USB_VIDEO_MEDIA_TRANSPORT_IN:
49			return "Media transport input";
50
51		case USB_VIDEO_VENDOR_OUT:
52			return "Vendor specific output";
53		case USB_VIDEO_DISPLAY_OUT:
54			return "Display";
55		case USB_VIDEO_MEDIA_TRANSPORT_OUT:
56			return "Media transport output";
57
58		case USB_VIDEO_VENDOR_EXT:
59			return "Vendor specific format";
60		case USB_VIDEO_COMPOSITE_EXT:
61			return "Composite";
62		case USB_VIDEO_SVIDEO_EXT:
63			return "S-Video";
64		case USB_VIDEO_COMPONENT_EXT:
65			return "Component";
66
67		default:
68			return "Unknown";
69	}
70}
71
72
73void
74DumpVideoCSInterfaceDescriptorOutputTerminal(
75	const usb_video_output_terminal_descriptor* descriptor)
76{
77	printf("                    Type .............. 0x%02x\n",
78		descriptor->descriptor_type);
79	printf("                    Subtype ........... 0x%02x (Output Terminal)\n",
80		descriptor->descriptor_subtype);
81	printf("                    Terminal ID ....... %u\n",
82		descriptor->terminal_id);
83	printf("                    Terminal Type ..... 0x%04x (%s)\n",
84		descriptor->terminal_type,
85			TerminalTypeName(descriptor->terminal_type));
86	printf("                    Associated Terminal %u\n",
87		descriptor->assoc_terminal);
88	printf("                    Source ID ......... %u\n",
89		descriptor->source_id);
90	printf("                    Terminal .......... %u\n",
91		descriptor->terminal);
92}
93
94
95void
96DumpVideoCSInterfaceDescriptorInputTerminal(
97	const usb_video_input_terminal_descriptor* descriptor)
98{
99	printf("                    Type .............. 0x%02x\n",
100		descriptor->descriptor_type);
101	printf("                    Subtype ........... 0x%02x (Input Terminal)\n",
102		descriptor->descriptor_subtype);
103	printf("                    Terminal ID ....... %u\n",
104		descriptor->terminal_id);
105	printf("                    Terminal Type ..... 0x%04x (%s)\n",
106		descriptor->terminal_type,
107			TerminalTypeName(descriptor->terminal_type));
108	printf("                    Terminal .......... %u\n",
109		descriptor->terminal);
110
111	if (descriptor->terminal_type == USB_VIDEO_CAMERA_IN)
112	{
113		printf("                    Min. Focal length . %u\n",
114			descriptor->camera.focal_length_min);
115		printf("                    Max. Focal length . %u\n",
116			descriptor->camera.focal_length_min);
117		printf("                    Focal length ...... %u\n",
118			descriptor->camera.focal_length);
119		printf("                    Controls .......... %02x%02x%02x\n",
120			descriptor->camera.controls[0],
121			descriptor->camera.controls[1],
122			descriptor->camera.controls[2]);
123	}
124}
125
126
127static const char*
128ProcessingControlString(int index)
129{
130	switch(index)
131	{
132		case 0:
133			return "Brightness, ";
134		case 1:
135			return "Contrast, ";
136		case 2:
137			return "Hue, ";
138		case 3:
139			return "Saturation, ";
140		case 4:
141			return "Sharpness, ";
142		case 5:
143			return "Gamma, ";
144		case 6:
145			return "White balance temp., ";
146		case 7:
147			return "White balance component, ";
148		case 8:
149			return "Backlight compensation, ";
150		case 9:
151			return "Gain, ";
152		case 10:
153			return "Power line frequency, ";
154		case 11:
155			return "Automatic hue, ";
156		case 12:
157			return "Automatic white balance temp., ";
158		case 13:
159			return "Automatic white balance component, ";
160		case 14:
161			return "Digital multiplier, ";
162		case 15:
163			return "Digital multiplier limit, ";
164		case 16:
165			return "Analog video standard, ";
166		case 17:
167			return "Analog video lock status, ";
168		case 18:
169			return "Automatic contrast, ";
170		default:
171			return "Unknown, ";
172	}
173}
174
175
176void
177DumpVideoCSInterfaceDescriptorProcessingUnit(
178	const usb_video_processing_unit_descriptor* descriptor)
179{
180	printf("                    Type .............. 0x%02x\n",
181		descriptor->descriptor_type);
182	printf("                    Subtype ........... 0x%02x (Processing unit)\n",
183		descriptor->descriptor_subtype);
184	printf("                    Unit ID ........... %u\n",
185		descriptor->unit_id);
186	printf("                    Source ID ......... %u\n",
187		descriptor->source_id);
188	printf("                    Max Multiplier .... %f\n",
189		descriptor->max_multiplier / 100.f);
190	printf("                    Controls .......... ");
191	uint32_t controls = (descriptor->controls[0] << 16)
192		| (descriptor->controls[1] << 8)
193		| descriptor->controls[2];
194	for (int i = 0; i < 19; i++)
195	{
196		if (controls & (1 << (23 - i))) {
197			fputs(ProcessingControlString(i), stdout);
198		}
199	}
200	printf("\n");
201	printf("                    Processing ........ %u\n",
202		descriptor->processing);
203	printf("                    Video Standards ... 0x%02x\n",
204		descriptor->video_standards);
205}
206
207
208void
209DumpVideoCSInterfaceDescriptorExtensionUnit(
210	const usb_generic_descriptor* descriptor)
211{
212	uint8 i = 0;
213
214	printf("                    Type .............. 0x%02x\n",
215		descriptor->descriptor_type);
216	printf("                    Subtype ........... 0x%02x (Extension unit)\n",
217		(uint8)descriptor->data[i++]);
218	printf("                    Unit ID ........... %u\n",
219		(uint8)descriptor->data[i++]);
220
221	printf("                    GUID .............. ");
222	for (i = 2; i < 16 + 2; i++)
223		printf("%02x ", descriptor->data[i]);
224	printf("\n");
225
226	printf("                    Control count ..... %u\n",
227		(uint8)descriptor->data[i++]);
228
229	printf("                    Input pins ........ ");
230	i = 20; // Skip the input pin count
231	for (; i - 20 < descriptor->data[19]; i++)
232		printf("%u, ", descriptor->data[i]);
233	printf("\n");
234
235	printf("                    Controls .......... ");
236	uint8_t end = descriptor->data[i++];
237	uint8_t start = i;
238	for (; i - start < end; i++)
239		printf("%02x", (uint8)descriptor->data[i]);
240	printf("\n");
241
242	printf("                    Extension ......... %u\n",
243		(uint8)descriptor->data[i++]);
244}
245
246
247void
248DumpVideoControlCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
249{
250	uint8 descriptorSubtype = descriptor->data[0];
251	switch (descriptorSubtype) {
252		case USB_VIDEO_VC_HEADER:
253			DumpVideoCSInterfaceDescriptorHeader(
254				(usb_videocontrol_header_descriptor*)descriptor);
255			break;
256		case USB_VIDEO_VC_INPUT_TERMINAL:
257			DumpVideoCSInterfaceDescriptorInputTerminal(
258				(usb_video_input_terminal_descriptor*)descriptor);
259			break;
260		case USB_VIDEO_VC_OUTPUT_TERMINAL:
261			DumpVideoCSInterfaceDescriptorOutputTerminal(
262				(usb_video_output_terminal_descriptor*)descriptor);
263			break;
264		case USB_VIDEO_VC_PROCESSING_UNIT:
265			DumpVideoCSInterfaceDescriptorProcessingUnit(
266				(usb_video_processing_unit_descriptor*)descriptor);
267			break;
268		case USB_VIDEO_VC_EXTENSION_UNIT:
269			DumpVideoCSInterfaceDescriptorExtensionUnit(descriptor);
270			break;
271		default:
272			DumpDescriptorData(descriptor);
273	}
274}
275
276
277void
278DumpVideoControlCSInterruptEndpointDescriptor(const usb_generic_descriptor* descriptor)
279{
280	printf("                    Type .............. 0x%02x (Endpoint)\n",
281		descriptor->descriptor_type);
282	printf("                    Subtype ........... 0x%02x (Interrupt)\n",
283		(uint8)descriptor->data[0]);
284	printf("                    Max Transfer Size . %u\n",
285		(uint16)((descriptor->data[1] << 8) | descriptor->data[2]));
286}
287
288
289void
290DumpVideoControlCSEndpointDescriptor(const usb_generic_descriptor* descriptor)
291{
292	uint8 descriptorSubtype = descriptor->data[0];
293	switch (descriptorSubtype) {
294		case EP_SUBTYPE_INTERRUPT:
295			DumpVideoControlCSInterruptEndpointDescriptor(descriptor);
296			break;
297		default:
298			DumpDescriptorData(descriptor);
299	}
300}
301
302
303void
304DumpVideoStreamInputHeaderDescriptor(const usb_generic_descriptor* descriptor)
305{
306	printf("                    Type .............. 0x%02x (VideoStream Interface)\n",
307		descriptor->descriptor_type);
308	printf("                    Subtype ........... 0x%02x (Input header)\n",
309		(uint8)descriptor->data[0]);
310	printf("                    Format count ...... %u\n",
311		(uint8)descriptor->data[1]);
312	printf("                    Total length ...... %u\n",
313		(uint16)((descriptor->data[2] << 8) | descriptor->data[3]));
314	printf("                    Endpoint .......... 0x%02x\n",
315		(uint8)descriptor->data[4]);
316	printf("                    Info .............. 0x%02x\n",
317		(uint8)descriptor->data[5]);
318	printf("                    Terminal Link ..... 0x%02x\n",
319		(uint8)descriptor->data[6]);
320	printf("                    Still capture ..... 0x%02x\n",
321		(uint8)descriptor->data[7]);
322	printf("                    Trigger support ... %u\n",
323		(uint8)descriptor->data[8]);
324	printf("                    Trigger usage ..... %u\n",
325		(uint8)descriptor->data[9]);
326
327	uint8 nformat = descriptor->data[1];
328	uint8 formatsize = descriptor->data[10];
329	uint8 i, j;
330
331	for (i = 0; i < nformat; i++)
332	{
333		printf("                    Format %2d ......... 0x", i);
334		for (j = 0; j < formatsize; j++)
335			printf("%02x", (uint8)descriptor->data[11 + i * formatsize + j]);
336		printf("\n");
337	}
338}
339
340
341void
342DumpVideoStillImageDescriptor(const usb_generic_descriptor* descriptor)
343{
344	printf("                    Type .............. 0x%02x (VideoStream Interface)\n",
345		descriptor->descriptor_type);
346	printf("                    Subtype ........... 0x%02x (Still Image)\n",
347		(uint8)descriptor->data[0]);
348	printf("                    Endpoint .......... %u\n",
349		(uint8)descriptor->data[1]);
350
351	uint8 npatterns = descriptor->data[2];
352	uint8 i;
353	printf("                    Resolutions ....... ");
354	for (i = 0; i < npatterns; i++)
355	{
356		// FIXME these are reverse-endian compared to everything else.
357		// Is my webcam wrong, or is it some quirk in the spec?
358		printf("%ux%u, ",
359			(uint16)((descriptor->data[i * 4 + 4] << 8) | (descriptor->data[i * 4 + 3])),
360			(uint16)((descriptor->data[i * 4 + 6] << 8) | (descriptor->data[i * 4 + 5])));
361	}
362	printf("\n");
363
364	i = i * 4 + 3;
365
366	npatterns = descriptor->data[i];
367	while (npatterns > 0)
368	{
369		printf("                    Compression ....... %u\n",
370			(uint8)descriptor->data[i]);
371		npatterns--;
372	}
373}
374
375
376static const char*
377VSInterfaceString(int subtype)
378{
379	switch(subtype) {
380		case USB_VIDEO_VS_UNDEFINED:
381			return "Undefined";
382		case USB_VIDEO_VS_INPUT_HEADER:
383			return "Input header";
384		case USB_VIDEO_VS_OUTPUT_HEADER:
385			return "Output header";
386		case USB_VIDEO_VS_STILL_IMAGE_FRAME:
387			return "Still image";
388		case USB_VIDEO_VS_FORMAT_UNCOMPRESSED:
389			return "Uncompressed format";
390		case USB_VIDEO_VS_FRAME_UNCOMPRESSED:
391			return "Uncompressed frame";
392		case USB_VIDEO_VS_FORMAT_MJPEG:
393			return "MJPEG format";
394		case USB_VIDEO_VS_FRAME_MJPEG:
395			return "MJPEG frame";
396		case USB_VIDEO_VS_FORMAT_MPEG2TS:
397			return "MPEG2TS format";
398		case USB_VIDEO_VS_FORMAT_DV:
399			return "DV format";
400		case USB_VIDEO_VS_COLORFORMAT:
401			return "Color format";
402		case USB_VIDEO_VS_FORMAT_FRAME_BASED:
403			return "Frame based format";
404		case USB_VIDEO_VS_FRAME_FRAME_BASED:
405			return "Frame based frame";
406		case USB_VIDEO_VS_FORMAT_STREAM_BASED:
407			return "Stream based format";
408		case USB_VIDEO_VS_FORMAT_H264:
409			return "H264 format";
410		case USB_VIDEO_VS_FRAME_H264:
411			return "H264 frame";
412		case USB_VIDEO_VS_FORMAT_H264_SIMULCAST:
413			return "H264 simulcast";
414		case USB_VIDEO_VS_FORMAT_VP8:
415			return "VP8 format";
416		case USB_VIDEO_VS_FRAME_VP8:
417			return "VP8 frame";
418		case USB_VIDEO_VS_FORMAT_VP8_SIMULCAST:
419			return "VP8 simulcast";
420		default:
421			return "Unknown";
422	};
423}
424
425
426void
427DumpVideoFormatDescriptor(const usb_generic_descriptor* descriptor)
428{
429	printf("                    Type .............. 0x%02x (VideoStream Interface)\n",
430		descriptor->descriptor_type);
431	printf("                    Subtype ........... 0x%02x (%s)\n",
432		(uint8)descriptor->data[0], VSInterfaceString(descriptor->data[0]));
433	printf("                    Index ............. 0x%02x\n",
434		(uint8)descriptor->data[1]);
435	printf("                    Frame number ...... 0x%02x\n",
436		(uint8)descriptor->data[2]);
437
438	printf("                    GUID .............. ");
439	for (uint8 i = 3; i < 16 + 3; i++)
440		printf("%02x ", descriptor->data[i]);
441	printf("\n");
442
443	printf("                    Bits per pixel .... %u\n",
444		(uint8)descriptor->data[19]);
445	printf("                    Default frame idx . 0x%02x\n",
446		(uint8)descriptor->data[20]);
447	printf("                    Aspect ratio ...... %u:%u\n",
448		(uint8)descriptor->data[21], (uint8)descriptor->data[22]);
449	printf("                    Interlace flags ... 0x%02x\n",
450		(uint8)descriptor->data[23]);
451	printf("                    Copy protect ...... %u\n",
452		(uint8)descriptor->data[24]);
453}
454
455
456void
457DumpVideoFrameDescriptor(const usb_video_frame_descriptor* descriptor)
458{
459	printf("                    Type .............. 0x%02x (VideoStream Interface)\n",
460		descriptor->descriptor_type);
461	printf("                    Subtype ........... 0x%02x (%s)\n",
462		descriptor->descriptor_subtype,
463		VSInterfaceString(descriptor->descriptor_subtype));
464	printf("                    Index ............. 0x%02x\n",
465		descriptor->frame_index);
466	printf("                    Capabilities ...... 0x%02x\n",
467		descriptor->capabilities);
468	printf("                    Resolution ........ %u x %u\n",
469		descriptor->width, descriptor->height);
470	printf("                    Bit rates ......... %" B_PRIu32 " - %" B_PRIu32 "\n",
471		descriptor->min_bit_rate, descriptor->max_bit_rate);
472	printf("                    Frame buffer size . %" B_PRIu32 "\n",
473		descriptor->max_video_frame_buffer_size);
474	printf("                    Frame interval .... %.4fms\n",
475		descriptor->default_frame_interval / 10000.f);
476	for (uint8 i = 0; i < descriptor->frame_interval_type; i++)
477	{
478		printf("                    Frame interval %2d . %.4fms\n",
479			i, descriptor->discrete_frame_intervals[i] / 10000.f);
480	}
481	// TODO if frame__interval_type is 0, dump continuous frame intervals
482}
483
484
485void
486DumpVideoStreamCSInterfaceDescriptor(const usb_generic_descriptor* descriptor)
487{
488	uint8 subtype = descriptor->data[0];
489	switch (subtype) {
490		case USB_VIDEO_VS_INPUT_HEADER:
491			DumpVideoStreamInputHeaderDescriptor(descriptor);
492			break;
493		case USB_VIDEO_VS_STILL_IMAGE_FRAME:
494			DumpVideoStillImageDescriptor(descriptor);
495			break;
496		case USB_VIDEO_VS_FORMAT_UNCOMPRESSED:
497		case USB_VIDEO_VS_FORMAT_MJPEG:
498			DumpVideoFormatDescriptor(descriptor);
499			break;
500		case USB_VIDEO_VS_FRAME_UNCOMPRESSED:
501		case USB_VIDEO_VS_FRAME_MJPEG:
502			DumpVideoFrameDescriptor((usb_video_frame_descriptor*)descriptor);
503			break;
504		default:
505			DumpDescriptorData(descriptor);
506			break;
507	}
508}
509
510
511
512void
513DumpVideoDescriptor(const usb_generic_descriptor* descriptor, int subclass)
514{
515	switch (subclass) {
516		case USB_VIDEO_INTERFACE_VIDEOCONTROL_SUBCLASS:
517			switch (descriptor->descriptor_type) {
518				case USB_VIDEO_CS_INTERFACE:
519					DumpVideoControlCSInterfaceDescriptor(descriptor);
520					break;
521				case USB_VIDEO_CS_ENDPOINT:
522					DumpVideoControlCSEndpointDescriptor(descriptor);
523					break;
524				default:
525					DumpDescriptorData(descriptor);
526					break;
527			}
528			break;
529		case USB_VIDEO_INTERFACE_VIDEOSTREAMING_SUBCLASS:
530			switch (descriptor->descriptor_type) {
531				case USB_VIDEO_CS_INTERFACE:
532					DumpVideoStreamCSInterfaceDescriptor(descriptor);
533					break;
534				default:
535					DumpDescriptorData(descriptor);
536					break;
537			}
538			break;
539		case USB_VIDEO_INTERFACE_COLLECTION_SUBCLASS:
540			switch (descriptor->descriptor_type) {
541				case USB_VIDEO_CS_INTERFACE:
542					// TODO
543					DumpDescriptorData(descriptor);
544					break;
545				default:
546					DumpDescriptorData(descriptor);
547					break;
548			}
549			break;
550		default:
551			DumpDescriptorData(descriptor);
552			break;
553	}
554}
555
556