xref: /netbsd-src/sys/dev/usb/uvideo.c (revision 0f0ac9cec282da336d9199611849cbcbd5327418)
1 /*	$NetBSD: uvideo.c,v 1.85 2023/04/10 15:27:51 mlelstv Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Patrick Mahoney
5  * All rights reserved.
6  *
7  * This code was written by Patrick Mahoney (pat@polycrystal.org) as
8  * part of Google Summer of Code 2008.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * USB video specs:
41  *      http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: uvideo.c,v 1.85 2023/04/10 15:27:51 mlelstv Exp $");
46 
47 #ifdef _KERNEL_OPT
48 #include "opt_usb.h"
49 #endif
50 
51 #ifdef _MODULE
52 #include <sys/module.h>
53 #endif
54 
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/kernel.h>
58 #include <sys/kmem.h>
59 #include <sys/device.h>
60 #include <sys/ioctl.h>
61 #include <sys/uio.h>
62 #include <sys/file.h>
63 #include <sys/select.h>
64 #include <sys/proc.h>
65 #include <sys/conf.h>
66 #include <sys/vnode.h>
67 #include <sys/poll.h>
68 #include <sys/queue.h>	/* SLIST */
69 #include <sys/kthread.h>
70 #include <sys/bus.h>
71 
72 #include <sys/videoio.h>
73 #include <dev/video_if.h>
74 
75 #include <dev/usb/usb.h>
76 #include <dev/usb/usbdi.h>
77 #include <dev/usb/usbdivar.h>
78 #include <dev/usb/usbdi_util.h>
79 #include <dev/usb/usb_quirks.h>
80 
81 #include <dev/usb/uvideoreg.h>
82 
83 #define UVIDEO_NXFERS	3
84 #define UVIDEO_NFRAMES_MAX 80
85 #define PRI_UVIDEO	PRI_BIO
86 
87 /* #define UVIDEO_DISABLE_MJPEG */
88 
89 #ifdef UVIDEO_DEBUG
90 #define DPRINTF(x)	do { if (uvideodebug) printf x; } while (0)
91 #define DPRINTFN(n,x)	do { if (uvideodebug>(n)) printf x; } while (0)
92 int	uvideodebug = 20;
93 #else
94 #define DPRINTF(x)	__nothing
95 #define DPRINTFN(n,x)	__nothing
96 #endif
97 
98 typedef enum {
99 	UVIDEO_STATE_CLOSED,
100 	UVIDEO_STATE_OPENING,
101 	UVIDEO_STATE_IDLE
102 } uvideo_state;
103 
104 struct uvideo_camera_terminal {
105 	uint16_t	ct_objective_focal_min;
106 	uint16_t	ct_objective_focal_max;
107 	uint16_t	ct_ocular_focal_length;
108 };
109 
110 struct uvideo_processing_unit {
111 	uint16_t	pu_max_multiplier; /* digital zoom */
112 	uint8_t		pu_video_standards;
113 };
114 
115 struct uvideo_extension_unit {
116 	guid_t		xu_guid;
117 };
118 
119 /*
120  * For simplicity, we consider a Terminal a special case of Unit
121  * rather than a separate entity.
122  */
123 struct uvideo_unit {
124 	uint8_t		vu_id;
125 	uint8_t		vu_type;
126 	uint8_t		vu_dst_id;
127 	uint8_t		vu_nsrcs;
128 	union {
129 		uint8_t	vu_src_id;	/* vu_nsrcs = 1 */
130 		uint8_t	*vu_src_id_ary; /* vu_nsrcs > 1 */
131 	} s;
132 
133 	/* fields for individual unit/terminal types */
134 	union {
135 		struct uvideo_camera_terminal	vu_camera;
136 		struct uvideo_processing_unit	vu_processing;
137 		struct uvideo_extension_unit	vu_extension;
138 	} u;
139 
140 	/* Used by camera terminal, processing and extension units. */
141 	uint8_t		vu_control_size; /* number of bytes in vu_controls */
142 	uint8_t		*vu_controls;	 /* array of bytes. bits are
143 					  * numbered from 0 at least
144 					  * significant bit to
145 					  * (8*vu_control_size - 1)*/
146 };
147 
148 struct uvideo_alternate {
149 	uint8_t		altno;
150 	uint8_t		interval;
151 	uint16_t	max_packet_size;
152 	SLIST_ENTRY(uvideo_alternate)	entries;
153 };
154 SLIST_HEAD(altlist, uvideo_alternate);
155 
156 #define UVIDEO_FORMAT_GET_FORMAT_INDEX(fmt)	\
157 	((fmt)->format.priv & 0xff)
158 #define UVIDEO_FORMAT_GET_FRAME_INDEX(fmt)	\
159 	(((fmt)->format.priv >> 8) & 0xff)
160 /* TODO: find a better way to set bytes within this 32 bit value? */
161 #define UVIDEO_FORMAT_SET_FORMAT_INDEX(fmt, index) do {	\
162 		(fmt)->format.priv &= ~0xff;		\
163 		(fmt)->format.priv |= ((index) & 0xff);	\
164 	} while (0)
165 #define UVIDEO_FORMAT_SET_FRAME_INDEX(fmt, index) do {			\
166 		(fmt)->format.priv &= ~(0xff << 8);			\
167 		((fmt)->format.priv |= (((index) & 0xff) << 8));	\
168 	} while (0)
169 
170 struct uvideo_pixel_format {
171 	enum video_pixel_format	pixel_format;
172 	SIMPLEQ_ENTRY(uvideo_pixel_format) entries;
173 };
174 SIMPLEQ_HEAD(uvideo_pixel_format_list, uvideo_pixel_format);
175 
176 struct uvideo_format {
177 	struct video_format	format;
178 	SIMPLEQ_ENTRY(uvideo_format) entries;
179 };
180 SIMPLEQ_HEAD(uvideo_format_list, uvideo_format);
181 
182 struct uvideo_isoc_xfer;
183 struct uvideo_stream;
184 
185 struct uvideo_isoc {
186 	struct uvideo_isoc_xfer	*i_ix;
187 	struct uvideo_stream	*i_vs;
188 	struct usbd_xfer	*i_xfer;
189 	uint8_t			*i_buf;
190 	uint16_t		*i_frlengths;
191 };
192 
193 struct uvideo_isoc_xfer {
194 	uint8_t			ix_endpt;
195 	struct usbd_pipe	*ix_pipe;
196 	struct uvideo_isoc	ix_i[UVIDEO_NXFERS];
197 	uint32_t		ix_nframes;
198 	uint32_t		ix_uframe_len;
199 
200 	struct altlist		ix_altlist;
201 };
202 
203 struct uvideo_bulk_xfer {
204 	uint8_t			bx_endpt;
205 	struct usbd_pipe	*bx_pipe;
206 	struct usbd_xfer	*bx_xfer;
207 	uint8_t			*bx_buffer;
208 	int			bx_buflen;
209 	bool			bx_running;
210 	kcondvar_t		bx_cv;
211 	kmutex_t		bx_lock;
212 };
213 
214 struct uvideo_stream {
215 	device_t		vs_videodev;
216 	struct uvideo_softc	*vs_parent;
217 	struct usbd_interface	*vs_iface;
218 	uint8_t			vs_ifaceno;
219 	uint8_t			vs_subtype;  /* input or output */
220 	uint16_t		vs_probelen; /* length of probe and
221 					      * commit data; varies
222 					      * depending on version
223 					      * of spec. */
224 	struct uvideo_format_list vs_formats;
225 	struct uvideo_pixel_format_list vs_pixel_formats;
226 	struct video_format	*vs_default_format;
227 	struct video_format	vs_current_format;
228 
229 	/* usb transfer details */
230 	uint8_t			vs_xfer_type;
231 	union {
232 		struct uvideo_bulk_xfer	bulk;
233 		struct uvideo_isoc_xfer isoc;
234 	} vs_xfer;
235 
236 	int			vs_frameno;	/* toggles between 0 and 1 */
237 
238 	/* current video format */
239 	uint32_t		vs_max_payload_size;
240 	uint32_t		vs_frame_interval;
241 	SLIST_ENTRY(uvideo_stream) entries;
242 
243 	uvideo_state		vs_state;
244 };
245 SLIST_HEAD(uvideo_stream_list, uvideo_stream);
246 
247 struct uvideo_softc {
248         device_t   	sc_dev;		/* base device */
249         struct usbd_device	*sc_udev;	/* device */
250 	struct usbd_interface	*sc_iface;	/* interface handle */
251         int     		sc_ifaceno;	/* interface number */
252 	char			*sc_devname;
253 
254 	int			sc_dying;
255 
256 	uint8_t			sc_nunits;
257 	struct uvideo_unit	**sc_unit;
258 
259 	struct uvideo_stream_list sc_stream_list;
260 
261 	char			sc_businfo[32];
262 };
263 
264 static int	uvideo_match(device_t, cfdata_t, void *);
265 static void	uvideo_attach(device_t, device_t, void *);
266 static int	uvideo_detach(device_t, int);
267 static void	uvideo_childdet(device_t, device_t);
268 static int	uvideo_activate(device_t, enum devact);
269 
270 static int	uvideo_open(void *, int);
271 static void	uvideo_close(void *);
272 static const char * uvideo_get_devname(void *);
273 static const char * uvideo_get_businfo(void *);
274 
275 static int	uvideo_enum_format(void *, uint32_t, struct video_format *);
276 static int	uvideo_get_format(void *, struct video_format *);
277 static int	uvideo_set_format(void *, struct video_format *);
278 static int	uvideo_try_format(void *, struct video_format *);
279 static int	uvideo_get_framerate(void *, struct video_fract *);
280 static int	uvideo_set_framerate(void *, struct video_fract *);
281 static int	uvideo_start_transfer(void *);
282 static int	uvideo_stop_transfer(void *);
283 
284 static int	uvideo_get_control_group(void *,
285 					 struct video_control_group *);
286 static int	uvideo_set_control_group(void *,
287 					 const struct video_control_group *);
288 
289 static usbd_status	uvideo_init_control(
290 	struct uvideo_softc *,
291 	const usb_interface_descriptor_t *,
292 	usbd_desc_iter_t *);
293 static usbd_status	uvideo_init_collection(
294 	struct uvideo_softc *,
295 	const usb_interface_descriptor_t *,
296 	usbd_desc_iter_t *);
297 
298 /* Functions for unit & terminal descriptors */
299 static struct uvideo_unit *	uvideo_unit_alloc(const uvideo_descriptor_t *);
300 static usbd_status		uvideo_unit_init(struct uvideo_unit *,
301 						 const uvideo_descriptor_t *);
302 static void			uvideo_unit_free(struct uvideo_unit *);
303 static void			uvideo_unit_alloc_controls(struct uvideo_unit *,
304 							   uint8_t,
305 							   const uint8_t *);
306 static void			uvideo_unit_free_controls(struct uvideo_unit *);
307 static void			uvideo_unit_alloc_sources(struct uvideo_unit *,
308 							  uint8_t,
309 							  const uint8_t *);
310 static void			uvideo_unit_free_sources(struct uvideo_unit *);
311 
312 
313 
314 
315 /*
316  * Functions for uvideo_stream, primary unit associated with a video
317  * driver or device file.
318  */
319 static struct uvideo_stream *	uvideo_find_stream(struct uvideo_softc *,
320 						   uint8_t);
321 #if 0
322 static struct uvideo_format *	uvideo_stream_find_format(
323 	struct uvideo_stream *,
324 	uint8_t, uint8_t);
325 #endif
326 static struct uvideo_format *	uvideo_stream_guess_format(
327 	struct uvideo_stream *,
328 	enum video_pixel_format, uint32_t, uint32_t);
329 static struct uvideo_stream *	uvideo_stream_alloc(void);
330 static usbd_status		uvideo_stream_init(
331 	struct uvideo_stream *,
332 	struct uvideo_softc *,
333 	const usb_interface_descriptor_t *);
334 static usbd_status		uvideo_stream_init_desc(
335 	struct uvideo_stream *,
336 	const usb_interface_descriptor_t *,
337 	usbd_desc_iter_t *);
338 static usbd_status		uvideo_stream_init_frame_based_format(
339 	struct uvideo_stream *,
340 	const uvideo_descriptor_t *,
341 	usbd_desc_iter_t *);
342 static void			uvideo_stream_free(struct uvideo_stream *);
343 
344 static int		uvideo_stream_start_xfer(struct uvideo_stream *);
345 static int		uvideo_stream_stop_xfer(struct uvideo_stream *);
346 static usbd_status	uvideo_stream_recv_process(struct uvideo_stream *,
347 						   uint8_t *, uint32_t);
348 static usbd_status	uvideo_stream_recv_isoc_start(struct uvideo_stream *);
349 static usbd_status	uvideo_stream_recv_isoc_start1(struct uvideo_isoc *);
350 static void		uvideo_stream_recv_isoc_complete(struct usbd_xfer *,
351 							 void *,
352 							 usbd_status);
353 static void		uvideo_stream_recv_bulk_transfer(void *);
354 
355 /* format probe and commit */
356 #define uvideo_stream_probe(vs, act, data)				\
357 	(uvideo_stream_probe_and_commit((vs), (act),			\
358 					UVIDEO_VS_PROBE_CONTROL, (data)))
359 #define uvideo_stream_commit(vs, act, data)				\
360 	(uvideo_stream_probe_and_commit((vs), (act),			\
361 					UVIDEO_VS_COMMIT_CONTROL, (data)))
362 static usbd_status	uvideo_stream_probe_and_commit(struct uvideo_stream *,
363 						       uint8_t, uint8_t,
364 						       void *);
365 static void		uvideo_init_probe_data(uvideo_probe_and_commit_data_t *);
366 
367 
368 static int	usb_guid_cmp(const usb_guid_t *, const guid_t *);
369 
370 
371 CFATTACH_DECL2_NEW(uvideo, sizeof(struct uvideo_softc),
372     uvideo_match, uvideo_attach, uvideo_detach, uvideo_activate, NULL,
373     uvideo_childdet);
374 
375 
376 
377 
378 static const struct video_hw_if uvideo_hw_if = {
379 	.open = uvideo_open,
380 	.close = uvideo_close,
381 	.get_devname = uvideo_get_devname,
382 	.get_businfo = uvideo_get_businfo,
383 	.enum_format = uvideo_enum_format,
384 	.get_format = uvideo_get_format,
385 	.set_format = uvideo_set_format,
386 	.try_format = uvideo_try_format,
387 	.get_framerate = uvideo_get_framerate,
388 	.set_framerate = uvideo_set_framerate,
389 	.start_transfer = uvideo_start_transfer,
390 	.stop_transfer = uvideo_stop_transfer,
391 	.control_iter_init = NULL,
392 	.control_iter_next = NULL,
393 	.get_control_desc_group = NULL,
394 	.get_control_group = uvideo_get_control_group,
395 	.set_control_group = uvideo_set_control_group,
396 };
397 
398 #ifdef UVIDEO_DEBUG
399 /*
400  * Some functions to print out descriptors.  Mostly useless other than
401  * debugging/exploration purposes.
402  */
403 static void usb_guid_print(const usb_guid_t *);
404 static void print_descriptor(const usb_descriptor_t *);
405 static void print_interface_descriptor(const usb_interface_descriptor_t *);
406 static void print_endpoint_descriptor(const usb_endpoint_descriptor_t *);
407 
408 static void print_vc_descriptor(const usb_descriptor_t *);
409 static void print_vs_descriptor(const usb_descriptor_t *);
410 
411 static void print_vc_header_descriptor(
412 	const uvideo_vc_header_descriptor_t *);
413 static void print_input_terminal_descriptor(
414 	const uvideo_input_terminal_descriptor_t *);
415 static void print_output_terminal_descriptor(
416 	const uvideo_output_terminal_descriptor_t *);
417 static void print_camera_terminal_descriptor(
418 	const uvideo_camera_terminal_descriptor_t *);
419 static void print_selector_unit_descriptor(
420 	const uvideo_selector_unit_descriptor_t *);
421 static void print_processing_unit_descriptor(
422 	const uvideo_processing_unit_descriptor_t *);
423 static void print_extension_unit_descriptor(
424 	const uvideo_extension_unit_descriptor_t *);
425 static void print_interrupt_endpoint_descriptor(
426 	const uvideo_vc_interrupt_endpoint_descriptor_t *);
427 
428 static void print_vs_input_header_descriptor(
429 	const uvideo_vs_input_header_descriptor_t *);
430 static void print_vs_output_header_descriptor(
431 	const uvideo_vs_output_header_descriptor_t *);
432 
433 static void print_vs_format_uncompressed_descriptor(
434 	const uvideo_vs_format_uncompressed_descriptor_t *);
435 static void print_vs_frame_uncompressed_descriptor(
436 	const uvideo_vs_frame_uncompressed_descriptor_t *);
437 static void print_vs_format_mjpeg_descriptor(
438 	const uvideo_vs_format_mjpeg_descriptor_t *);
439 static void print_vs_frame_mjpeg_descriptor(
440 	const uvideo_vs_frame_mjpeg_descriptor_t *);
441 static void print_vs_format_dv_descriptor(
442 	const uvideo_vs_format_dv_descriptor_t *);
443 #endif /* !UVIDEO_DEBUG */
444 
445 #define GET(type, descp, field) (((const type *)(descp))->field)
446 #define GETP(type, descp, field) (&(((const type *)(descp))->field))
447 
448 /*
449  * Given a format descriptor and frame descriptor, copy values common
450  * to all formats into a struct uvideo_format.
451  */
452 #define UVIDEO_FORMAT_INIT_FRAME_BASED(format_type, format_desc,	\
453 				       frame_type, frame_desc,		\
454 				       format)				\
455 	do {								\
456 		UVIDEO_FORMAT_SET_FORMAT_INDEX(				\
457 			format,						\
458 			GET(format_type, format_desc, bFormatIndex));	\
459 		UVIDEO_FORMAT_SET_FRAME_INDEX(				\
460 			format,						\
461 			GET(frame_type, frame_desc, bFrameIndex));	\
462 		format->format.width =					\
463 		    UGETW(GET(frame_type, frame_desc, wWidth));		\
464 		format->format.height =					\
465 		    UGETW(GET(frame_type, frame_desc, wHeight));	\
466 		format->format.aspect_x =				\
467 		    GET(format_type, format_desc, bAspectRatioX);	\
468 		format->format.aspect_y =				\
469 		    GET(format_type, format_desc, bAspectRatioY);	\
470 	} while (0)
471 
472 
473 static int
uvideo_match(device_t parent,cfdata_t match,void * aux)474 uvideo_match(device_t parent, cfdata_t match, void *aux)
475 {
476 	struct usbif_attach_arg *uiaa = aux;
477 
478         /*
479          * TODO: May need to change in the future to work with
480          * Interface Association Descriptor.
481 	 */
482 
483 	/* Trigger on the Video Control Interface which must be present */
484 	if (uiaa->uiaa_class == UICLASS_VIDEO &&
485 	    uiaa->uiaa_subclass == UISUBCLASS_VIDEOCONTROL)
486 		return UMATCH_IFACECLASS_IFACESUBCLASS;
487 
488 	return UMATCH_NONE;
489 }
490 
491 static void
uvideo_attach(device_t parent,device_t self,void * aux)492 uvideo_attach(device_t parent, device_t self, void *aux)
493 {
494 	struct uvideo_softc *sc = device_private(self);
495 	struct usbif_attach_arg *uiaa = aux;
496 	usbd_desc_iter_t iter;
497 	const usb_interface_descriptor_t *ifdesc;
498 	struct uvideo_stream *vs;
499 	usbd_status err;
500 
501 	sc->sc_dev = self;
502 
503 	sc->sc_devname = usbd_devinfo_alloc(uiaa->uiaa_device, 0);
504 
505 	aprint_naive("\n");
506 	aprint_normal(": %s\n", sc->sc_devname);
507 
508 	sc->sc_udev = uiaa->uiaa_device;
509 	sc->sc_iface = uiaa->uiaa_iface;
510 	sc->sc_ifaceno = uiaa->uiaa_ifaceno;
511 	sc->sc_dying = 0;
512 	SLIST_INIT(&sc->sc_stream_list);
513 	snprintf(sc->sc_businfo, sizeof(sc->sc_businfo), "usb:%08x",
514 	    sc->sc_udev->ud_cookie.cookie);
515 
516 #ifdef UVIDEO_DEBUG
517 	/*
518 	 * Debugging dump of descriptors. TODO: move this to userspace
519 	 * via a custom IOCTL or something.
520 	 */
521 	const usb_descriptor_t *desc;
522 	usb_desc_iter_init(sc->sc_udev, &iter);
523 	while ((desc = usb_desc_iter_next(&iter)) != NULL) {
524 		/* print out all descriptors */
525 		printf("uvideo_attach: ");
526 		print_descriptor(desc);
527 	}
528 #endif /* !UVIDEO_DEBUG */
529 
530 	/* iterate through interface descriptors and initialize softc */
531 	usb_desc_iter_init(sc->sc_udev, &iter);
532 	while ((ifdesc = usb_desc_iter_next_interface(&iter)) != NULL) {
533 		KASSERT(ifdesc->bLength >= USB_INTERFACE_DESCRIPTOR_SIZE);
534 		if (ifdesc->bInterfaceClass != UICLASS_VIDEO) {
535 			DPRINTFN(50, ("uvideo_attach: "
536 				      "ignoring non-uvc interface: "
537 				      "len=%d type=0x%02x "
538 				      "class=0x%02x subclass=0x%02x\n",
539 				      ifdesc->bLength,
540 				      ifdesc->bDescriptorType,
541 				      ifdesc->bInterfaceClass,
542 				      ifdesc->bInterfaceSubClass));
543 			continue;
544 		}
545 
546 		switch (ifdesc->bInterfaceSubClass) {
547 		case UISUBCLASS_VIDEOCONTROL:
548 			err = uvideo_init_control(sc, ifdesc, &iter);
549 			if (err != USBD_NORMAL_COMPLETION) {
550 				DPRINTF(("uvideo_attach: error with interface "
551 					 "%d, VideoControl, "
552 					 "descriptor len=%d type=0x%02x: "
553 					 "%s (%d)\n",
554 					 ifdesc->bInterfaceNumber,
555 					 ifdesc->bLength,
556 					 ifdesc->bDescriptorType,
557 					 usbd_errstr(err), err));
558 			}
559 			break;
560 		case UISUBCLASS_VIDEOSTREAMING:
561 			vs = uvideo_find_stream(sc, ifdesc->bInterfaceNumber);
562 			if (vs == NULL) {
563 				vs = uvideo_stream_alloc();
564 				err = uvideo_stream_init(vs, sc, ifdesc);
565 				if (err != USBD_NORMAL_COMPLETION) {
566 					DPRINTF(("uvideo_attach: "
567 						 "error initializing stream: "
568 						 "%s (%d)\n",
569 						 usbd_errstr(err), err));
570 					goto bad;
571 				}
572 			}
573 			err = uvideo_stream_init_desc(vs, ifdesc, &iter);
574 			if (err != USBD_NORMAL_COMPLETION) {
575 				DPRINTF(("uvideo_attach: "
576 					 "error initializing stream descriptor: "
577 					 "%s (%d)\n",
578 					 usbd_errstr(err), err));
579 				goto bad;
580 			}
581 			break;
582 		case UISUBCLASS_VIDEOCOLLECTION:
583 			err = uvideo_init_collection(sc, ifdesc, &iter);
584 			if (err != USBD_NORMAL_COMPLETION) {
585 				DPRINTF(("uvideo_attach: error with interface "
586 				       "%d, VideoCollection, "
587 				       "descriptor len=%d type=0x%02x: "
588 				       "%s (%d)\n",
589 				       ifdesc->bInterfaceNumber,
590 				       ifdesc->bLength,
591 				       ifdesc->bDescriptorType,
592 				       usbd_errstr(err), err));
593 				goto bad;
594 			}
595 			break;
596 		default:
597 			DPRINTF(("uvideo_attach: unknown UICLASS_VIDEO "
598 				 "subclass=0x%02x\n",
599 				 ifdesc->bInterfaceSubClass));
600 			break;
601 		}
602 
603 	}
604 
605 
606 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev);
607 
608 	if (!pmf_device_register(self, NULL, NULL))
609 		aprint_error_dev(self, "couldn't establish power handler\n");
610 
611 	SLIST_FOREACH(vs, &sc->sc_stream_list, entries) {
612 		/*
613 		 * If the descriptor is invalid, there may be no
614 		 * default format.
615 		 *
616 		 * XXX Maybe this should just be removed from the list
617 		 * at some other point, but finding the right other
618 		 * point is not trivial.
619 		 */
620 		if (vs->vs_default_format == NULL)
621 			continue;
622 		/* XXX initialization of vs_videodev is racy */
623 		vs->vs_videodev = video_attach_mi(&uvideo_hw_if, sc->sc_dev,
624 		    vs);
625 	}
626 
627 	return;
628 
629 bad:
630 	if (err != USBD_NORMAL_COMPLETION) {
631 		DPRINTF(("uvideo_attach: error: %s (%d)\n",
632 			 usbd_errstr(err), err));
633 	}
634 	return;
635 }
636 
637 
638 static int
uvideo_activate(device_t self,enum devact act)639 uvideo_activate(device_t self, enum devact act)
640 {
641 	struct uvideo_softc *sc = device_private(self);
642 
643 	switch (act) {
644 	case DVACT_DEACTIVATE:
645 		DPRINTF(("uvideo_activate: deactivating\n"));
646 		sc->sc_dying = 1;
647 		return 0;
648 	default:
649 		return EOPNOTSUPP;
650 	}
651 }
652 
653 
654 /* Detach child (video interface) */
655 static void
uvideo_childdet(device_t self,device_t child)656 uvideo_childdet(device_t self, device_t child)
657 {
658 	struct uvideo_softc *sc = device_private(self);
659 	struct uvideo_stream *vs;
660 
661 	SLIST_FOREACH(vs, &sc->sc_stream_list, entries) {
662 		if (child == vs->vs_videodev) {
663 			vs->vs_videodev = NULL;
664 			break;
665 		}
666 	}
667 	KASSERTMSG(vs != NULL, "unknown child of %s detached: %s @ %p",
668 	    device_xname(self), device_xname(child), child);
669 }
670 
671 
672 static int
uvideo_detach(device_t self,int flags)673 uvideo_detach(device_t self, int flags)
674 {
675 	struct uvideo_softc *sc = device_private(self);
676 	struct uvideo_stream *vs;
677 	int error;
678 
679 	error = config_detach_children(self, flags);
680 	if (error)
681 		return error;
682 
683 	sc->sc_dying = 1;
684 
685 	pmf_device_deregister(self);
686 
687 	/*
688 	 * TODO: close the device if it is currently opened?  Or will
689 	 * close be called automatically?
690 	 */
691 
692 	while (!SLIST_EMPTY(&sc->sc_stream_list)) {
693 		vs = SLIST_FIRST(&sc->sc_stream_list);
694 		SLIST_REMOVE_HEAD(&sc->sc_stream_list, entries);
695 		uvideo_stream_stop_xfer(vs);
696 		uvideo_stream_free(vs);
697 	}
698 
699 #if 0
700 	/*
701 	 * Wait for outstanding request to complete.  TODO: what is
702 	 * appropriate here?
703 	 */
704 	usbd_delay_ms(sc->sc_udev, 1000);
705 #endif
706 
707 	DPRINTFN(15, ("uvideo: detaching from %s\n",
708 		device_xname(sc->sc_dev)));
709 
710 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, sc->sc_dev);
711 
712 	usbd_devinfo_free(sc->sc_devname);
713 
714 	return 0;
715 }
716 
717 /*
718  * Search the stream list for a stream matching the interface number.
719  * This is an O(n) search, but most devices should have only one or at
720  * most two streams.
721  */
722 static struct uvideo_stream *
uvideo_find_stream(struct uvideo_softc * sc,uint8_t ifaceno)723 uvideo_find_stream(struct uvideo_softc *sc, uint8_t ifaceno)
724 {
725 	struct uvideo_stream *vs;
726 
727 	SLIST_FOREACH(vs, &sc->sc_stream_list, entries) {
728 		if (vs->vs_ifaceno == ifaceno)
729 			return vs;
730 	}
731 
732 	return NULL;
733 }
734 
735 /*
736  * Search the format list for the given format and frame index.  This
737  * might be improved through indexing, but the format and frame count
738  * is unknown ahead of time (only after iterating through the
739  * usb device descriptors).
740  */
741 #if 0
742 static struct uvideo_format *
743 uvideo_stream_find_format(struct uvideo_stream *vs,
744 			  uint8_t format_index, uint8_t frame_index)
745 {
746 	struct uvideo_format *format;
747 
748 	SIMPLEQ_FOREACH(format, &vs->vs_formats, entries) {
749 		if (UVIDEO_FORMAT_GET_FORMAT_INDEX(format) == format_index &&
750 		    UVIDEO_FORMAT_GET_FRAME_INDEX(format) == frame_index)
751 			return format;
752 	}
753 	return NULL;
754 }
755 #endif
756 
757 static struct uvideo_format *
uvideo_stream_guess_format(struct uvideo_stream * vs,enum video_pixel_format pixel_format,uint32_t width,uint32_t height)758 uvideo_stream_guess_format(struct uvideo_stream *vs,
759 			   enum video_pixel_format pixel_format,
760 			   uint32_t width, uint32_t height)
761 {
762 	struct uvideo_format *format, *gformat = NULL;
763 
764 	SIMPLEQ_FOREACH(format, &vs->vs_formats, entries) {
765 		if (format->format.pixel_format != pixel_format)
766 			continue;
767 		if (format->format.width <= width &&
768 		    format->format.height <= height) {
769 			if (gformat == NULL ||
770 			    (gformat->format.width < format->format.width &&
771 			     gformat->format.height < format->format.height))
772 				gformat = format;
773 		}
774 	}
775 
776 	return gformat;
777 }
778 
779 static struct uvideo_stream *
uvideo_stream_alloc(void)780 uvideo_stream_alloc(void)
781 {
782 	return kmem_zalloc(sizeof(*uvideo_stream_alloc()), KM_SLEEP);
783 }
784 
785 
786 static usbd_status
uvideo_init_control(struct uvideo_softc * sc,const usb_interface_descriptor_t * ifdesc,usbd_desc_iter_t * iter)787 uvideo_init_control(struct uvideo_softc *sc,
788 		    const usb_interface_descriptor_t *ifdesc,
789 		    usbd_desc_iter_t *iter)
790 {
791 	const usb_descriptor_t *desc;
792 	const uvideo_descriptor_t *uvdesc;
793 	usbd_desc_iter_t orig;
794 	uint8_t i, j, nunits;
795 
796 	/* save original iterator state */
797 	memcpy(&orig, iter, sizeof(orig));
798 
799 	/* count number of units and terminals */
800 	nunits = 0;
801 	while ((desc = usb_desc_iter_next_non_interface(iter)) != NULL) {
802 		if (desc->bDescriptorType != UDESC_CS_INTERFACE ||
803 		    desc->bLength < sizeof(*uvdesc))
804 			continue;
805 		uvdesc = (const uvideo_descriptor_t *)desc;
806 
807 		if (uvdesc->bDescriptorSubtype < UDESC_INPUT_TERMINAL ||
808 		    uvdesc->bDescriptorSubtype > UDESC_EXTENSION_UNIT)
809 			continue;
810 		KASSERT(nunits < 255);
811 		++nunits;
812 	}
813 
814 	if (nunits == 0) {
815 		DPRINTF(("uvideo_init_control: no units\n"));
816 		return USBD_NORMAL_COMPLETION;
817 	}
818 
819 	i = 0;
820 
821 	/* allocate space for units */
822 	sc->sc_nunits = nunits;
823 	sc->sc_unit = kmem_alloc(sizeof(*sc->sc_unit) * nunits, KM_SLEEP);
824 
825 	/* restore original iterator state */
826 	memcpy(iter, &orig, sizeof(orig));
827 
828 	/* iterate again, initializing the units */
829 	while ((desc = usb_desc_iter_next_non_interface(iter)) != NULL) {
830 		if (desc->bDescriptorType != UDESC_CS_INTERFACE ||
831 		    desc->bLength < sizeof(*uvdesc))
832 			continue;
833 		uvdesc = (const uvideo_descriptor_t *)desc;
834 
835 		if (uvdesc->bDescriptorSubtype < UDESC_INPUT_TERMINAL ||
836 		    uvdesc->bDescriptorSubtype > UDESC_EXTENSION_UNIT)
837 			continue;
838 
839 		sc->sc_unit[i] = uvideo_unit_alloc(uvdesc);
840 		/* TODO: free other units before returning? */
841 		if (sc->sc_unit[i] == NULL)
842 			goto enomem;
843 		KASSERT(i < 255);
844 		++i;
845 	}
846 
847 	return USBD_NORMAL_COMPLETION;
848 
849 enomem:
850 	if (sc->sc_unit != NULL) {
851 		for (j = 0; j < i; ++j) {
852 			uvideo_unit_free(sc->sc_unit[j]);
853 			sc->sc_unit[j] = NULL;
854 		}
855 		kmem_free(sc->sc_unit, sizeof(*sc->sc_unit) * nunits);
856 		sc->sc_unit = NULL;
857 	}
858 	sc->sc_nunits = 0;
859 
860 	return USBD_NOMEM;
861 }
862 
863 static usbd_status
uvideo_init_collection(struct uvideo_softc * sc,const usb_interface_descriptor_t * ifdesc,usbd_desc_iter_t * iter)864 uvideo_init_collection(struct uvideo_softc *sc,
865 		       const usb_interface_descriptor_t *ifdesc,
866 		       usbd_desc_iter_t *iter)
867 {
868 	DPRINTF(("uvideo: ignoring Video Collection\n"));
869 	return USBD_NORMAL_COMPLETION;
870 }
871 
872 /*
873  * Allocates space for and initializes a uvideo unit based on the
874  * given descriptor.  Returns NULL with bad descriptor or ENOMEM.
875  */
876 static struct uvideo_unit *
uvideo_unit_alloc(const uvideo_descriptor_t * desc)877 uvideo_unit_alloc(const uvideo_descriptor_t *desc)
878 {
879 	struct uvideo_unit *vu;
880 	usbd_status err;
881 
882 	KASSERT(desc->bDescriptorType == UDESC_CS_INTERFACE);
883 
884 	vu = kmem_zalloc(sizeof(*vu), KM_SLEEP);
885 	err = uvideo_unit_init(vu, desc);
886 	if (err != USBD_NORMAL_COMPLETION) {
887 		DPRINTF(("uvideo_unit_alloc: error initializing unit: "
888 			 "%s (%d)\n", usbd_errstr(err), err));
889 		kmem_free(vu, sizeof(*vu));
890 		return NULL;
891 	}
892 
893 	return vu;
894 }
895 
896 static usbd_status
uvideo_unit_init(struct uvideo_unit * vu,const uvideo_descriptor_t * desc)897 uvideo_unit_init(struct uvideo_unit *vu, const uvideo_descriptor_t *desc)
898 {
899 	struct uvideo_camera_terminal *ct;
900 	struct uvideo_processing_unit *pu;
901 
902 	const uvideo_input_terminal_descriptor_t *input;
903 	const uvideo_camera_terminal_descriptor_t *camera;
904 	const uvideo_selector_unit_descriptor_t *selector;
905 	const uvideo_processing_unit_descriptor_t *processing;
906 	const uvideo_extension_unit_descriptor_t *extension;
907 
908 	switch (desc->bDescriptorSubtype) {
909 	case UDESC_INPUT_TERMINAL:
910 		if (desc->bLength < sizeof(*input))
911 			return USBD_INVAL;
912 		input = (const uvideo_input_terminal_descriptor_t *)desc;
913 		switch (UGETW(input->wTerminalType)) {
914 		case UVIDEO_ITT_CAMERA:
915 			if (desc->bLength < sizeof(*camera))
916 				return USBD_INVAL;
917 			camera =
918 			    (const uvideo_camera_terminal_descriptor_t *)desc;
919 
920 			ct = &vu->u.vu_camera;
921 			ct->ct_objective_focal_min =
922 			    UGETW(camera->wObjectiveFocalLengthMin);
923 			ct->ct_objective_focal_max =
924 			    UGETW(camera->wObjectiveFocalLengthMax);
925 			ct->ct_ocular_focal_length =
926 			    UGETW(camera->wOcularFocalLength);
927 
928 			uvideo_unit_alloc_controls(vu, camera->bControlSize,
929 						   camera->bmControls);
930 			break;
931 		default:
932 			DPRINTF(("uvideo_unit_init: "
933 				 "unknown input terminal type 0x%04x\n",
934 				 UGETW(input->wTerminalType)));
935 			return USBD_INVAL;
936 		}
937 		break;
938 	case UDESC_OUTPUT_TERMINAL:
939 		break;
940 	case UDESC_SELECTOR_UNIT:
941 		if (desc->bLength < sizeof(*selector))
942 			return USBD_INVAL;
943 		selector = (const uvideo_selector_unit_descriptor_t *)desc;
944 
945 		uvideo_unit_alloc_sources(vu, selector->bNrInPins,
946 					  selector->baSourceID);
947 		break;
948 	case UDESC_PROCESSING_UNIT:
949 		if (desc->bLength < sizeof(*processing))
950 			return USBD_INVAL;
951 		processing = (const uvideo_processing_unit_descriptor_t *)desc;
952 		pu = &vu->u.vu_processing;
953 
954 		pu->pu_video_standards = PU_GET_VIDEO_STANDARDS(processing);
955 		pu->pu_max_multiplier = UGETW(processing->wMaxMultiplier);
956 
957 		uvideo_unit_alloc_sources(vu, 1, &processing->bSourceID);
958 		uvideo_unit_alloc_controls(vu, processing->bControlSize,
959 					   processing->bmControls);
960 		break;
961 	case UDESC_EXTENSION_UNIT:
962 		if (desc->bLength < sizeof(*extension))
963 			return USBD_INVAL;
964 		extension = (const uvideo_extension_unit_descriptor_t *)desc;
965 		/* TODO: copy guid */
966 
967 		uvideo_unit_alloc_sources(vu, extension->bNrInPins,
968 					  extension->baSourceID);
969 		uvideo_unit_alloc_controls(vu, XU_GET_CONTROL_SIZE(extension),
970 					   XU_GET_CONTROLS(extension));
971 		break;
972 	default:
973 		DPRINTF(("uvideo_unit_alloc: unknown descriptor "
974 			 "type=0x%02x subtype=0x%02x\n",
975 			 desc->bDescriptorType, desc->bDescriptorSubtype));
976 		return USBD_INVAL;
977 	}
978 
979 	return USBD_NORMAL_COMPLETION;
980 }
981 
982 static void
uvideo_unit_free(struct uvideo_unit * vu)983 uvideo_unit_free(struct uvideo_unit *vu)
984 {
985 	uvideo_unit_free_sources(vu);
986 	uvideo_unit_free_controls(vu);
987 	kmem_free(vu, sizeof(*vu));
988 }
989 
990 static void
uvideo_unit_alloc_sources(struct uvideo_unit * vu,uint8_t nsrcs,const uint8_t * src_ids)991 uvideo_unit_alloc_sources(struct uvideo_unit *vu,
992 			  uint8_t nsrcs, const uint8_t *src_ids)
993 {
994 
995 	vu->vu_nsrcs = nsrcs;
996 	if (nsrcs == 0) {
997 		/* do nothing */
998 	} else if (nsrcs == 1) {
999 		vu->s.vu_src_id = src_ids[0];
1000 	} else {
1001 		vu->s.vu_src_id_ary =
1002 		    kmem_alloc(sizeof(*vu->s.vu_src_id_ary) * nsrcs, KM_SLEEP);
1003 		memcpy(vu->s.vu_src_id_ary, src_ids, nsrcs);
1004 	}
1005 }
1006 
1007 static void
uvideo_unit_free_sources(struct uvideo_unit * vu)1008 uvideo_unit_free_sources(struct uvideo_unit *vu)
1009 {
1010 
1011 	if (vu->vu_nsrcs <= 1)
1012 		return;
1013 
1014 	kmem_free(vu->s.vu_src_id_ary,
1015 	    sizeof(*vu->s.vu_src_id_ary) * vu->vu_nsrcs);
1016 	vu->s.vu_src_id_ary = NULL;
1017 	vu->vu_nsrcs = 0;
1018 }
1019 
1020 static void
uvideo_unit_alloc_controls(struct uvideo_unit * vu,uint8_t size,const uint8_t * controls)1021 uvideo_unit_alloc_controls(struct uvideo_unit *vu, uint8_t size,
1022 			   const uint8_t *controls)
1023 {
1024 
1025 	vu->vu_control_size = size;
1026 	if (size == 0)
1027 		return;
1028 
1029 	vu->vu_controls = kmem_alloc(sizeof(*vu->vu_controls) * size, KM_SLEEP);
1030 	memcpy(vu->vu_controls, controls, size);
1031 }
1032 
1033 static void
uvideo_unit_free_controls(struct uvideo_unit * vu)1034 uvideo_unit_free_controls(struct uvideo_unit *vu)
1035 {
1036 
1037 	if (vu->vu_control_size == 0)
1038 		return;
1039 
1040 	kmem_free(vu->vu_controls,
1041 	    sizeof(*vu->vu_controls) * vu->vu_control_size);
1042 	vu->vu_controls = NULL;
1043 	vu->vu_control_size = 0;
1044 }
1045 
1046 
1047 /*
1048  * Initialize a stream from a Video Streaming interface
1049  * descriptor. Adds the stream to the stream_list in uvideo_softc.
1050  * This should be called once for new streams, and
1051  * uvideo_stream_init_desc() should then be called for this and each
1052  * additional interface with the same interface number.
1053  */
1054 static usbd_status
uvideo_stream_init(struct uvideo_stream * vs,struct uvideo_softc * sc,const usb_interface_descriptor_t * ifdesc)1055 uvideo_stream_init(struct uvideo_stream *vs,
1056 		   struct uvideo_softc *sc,
1057 		   const usb_interface_descriptor_t *ifdesc)
1058 {
1059 	uWord len;
1060 	usbd_status err;
1061 
1062 	DPRINTF(("%s: %s ifaceno=%d vs=%p\n", __func__,
1063 		device_xname(sc->sc_dev),
1064 		ifdesc->bInterfaceNumber,
1065 		vs));
1066 
1067 	SLIST_INSERT_HEAD(&sc->sc_stream_list, vs, entries);
1068 	vs->vs_parent = sc;
1069 	vs->vs_ifaceno = ifdesc->bInterfaceNumber;
1070 	vs->vs_subtype = 0;
1071 	SIMPLEQ_INIT(&vs->vs_formats);
1072 	SIMPLEQ_INIT(&vs->vs_pixel_formats);
1073 	vs->vs_default_format = NULL;
1074 	vs->vs_current_format.priv = -1;
1075 	vs->vs_xfer_type = 0;
1076 	vs->vs_state = UVIDEO_STATE_CLOSED;
1077 
1078 	err = usbd_device2interface_handle(sc->sc_udev, vs->vs_ifaceno,
1079 	    &vs->vs_iface);
1080 	if (err != USBD_NORMAL_COMPLETION) {
1081 		DPRINTF(("uvideo_stream_init: "
1082 			 "error getting vs interface: "
1083 			 "%s (%d)\n",
1084 			 usbd_errstr(err), err));
1085 		return err;
1086 	}
1087 
1088 	/*
1089 	 * For Xbox Live Vision camera, linux-uvc folk say we need to
1090 	 * set an alternate interface and wait ~3 seconds prior to
1091 	 * doing the format probe/commit.  We set to alternate
1092 	 * interface 0, which is the default, zero bandwidth
1093 	 * interface.  This should not have adverse affects on other
1094 	 * cameras.  Errors are ignored.
1095 	 */
1096 	err = usbd_set_interface(vs->vs_iface, 0);
1097 	if (err != USBD_NORMAL_COMPLETION) {
1098 		DPRINTF(("uvideo_stream_init: error setting alt interface: "
1099 			 "%s (%d)\n",
1100 			 usbd_errstr(err), err));
1101 	}
1102 
1103 	/*
1104 	 * Initialize probe and commit data size.  This value is
1105 	 * dependent on the version of the spec the hardware
1106 	 * implements.
1107 	 */
1108 	err = uvideo_stream_probe(vs, UR_GET_LEN, &len);
1109 	if (err != USBD_NORMAL_COMPLETION) {
1110 		DPRINTF(("uvideo_stream_init: "
1111 			 "error getting probe data len: "
1112 			 "%s (%d)\n",
1113 			 usbd_errstr(err), err));
1114 		vs->vs_probelen = 26; /* conservative v1.0 length */
1115 	} else if (UGETW(len) <= sizeof(uvideo_probe_and_commit_data_t)) {
1116 		DPRINTFN(15,("uvideo_stream_init: probelen=%d\n", UGETW(len)));
1117 		vs->vs_probelen = UGETW(len);
1118 	} else {
1119 		DPRINTFN(15,("uvideo_stream_init: device returned invalid probe"
1120 				" len %d, using default\n", UGETW(len)));
1121 		vs->vs_probelen = 26;
1122 	}
1123 
1124 	return USBD_NORMAL_COMPLETION;
1125 }
1126 
1127 /*
1128  * Further stream initialization based on a Video Streaming interface
1129  * descriptor and following descriptors belonging to that interface.
1130  * Iterates through all descriptors belonging to this particular
1131  * interface descriptor, modifying the iterator.  This may be called
1132  * multiple times because there may be several alternate interfaces
1133  * associated with the same interface number.
1134  */
1135 static usbd_status
uvideo_stream_init_desc(struct uvideo_stream * vs,const usb_interface_descriptor_t * ifdesc,usbd_desc_iter_t * iter)1136 uvideo_stream_init_desc(struct uvideo_stream *vs,
1137 			const usb_interface_descriptor_t *ifdesc,
1138 			usbd_desc_iter_t *iter)
1139 {
1140 	const usb_descriptor_t *desc;
1141 	const uvideo_descriptor_t *uvdesc;
1142 	struct uvideo_bulk_xfer *bx;
1143 	struct uvideo_isoc_xfer *ix;
1144 	struct uvideo_alternate *alt;
1145 	uint8_t xfer_type, xfer_dir;
1146 	uint8_t bmAttributes, bEndpointAddress;
1147 	int i;
1148 
1149 	DPRINTF(("%s: bInterfaceNumber=%d bAlternateSetting=%d\n", __func__,
1150 		ifdesc->bInterfaceNumber, ifdesc->bAlternateSetting));
1151 
1152 	/*
1153 	 * Iterate until the next interface descriptor.  All
1154 	 * descriptors until then belong to this streaming
1155 	 * interface.
1156 	 */
1157 	while ((desc = usb_desc_iter_next_non_interface(iter)) != NULL) {
1158 		switch (desc->bDescriptorType) {
1159 		case UDESC_ENDPOINT:
1160 			if (desc->bLength < sizeof(usb_endpoint_descriptor_t))
1161 				goto baddesc;
1162 			bmAttributes = GET(usb_endpoint_descriptor_t,
1163 					   desc, bmAttributes);
1164 			bEndpointAddress = GET(usb_endpoint_descriptor_t,
1165 					       desc, bEndpointAddress);
1166 			xfer_type = UE_GET_XFERTYPE(bmAttributes);
1167 			xfer_dir = UE_GET_DIR(bEndpointAddress);
1168 			if (xfer_type == UE_BULK && xfer_dir == UE_DIR_IN) {
1169 				bx = &vs->vs_xfer.bulk;
1170 				if (vs->vs_xfer_type == 0) {
1171 					DPRINTFN(15, ("uvideo_attach: "
1172 						      "BULK stream *\n"));
1173 					vs->vs_xfer_type = UE_BULK;
1174 					bx->bx_endpt = bEndpointAddress;
1175 					DPRINTF(("uvideo_attach: BULK "
1176 						 "endpoint %x\n",
1177 						 bx->bx_endpt));
1178 					bx->bx_running = false;
1179 					cv_init(&bx->bx_cv,
1180 					    device_xname(vs->vs_parent->sc_dev)
1181 					    );
1182 					mutex_init(&bx->bx_lock,
1183 					  MUTEX_DEFAULT, IPL_NONE);
1184 				}
1185 			} else if (xfer_type == UE_ISOCHRONOUS) {
1186 				ix = &vs->vs_xfer.isoc;
1187 				for (i = 0; i < UVIDEO_NXFERS; i++) {
1188 					ix->ix_i[i].i_ix = ix;
1189 					ix->ix_i[i].i_vs = vs;
1190 				}
1191 				if (vs->vs_xfer_type == 0) {
1192 					DPRINTFN(15, ("uvideo_attach: "
1193 						      "ISOC stream *\n"));
1194 					SLIST_INIT(&ix->ix_altlist);
1195 					vs->vs_xfer_type = UE_ISOCHRONOUS;
1196 					ix->ix_endpt =
1197 					    GET(usb_endpoint_descriptor_t,
1198 						desc, bEndpointAddress);
1199 				}
1200 
1201 				alt = kmem_alloc(sizeof(*alt), KM_SLEEP);
1202 				alt->altno = ifdesc->bAlternateSetting;
1203 				alt->interval =
1204 				    GET(usb_endpoint_descriptor_t,
1205 					desc, bInterval);
1206 
1207 				alt->max_packet_size =
1208 				UE_GET_SIZE(UGETW(GET(usb_endpoint_descriptor_t,
1209 					desc, wMaxPacketSize)));
1210 				alt->max_packet_size *=
1211 					(UE_GET_TRANS(UGETW(GET(
1212 						usb_endpoint_descriptor_t, desc,
1213 						wMaxPacketSize)))) + 1;
1214 
1215 				SLIST_INSERT_HEAD(&ix->ix_altlist,
1216 						  alt, entries);
1217 			}
1218 			break;
1219 		case UDESC_CS_INTERFACE:
1220 			if (desc->bLength < sizeof(*uvdesc))
1221 				goto baddesc;
1222 			uvdesc = (const uvideo_descriptor_t *)desc;
1223 			if (ifdesc->bAlternateSetting != 0) {
1224 				DPRINTF(("uvideo_stream_init_alternate: "
1225 					 "unexpected class-specific descriptor "
1226 					 "len=%d type=0x%02x subtype=0x%02x\n",
1227 					 uvdesc->bLength,
1228 					 uvdesc->bDescriptorType,
1229 					 uvdesc->bDescriptorSubtype));
1230 				break;
1231 			}
1232 
1233 			switch (uvdesc->bDescriptorSubtype) {
1234 			case UDESC_VS_INPUT_HEADER:
1235 				vs->vs_subtype = UDESC_VS_INPUT_HEADER;
1236 				break;
1237 			case UDESC_VS_OUTPUT_HEADER:
1238 				/* TODO: handle output stream */
1239 				DPRINTF(("uvideo: VS output not implemented\n"));
1240 				vs->vs_subtype = UDESC_VS_OUTPUT_HEADER;
1241 				return USBD_INVAL;
1242 			case UDESC_VS_FORMAT_UNCOMPRESSED:
1243 			case UDESC_VS_FORMAT_FRAME_BASED:
1244 			case UDESC_VS_FORMAT_MJPEG:
1245 				uvideo_stream_init_frame_based_format(vs,
1246 								      uvdesc,
1247 								      iter);
1248 				break;
1249 			case UDESC_VS_FORMAT_MPEG2TS:
1250 			case UDESC_VS_FORMAT_DV:
1251 			case UDESC_VS_FORMAT_STREAM_BASED:
1252 			default:
1253 				DPRINTF(("uvideo: unimplemented VS CS "
1254 					 "descriptor len=%d type=0x%02x "
1255 					 "subtype=0x%02x\n",
1256 					 uvdesc->bLength,
1257 					 uvdesc->bDescriptorType,
1258 					 uvdesc->bDescriptorSubtype));
1259 				break;
1260 			}
1261 			break;
1262 		default:
1263 		baddesc:
1264 			DPRINTF(("uvideo_stream_init_desc: "
1265 				 "bad descriptor "
1266 				 "len=%d type=0x%02x\n",
1267 				 desc->bLength,
1268 				 desc->bDescriptorType));
1269 			break;
1270 		}
1271 	}
1272 
1273 	DPRINTF(("%s: bInterfaceNumber=%d bAlternateSetting=%d done\n",
1274 		__func__,
1275 		ifdesc->bInterfaceNumber, ifdesc->bAlternateSetting));
1276 
1277 	return USBD_NORMAL_COMPLETION;
1278 }
1279 
1280 /* Finialize and free memory associated with this stream. */
1281 static void
uvideo_stream_free(struct uvideo_stream * vs)1282 uvideo_stream_free(struct uvideo_stream *vs)
1283 {
1284 	struct uvideo_alternate *alt;
1285 	struct uvideo_pixel_format *pixel_format;
1286 	struct uvideo_format *format;
1287 
1288 	/* free linked list of alternate interfaces */
1289 	if (vs->vs_xfer_type == UE_ISOCHRONOUS) {
1290 		while (!SLIST_EMPTY(&vs->vs_xfer.isoc.ix_altlist)) {
1291 			alt = SLIST_FIRST(&vs->vs_xfer.isoc.ix_altlist);
1292 			SLIST_REMOVE_HEAD(&vs->vs_xfer.isoc.ix_altlist,
1293 					  entries);
1294 			kmem_free(alt, sizeof(*alt));
1295 		}
1296 	}
1297 
1298 	/* free linked-list of formats and pixel formats */
1299 	while ((format = SIMPLEQ_FIRST(&vs->vs_formats)) != NULL) {
1300 		SIMPLEQ_REMOVE_HEAD(&vs->vs_formats, entries);
1301 		kmem_free(format, sizeof(*format));
1302 	}
1303 	while ((pixel_format = SIMPLEQ_FIRST(&vs->vs_pixel_formats)) != NULL) {
1304 		SIMPLEQ_REMOVE_HEAD(&vs->vs_pixel_formats, entries);
1305 		kmem_free(pixel_format, sizeof(*pixel_format));
1306 	}
1307 
1308 	kmem_free(vs, sizeof(*vs));
1309 }
1310 
1311 #define framedesc_size(T, d) ( \
1312 	offsetof(T, uFrameInterval) + \
1313 	((T *)(d))->bFrameIntervalType \
1314 	    ? ((T *)(d))->bFrameIntervalType \
1315 	        * sizeof(((T *)(d))->uFrameInterval.discrete) \
1316 	    : sizeof(((T *)(d))->uFrameInterval.continuous) \
1317 )
1318 
1319 static usbd_status
uvideo_stream_init_frame_based_format(struct uvideo_stream * vs,const uvideo_descriptor_t * format_desc,usbd_desc_iter_t * iter)1320 uvideo_stream_init_frame_based_format(struct uvideo_stream *vs,
1321 				      const uvideo_descriptor_t *format_desc,
1322 				      usbd_desc_iter_t *iter)
1323 {
1324 	struct uvideo_pixel_format *pformat, *pfiter;
1325 	enum video_pixel_format pixel_format;
1326 	struct uvideo_format *format;
1327 	const usb_descriptor_t *desc;
1328 	const uvideo_descriptor_t *uvdesc;
1329 	uint8_t subtype, subtypelen, default_index, index;
1330 	uint32_t frame_interval;
1331 	const usb_guid_t *guid;
1332 
1333 	DPRINTF(("%s: ifaceno=%d subtype=%d probelen=%d\n", __func__,
1334 		vs->vs_ifaceno, vs->vs_subtype, vs->vs_probelen));
1335 
1336 	pixel_format = VIDEO_FORMAT_UNDEFINED;
1337 
1338 	switch (format_desc->bDescriptorSubtype) {
1339 	case UDESC_VS_FORMAT_UNCOMPRESSED:
1340 		DPRINTF(("%s: uncompressed\n", __func__));
1341 		if (format_desc->bLength <
1342 		    sizeof(uvideo_vs_format_uncompressed_descriptor_t)) {
1343 			DPRINTF(("uvideo: truncated uncompressed format: %d\n",
1344 				format_desc->bLength));
1345 			return USBD_INVAL;
1346 		}
1347 		subtype = UDESC_VS_FRAME_UNCOMPRESSED;
1348 		default_index = GET(uvideo_vs_format_uncompressed_descriptor_t,
1349 				    format_desc,
1350 				    bDefaultFrameIndex);
1351 		guid = GETP(uvideo_vs_format_uncompressed_descriptor_t,
1352 			    format_desc,
1353 			    guidFormat);
1354 		if (usb_guid_cmp(guid, &uvideo_guid_format_yuy2) == 0)
1355 			pixel_format = VIDEO_FORMAT_YUY2;
1356 		else if (usb_guid_cmp(guid, &uvideo_guid_format_nv12) == 0)
1357 			pixel_format = VIDEO_FORMAT_NV12;
1358 		else if (usb_guid_cmp(guid, &uvideo_guid_format_uyvy) == 0)
1359 			pixel_format = VIDEO_FORMAT_UYVY;
1360 		else {
1361 #ifdef UVIDEO_DEBUG
1362 			DPRINTF(("%s: unknown format: ", __func__));
1363 			usb_guid_print(guid);
1364 			DPRINTF(("\n"));
1365 #endif
1366 		}
1367 		break;
1368 	case UDESC_VS_FORMAT_FRAME_BASED:
1369 		DPRINTF(("%s: frame-based\n", __func__));
1370 		if (format_desc->bLength <
1371 		    sizeof(uvideo_format_frame_based_descriptor_t)) {
1372 			DPRINTF(("uvideo: truncated frame-based format: %d\n",
1373 				format_desc->bLength));
1374 			return USBD_INVAL;
1375 		}
1376 		subtype = UDESC_VS_FRAME_FRAME_BASED;
1377 		default_index = GET(uvideo_format_frame_based_descriptor_t,
1378 				    format_desc,
1379 				    bDefaultFrameIndex);
1380 		break;
1381 	case UDESC_VS_FORMAT_MJPEG:
1382 		DPRINTF(("%s: mjpeg\n", __func__));
1383 		if (format_desc->bLength <
1384 		    sizeof(uvideo_vs_format_mjpeg_descriptor_t)) {
1385 			DPRINTF(("uvideo: truncated mjpeg format: %d\n",
1386 				format_desc->bLength));
1387 			return USBD_INVAL;
1388 		}
1389 		subtype = UDESC_VS_FRAME_MJPEG;
1390 		default_index = GET(uvideo_vs_format_mjpeg_descriptor_t,
1391 				    format_desc,
1392 				    bDefaultFrameIndex);
1393 		pixel_format = VIDEO_FORMAT_MJPEG;
1394 		break;
1395 	default:
1396 		DPRINTF(("uvideo: unknown frame based format %d\n",
1397 			 format_desc->bDescriptorSubtype));
1398 		return USBD_INVAL;
1399 	}
1400 
1401 	pformat = NULL;
1402 	SIMPLEQ_FOREACH(pfiter, &vs->vs_pixel_formats, entries) {
1403 		if (pfiter->pixel_format == pixel_format) {
1404 			pformat = pfiter;
1405 			break;
1406 		}
1407 	}
1408 	if (pixel_format != VIDEO_FORMAT_UNDEFINED && pformat == NULL) {
1409 		pformat = kmem_zalloc(sizeof(*pformat), KM_SLEEP);
1410 		pformat->pixel_format = pixel_format;
1411 		DPRINTF(("uvideo: Adding pixel format %d\n",
1412 		    pixel_format));
1413 		SIMPLEQ_INSERT_TAIL(&vs->vs_pixel_formats,
1414 		    pformat, entries);
1415 	}
1416 
1417 	/*
1418 	 * Iterate through frame descriptors directly following the
1419 	 * format descriptor, and add a format to the format list for
1420 	 * each frame descriptor.
1421 	 */
1422 	while ((desc = usb_desc_iter_peek(iter)) != NULL) {
1423 		if (desc->bDescriptorType != UDESC_CS_INTERFACE)
1424 			break;
1425 		if (desc->bLength < sizeof(*uvdesc)) {
1426 			DPRINTF(("uvideo: truncated CS descriptor, length %d\n",
1427 				desc->bLength));
1428 			break;
1429 		}
1430 		uvdesc = (const uvideo_descriptor_t *)desc;
1431 		if (uvdesc->bDescriptorSubtype != subtype)
1432 			break;
1433 
1434 		switch (format_desc->bDescriptorSubtype) {
1435 		case UDESC_VS_FORMAT_UNCOMPRESSED:
1436 			subtypelen = framedesc_size(
1437 			    const uvideo_vs_frame_uncompressed_descriptor_t,
1438 			    uvdesc);
1439 			break;
1440 		case UDESC_VS_FORMAT_MJPEG:
1441 			subtypelen = framedesc_size(
1442 			    const uvideo_vs_frame_mjpeg_descriptor_t,
1443 			    uvdesc);
1444 			break;
1445 		case UDESC_VS_FORMAT_FRAME_BASED:
1446 			subtypelen = framedesc_size(
1447 			    const uvideo_frame_frame_based_descriptor_t,
1448 			    uvdesc);
1449 			break;
1450 		default:
1451 			/* will bail out below */
1452 			subtypelen = uvdesc->bLength;
1453 			break;
1454 		}
1455 
1456 		if (uvdesc->bLength < subtypelen) {
1457 			DPRINTF(("uvideo:"
1458 				" truncated CS subtype-0x%x descriptor,"
1459 				" length %d < %d\n",
1460 				uvdesc->bDescriptorSubtype,
1461 				uvdesc->bLength, subtypelen));
1462 			break;
1463 		}
1464 
1465 		/* We peeked; now consume.  */
1466 		(void)usb_desc_iter_next(iter);
1467 
1468 		format = kmem_zalloc(sizeof(*format), KM_SLEEP);
1469 		format->format.pixel_format = pixel_format;
1470 
1471 		switch (format_desc->bDescriptorSubtype) {
1472 		case UDESC_VS_FORMAT_UNCOMPRESSED:
1473 #ifdef UVIDEO_DEBUG
1474 			if (pixel_format == VIDEO_FORMAT_UNDEFINED &&
1475 			    uvideodebug) {
1476 				guid = GETP(
1477 				    uvideo_vs_format_uncompressed_descriptor_t,
1478 				    format_desc,
1479 				    guidFormat);
1480 
1481 				DPRINTF(("uvideo: format undefined "));
1482 				usb_guid_print(guid);
1483 				DPRINTF(("\n"));
1484 			}
1485 #endif
1486 
1487 			UVIDEO_FORMAT_INIT_FRAME_BASED(
1488 				uvideo_vs_format_uncompressed_descriptor_t,
1489 				format_desc,
1490 				uvideo_vs_frame_uncompressed_descriptor_t,
1491 				uvdesc,
1492 				format);
1493 			format->format.sample_size =
1494 			    UGETDW(
1495 			      GET(uvideo_vs_frame_uncompressed_descriptor_t,
1496 			      uvdesc, dwMaxVideoFrameBufferSize));
1497 			format->format.stride =
1498 			    format->format.sample_size / format->format.height;
1499 			index = GET(uvideo_vs_frame_uncompressed_descriptor_t,
1500 				    uvdesc,
1501 				    bFrameIndex);
1502 			frame_interval =
1503 			    UGETDW(
1504 				GET(uvideo_vs_frame_uncompressed_descriptor_t,
1505 				uvdesc,
1506 				dwDefaultFrameInterval));
1507 			break;
1508 		case UDESC_VS_FORMAT_MJPEG:
1509 			UVIDEO_FORMAT_INIT_FRAME_BASED(
1510 				uvideo_vs_format_mjpeg_descriptor_t,
1511 				format_desc,
1512 				uvideo_vs_frame_mjpeg_descriptor_t,
1513 				uvdesc,
1514 				format);
1515 			format->format.sample_size =
1516 			    UGETDW(
1517 				GET(uvideo_vs_frame_mjpeg_descriptor_t,
1518 			        uvdesc, dwMaxVideoFrameBufferSize));
1519 			format->format.stride =
1520 			    format->format.sample_size / format->format.height;
1521 			index = GET(uvideo_vs_frame_mjpeg_descriptor_t,
1522 				    uvdesc,
1523 				    bFrameIndex);
1524 			frame_interval =
1525 			    UGETDW(
1526 				GET(uvideo_vs_frame_mjpeg_descriptor_t,
1527 				uvdesc,
1528 				dwDefaultFrameInterval));
1529 			break;
1530 		case UDESC_VS_FORMAT_FRAME_BASED:
1531 			format->format.pixel_format = VIDEO_FORMAT_UNDEFINED;
1532 			UVIDEO_FORMAT_INIT_FRAME_BASED(
1533 				uvideo_format_frame_based_descriptor_t,
1534 				format_desc,
1535 				uvideo_frame_frame_based_descriptor_t,
1536 				uvdesc,
1537 				format);
1538 			index = GET(uvideo_frame_frame_based_descriptor_t,
1539 				    uvdesc,
1540 				    bFrameIndex);
1541 			format->format.stride =
1542 			    UGETDW(
1543 				GET(uvideo_frame_frame_based_descriptor_t,
1544 			        uvdesc, dwBytesPerLine));
1545 			format->format.sample_size =
1546 			    format->format.stride * format->format.height;
1547 			frame_interval =
1548 			    UGETDW(
1549 				GET(uvideo_frame_frame_based_descriptor_t,
1550 				uvdesc, dwDefaultFrameInterval));
1551 			break;
1552 		default:
1553 			/* shouldn't ever get here */
1554 			DPRINTF(("uvideo: unknown frame based format %d\n",
1555 				 format_desc->bDescriptorSubtype));
1556 			kmem_free(format, sizeof(*format));
1557 			return USBD_INVAL;
1558 		}
1559 
1560 		DPRINTF(("uvideo: found format (index %d) type %d "
1561 		    "size %ux%u size %u stride %u interval %u\n",
1562 		    index, format->format.pixel_format, format->format.width,
1563 		    format->format.height, format->format.sample_size,
1564 		    format->format.stride, frame_interval));
1565 
1566 		SIMPLEQ_INSERT_TAIL(&vs->vs_formats, format, entries);
1567 
1568 		if (vs->vs_default_format == NULL && index == default_index
1569 #ifdef UVIDEO_DISABLE_MJPEG
1570 		    && subtype != UDESC_VS_FRAME_MJPEG
1571 #endif
1572 		    ) {
1573 			DPRINTF((" ^ picking this one\n"));
1574 			vs->vs_default_format = &format->format;
1575 			vs->vs_frame_interval = frame_interval;
1576 		}
1577 
1578 	}
1579 
1580 	return USBD_NORMAL_COMPLETION;
1581 }
1582 
1583 static int
uvideo_stream_start_xfer(struct uvideo_stream * vs)1584 uvideo_stream_start_xfer(struct uvideo_stream *vs)
1585 {
1586 	struct uvideo_softc *sc = vs->vs_parent;
1587 	struct uvideo_bulk_xfer *bx;
1588 	struct uvideo_isoc_xfer *ix;
1589 	uint32_t vframe_len;	/* rough bytes per video frame */
1590 	uint32_t uframe_len;	/* bytes per usb frame (TODO: or microframe?) */
1591 	uint32_t nframes;	/* number of usb frames (TODO: or microframs?) */
1592 	int i, ret;
1593 	int error;
1594 
1595 	struct uvideo_alternate *alt, *alt_maybe;
1596 	usbd_status err;
1597 
1598 	switch (vs->vs_xfer_type) {
1599 	case UE_BULK:
1600 		ret = 0;
1601 		bx = &vs->vs_xfer.bulk;
1602 
1603 		err = usbd_open_pipe(vs->vs_iface, bx->bx_endpt, 0,
1604 		    &bx->bx_pipe);
1605 		if (err != USBD_NORMAL_COMPLETION) {
1606 			DPRINTF(("uvideo: error opening pipe: %s (%d)\n",
1607 				 usbd_errstr(err), err));
1608 			return EIO;
1609 		}
1610 		DPRINTF(("uvideo: pipe %p\n", bx->bx_pipe));
1611 
1612 		error = usbd_create_xfer(bx->bx_pipe, vs->vs_max_payload_size,
1613 		    0, 0, &bx->bx_xfer);
1614 		if (error) {
1615 			DPRINTF(("uvideo: couldn't allocate xfer\n"));
1616 			return error;
1617 		}
1618 		DPRINTF(("uvideo: xfer %p\n", bx->bx_xfer));
1619 
1620 		bx->bx_buflen = vs->vs_max_payload_size;
1621 		bx->bx_buffer = usbd_get_buffer(bx->bx_xfer);
1622 
1623 		mutex_enter(&bx->bx_lock);
1624 		if (bx->bx_running == false) {
1625 			bx->bx_running = true;
1626 			ret = kthread_create(PRI_UVIDEO, 0, NULL,
1627 			    uvideo_stream_recv_bulk_transfer, vs,
1628 			    NULL, "%s", device_xname(sc->sc_dev));
1629 			if (ret) {
1630 				DPRINTF(("uvideo: couldn't create kthread:"
1631 					 " %d\n", err));
1632 				bx->bx_running = false;
1633 				mutex_exit(&bx->bx_lock);
1634 				return err;
1635 			}
1636 		} else
1637 			aprint_error_dev(sc->sc_dev,
1638 			    "transfer already in progress\n");
1639 		mutex_exit(&bx->bx_lock);
1640 
1641 		DPRINTF(("uvideo: thread created\n"));
1642 
1643 		return 0;
1644 	case UE_ISOCHRONOUS:
1645 		ix = &vs->vs_xfer.isoc;
1646 
1647 		/*
1648 		 * Choose an alternate interface most suitable for
1649 		 * this format.  Choose the smallest size that can
1650 		 * contain max_payload_size.
1651 		 *
1652 		 * It is assumed that the list is sorted in descending
1653 		 * order from largest to smallest packet size.
1654 		 *
1655 		 * TODO: what should the strategy be for choosing an
1656 		 * alt interface?
1657 		 */
1658 		alt = NULL;
1659 		SLIST_FOREACH(alt_maybe, &ix->ix_altlist, entries) {
1660 			/*
1661 			 * TODO: define "packet" and "payload".  I think
1662 			 * several packets can make up one payload which would
1663 			 * call into question this method of selecting an
1664 			 * alternate interface...
1665 			 */
1666 
1667 			if (alt_maybe->max_packet_size > vs->vs_max_payload_size)
1668 				continue;
1669 
1670 			if (alt == NULL ||
1671 			    alt_maybe->max_packet_size >= alt->max_packet_size)
1672 				alt = alt_maybe;
1673 		}
1674 
1675 		if (alt == NULL) {
1676 			DPRINTF(("uvideo_stream_start_xfer: "
1677 				 "no suitable alternate interface found\n"));
1678 			return EINVAL;
1679 		}
1680 
1681 		DPRINTFN(15,("uvideo_stream_start_xfer: "
1682 			     "choosing alternate interface "
1683 			     "%d wMaxPacketSize=%d bInterval=%d\n",
1684 			     alt->altno, alt->max_packet_size, alt->interval));
1685 
1686 		err = usbd_set_interface(vs->vs_iface, alt->altno);
1687 		if (err != USBD_NORMAL_COMPLETION) {
1688 			DPRINTF(("uvideo_stream_start_xfer: "
1689 				 "error setting alt interface: %s (%d)\n",
1690 				 usbd_errstr(err), err));
1691 			return EIO;
1692 		}
1693 
1694 		/* TODO: "packet" not same as frame */
1695 		vframe_len = vs->vs_current_format.sample_size;
1696 		uframe_len = alt->max_packet_size;
1697 		nframes = (vframe_len + uframe_len - 1) / uframe_len;
1698 		nframes = (nframes + 7) & ~7; /*round up for ehci inefficiency*/
1699 		nframes = uimin(UVIDEO_NFRAMES_MAX, nframes);
1700 		DPRINTF(("uvideo_stream_start_xfer: nframes=%d\n", nframes));
1701 
1702 		ix->ix_nframes = nframes;
1703 		ix->ix_uframe_len = uframe_len;
1704 		for (i = 0; i < UVIDEO_NXFERS; i++) {
1705 			struct uvideo_isoc *isoc = &ix->ix_i[i];
1706 			isoc->i_frlengths =
1707 			    kmem_alloc(sizeof(isoc->i_frlengths[0]) * nframes,
1708 				KM_SLEEP);
1709 		}
1710 
1711 		err = usbd_open_pipe(vs->vs_iface, ix->ix_endpt,
1712 				     USBD_EXCLUSIVE_USE, &ix->ix_pipe);
1713 		if (err != USBD_NORMAL_COMPLETION) {
1714 			DPRINTF(("uvideo: error opening pipe: %s (%d)\n",
1715 				 usbd_errstr(err), err));
1716 			return EIO;
1717 		}
1718 
1719 		for (i = 0; i < UVIDEO_NXFERS; i++) {
1720 			struct uvideo_isoc *isoc = &ix->ix_i[i];
1721 			error = usbd_create_xfer(ix->ix_pipe,
1722 			    nframes * uframe_len, 0, ix->ix_nframes,
1723 			    &isoc->i_xfer);
1724 			if (error) {
1725 				DPRINTF(("uvideo: "
1726 				    "couldn't allocate xfer (%d)\n", error));
1727 				return error;
1728 			}
1729 
1730 			isoc->i_buf = usbd_get_buffer(isoc->i_xfer);
1731 		}
1732 
1733 		uvideo_stream_recv_isoc_start(vs);
1734 
1735 		return 0;
1736 	default:
1737 		/* should never get here */
1738 		DPRINTF(("uvideo_stream_start_xfer: unknown xfer type %#x\n",
1739 			 vs->vs_xfer_type));
1740 		return EINVAL;
1741 	}
1742 }
1743 
1744 static int
uvideo_stream_stop_xfer(struct uvideo_stream * vs)1745 uvideo_stream_stop_xfer(struct uvideo_stream *vs)
1746 {
1747 	struct uvideo_bulk_xfer *bx;
1748 	struct uvideo_isoc_xfer *ix;
1749 	usbd_status err;
1750 	int i;
1751 
1752 	switch (vs->vs_xfer_type) {
1753 	case UE_BULK:
1754 		bx = &vs->vs_xfer.bulk;
1755 
1756 		DPRINTF(("uvideo_stream_stop_xfer: UE_BULK: "
1757 			 "waiting for thread to complete\n"));
1758 		mutex_enter(&bx->bx_lock);
1759 		if (bx->bx_running == true) {
1760 			bx->bx_running = false;
1761 			cv_wait_sig(&bx->bx_cv, &bx->bx_lock);
1762 		}
1763 		mutex_exit(&bx->bx_lock);
1764 
1765 		DPRINTF(("uvideo_stream_stop_xfer: UE_BULK: cleaning up\n"));
1766 
1767 		if (bx->bx_pipe) {
1768 			usbd_abort_pipe(bx->bx_pipe);
1769 		}
1770 
1771 		if (bx->bx_xfer) {
1772 			usbd_destroy_xfer(bx->bx_xfer);
1773 			bx->bx_xfer = NULL;
1774 		}
1775 
1776 		if (bx->bx_pipe) {
1777 			usbd_close_pipe(bx->bx_pipe);
1778 			bx->bx_pipe = NULL;
1779 		}
1780 
1781 		DPRINTF(("uvideo_stream_stop_xfer: UE_BULK: done\n"));
1782 
1783 		return 0;
1784 	case UE_ISOCHRONOUS:
1785 		ix = &vs->vs_xfer.isoc;
1786 		if (ix->ix_pipe != NULL) {
1787 			usbd_abort_pipe(ix->ix_pipe);
1788 		}
1789 
1790 		for (i = 0; i < UVIDEO_NXFERS; i++) {
1791 			struct uvideo_isoc *isoc = &ix->ix_i[i];
1792 			if (isoc->i_xfer != NULL) {
1793 				usbd_destroy_xfer(isoc->i_xfer);
1794 				isoc->i_xfer = NULL;
1795 			}
1796 		}
1797 
1798 		if (ix->ix_pipe != NULL) {
1799 			usbd_close_pipe(ix->ix_pipe);
1800 			ix->ix_pipe = NULL;
1801 		}
1802 
1803 		for (i = 0; i < UVIDEO_NXFERS; i++) {
1804 			struct uvideo_isoc *isoc = &ix->ix_i[i];
1805 			if (isoc->i_frlengths != NULL) {
1806 				kmem_free(isoc->i_frlengths,
1807 				  sizeof(isoc->i_frlengths[0]) *
1808 				  ix->ix_nframes);
1809 				isoc->i_frlengths = NULL;
1810 			}
1811 		}
1812 
1813 		/* Give it some time to settle */
1814 		usbd_delay_ms(vs->vs_parent->sc_udev, 20);
1815 
1816 		/* Set to zero bandwidth alternate interface zero */
1817 		err = usbd_set_interface(vs->vs_iface, 0);
1818 		if (err != USBD_NORMAL_COMPLETION) {
1819 			DPRINTF(("uvideo_stream_stop_transfer: "
1820 				 "error setting zero bandwidth interface: "
1821 				 "%s (%d)\n",
1822 				 usbd_errstr(err), err));
1823 			return EIO;
1824 		}
1825 
1826 		return 0;
1827 	default:
1828 		/* should never get here */
1829 		DPRINTF(("uvideo_stream_stop_xfer: unknown xfer type %#x\n",
1830 			 vs->vs_xfer_type));
1831 		return EINVAL;
1832 	}
1833 }
1834 
1835 static usbd_status
uvideo_stream_recv_isoc_start(struct uvideo_stream * vs)1836 uvideo_stream_recv_isoc_start(struct uvideo_stream *vs)
1837 {
1838 	int i;
1839 
1840 	for (i = 0; i < UVIDEO_NXFERS; i++)
1841 		uvideo_stream_recv_isoc_start1(&vs->vs_xfer.isoc.ix_i[i]);
1842 
1843 	return USBD_NORMAL_COMPLETION;
1844 }
1845 
1846 /* Initiate a usb transfer. */
1847 static usbd_status
uvideo_stream_recv_isoc_start1(struct uvideo_isoc * isoc)1848 uvideo_stream_recv_isoc_start1(struct uvideo_isoc *isoc)
1849 {
1850 	struct uvideo_isoc_xfer *ix;
1851 	usbd_status err;
1852 	int i;
1853 
1854 	ix = isoc->i_ix;
1855 
1856 	for (i = 0; i < ix->ix_nframes; ++i)
1857 		isoc->i_frlengths[i] = ix->ix_uframe_len;
1858 
1859 	usbd_setup_isoc_xfer(isoc->i_xfer,
1860 			     isoc,
1861 			     isoc->i_frlengths,
1862 			     ix->ix_nframes,
1863 			     USBD_SHORT_XFER_OK,
1864 			     uvideo_stream_recv_isoc_complete);
1865 
1866 	err = usbd_transfer(isoc->i_xfer);
1867 	if (err != USBD_IN_PROGRESS) {
1868 		DPRINTF(("uvideo_stream_recv_start: "
1869 			 "usbd_transfer status=%s (%d)\n",
1870 			 usbd_errstr(err), err));
1871 	}
1872 	return err;
1873 }
1874 
1875 static usbd_status
uvideo_stream_recv_process(struct uvideo_stream * vs,uint8_t * buf,uint32_t len)1876 uvideo_stream_recv_process(struct uvideo_stream *vs, uint8_t *buf, uint32_t len)
1877 {
1878 	uvideo_payload_header_t *hdr;
1879 	struct video_payload payload;
1880 
1881 	if (len < sizeof(uvideo_payload_header_t)) {
1882 		DPRINTF(("uvideo_stream_recv_process: len %d < payload hdr\n",
1883 			 len));
1884 		return USBD_SHORT_XFER;
1885 	}
1886 
1887 	hdr = (uvideo_payload_header_t *)buf;
1888 
1889 	if (hdr->bHeaderLength > UVIDEO_PAYLOAD_HEADER_SIZE ||
1890 	    hdr->bHeaderLength < sizeof(uvideo_payload_header_t))
1891 		return USBD_INVAL;
1892 	if (hdr->bHeaderLength == len && !(hdr->bmHeaderInfo & UV_END_OF_FRAME))
1893 		return USBD_INVAL;
1894 	if (hdr->bmHeaderInfo & UV_ERROR)
1895 		return USBD_IOERROR;
1896 
1897 	payload.data = buf + hdr->bHeaderLength;
1898 	payload.size = len - hdr->bHeaderLength;
1899 	payload.frameno = hdr->bmHeaderInfo & UV_FRAME_ID;
1900 	payload.end_of_frame = hdr->bmHeaderInfo & UV_END_OF_FRAME;
1901 
1902 	video_submit_payload(vs->vs_videodev, &payload);
1903 
1904 	return USBD_NORMAL_COMPLETION;
1905 }
1906 
1907 /* Callback on completion of usb isoc transfer */
1908 static void
uvideo_stream_recv_isoc_complete(struct usbd_xfer * xfer,void * priv,usbd_status status)1909 uvideo_stream_recv_isoc_complete(struct usbd_xfer *xfer,
1910 				 void *priv,
1911 				 usbd_status status)
1912 {
1913 	struct uvideo_stream *vs;
1914 	struct uvideo_isoc_xfer *ix;
1915 	struct uvideo_isoc *isoc;
1916 	int i;
1917 	uint32_t count;
1918 	uint8_t *buf;
1919 
1920 	isoc = priv;
1921 	vs = isoc->i_vs;
1922 	ix = isoc->i_ix;
1923 
1924 	if (status != USBD_NORMAL_COMPLETION) {
1925 		DPRINTF(("uvideo_stream_recv_isoc_complete: status=%s (%d)\n",
1926 			usbd_errstr(status), status));
1927 
1928 		if (status == USBD_STALLED)
1929 			usbd_clear_endpoint_stall_async(ix->ix_pipe);
1930 		else
1931 			return;
1932 	} else {
1933 		usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL);
1934 
1935 		if (count == 0) {
1936 			/* DPRINTF(("uvideo: zero length transfer\n")); */
1937 			goto next;
1938 		}
1939 
1940 
1941 		for (i = 0, buf = isoc->i_buf;
1942 		     i < ix->ix_nframes;
1943 		     ++i, buf += ix->ix_uframe_len)
1944 		{
1945 			status = uvideo_stream_recv_process(vs, buf,
1946 			    isoc->i_frlengths[i]);
1947 			if (status == USBD_IOERROR)
1948 				break;
1949 		}
1950 	}
1951 
1952 next:
1953 	uvideo_stream_recv_isoc_start1(isoc);
1954 }
1955 
1956 static void
uvideo_stream_recv_bulk_transfer(void * addr)1957 uvideo_stream_recv_bulk_transfer(void *addr)
1958 {
1959 	struct uvideo_stream *vs = addr;
1960 	struct uvideo_bulk_xfer *bx = &vs->vs_xfer.bulk;
1961 	usbd_status err;
1962 	uint32_t len;
1963 
1964 	DPRINTF(("uvideo_stream_recv_bulk_transfer: "
1965 		 "vs %p sc %p bx %p buffer %p\n", vs, vs->vs_parent, bx,
1966 		 bx->bx_buffer));
1967 
1968 	while (bx->bx_running) {
1969 		len = bx->bx_buflen;
1970 		err = usbd_bulk_transfer(bx->bx_xfer, bx->bx_pipe,
1971 		    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT,
1972 		    bx->bx_buffer, &len);
1973 
1974 		if (err == USBD_NORMAL_COMPLETION) {
1975 			uvideo_stream_recv_process(vs, bx->bx_buffer, len);
1976 		} else {
1977 			DPRINTF(("uvideo_stream_recv_bulk_transfer: %s\n",
1978 				 usbd_errstr(err)));
1979 		}
1980 	}
1981 
1982 	DPRINTF(("uvideo_stream_recv_bulk_transfer: notify complete\n"));
1983 
1984 	mutex_enter(&bx->bx_lock);
1985 	cv_broadcast(&bx->bx_cv);
1986 	mutex_exit(&bx->bx_lock);
1987 
1988 	DPRINTF(("uvideo_stream_recv_bulk_transfer: return\n"));
1989 
1990 	kthread_exit(0);
1991 }
1992 
1993 /*
1994  * uvideo_open - probe and commit video format and start receiving
1995  * video data
1996  */
1997 static int
uvideo_open(void * addr,int flags)1998 uvideo_open(void *addr, int flags)
1999 {
2000 	struct uvideo_stream *vs = addr;
2001 	struct uvideo_softc *sc = vs->vs_parent;
2002 	struct video_format fmt;
2003 
2004 	DPRINTF(("uvideo_open: sc=%p\n", sc));
2005 	if (sc->sc_dying)
2006 		return EIO;
2007 
2008 	/* XXX select default format */
2009 	if (vs->vs_default_format == NULL)
2010 		return EINVAL;
2011 	fmt = *vs->vs_default_format;
2012 
2013 	return uvideo_set_format(addr, &fmt);
2014 }
2015 
2016 
2017 static void
uvideo_close(void * addr)2018 uvideo_close(void *addr)
2019 {
2020 	struct uvideo_stream *vs = addr;
2021 
2022 	uvideo_stop_transfer(addr);
2023 
2024 	if (vs->vs_state != UVIDEO_STATE_CLOSED) {
2025 		vs->vs_state = UVIDEO_STATE_CLOSED;
2026 	}
2027 }
2028 
2029 static const char *
uvideo_get_devname(void * addr)2030 uvideo_get_devname(void *addr)
2031 {
2032 	struct uvideo_stream *vs = addr;
2033 
2034 	return vs->vs_parent->sc_devname;
2035 }
2036 
2037 static const char *
uvideo_get_businfo(void * addr)2038 uvideo_get_businfo(void *addr)
2039 {
2040 	struct uvideo_stream *vs = addr;
2041 
2042 	return vs->vs_parent->sc_businfo;
2043 }
2044 
2045 static int
uvideo_enum_format(void * addr,uint32_t index,struct video_format * format)2046 uvideo_enum_format(void *addr, uint32_t index, struct video_format *format)
2047 {
2048 	struct uvideo_stream *vs = addr;
2049 	struct uvideo_softc *sc = vs->vs_parent;
2050 	struct uvideo_format *video_format;
2051 	int off;
2052 
2053 	if (sc->sc_dying)
2054 		return EIO;
2055 
2056 	off = 0;
2057 	SIMPLEQ_FOREACH(video_format, &vs->vs_formats, entries) {
2058 		if (off++ != index)
2059 			continue;
2060 		format->pixel_format = video_format->format.pixel_format;
2061 		format->width = video_format->format.width;
2062 		format->height = video_format->format.height;
2063 		return 0;
2064 	}
2065 
2066 	return EINVAL;
2067 }
2068 
2069 /*
2070  * uvideo_get_format
2071  */
2072 static int
uvideo_get_format(void * addr,struct video_format * format)2073 uvideo_get_format(void *addr, struct video_format *format)
2074 {
2075 	struct uvideo_stream *vs = addr;
2076 	struct uvideo_softc *sc = vs->vs_parent;
2077 
2078 	if (sc->sc_dying)
2079 		return EIO;
2080 
2081 	*format = vs->vs_current_format;
2082 
2083 	return 0;
2084 }
2085 
2086 /*
2087  * uvideo_set_format - TODO: this is broken and does nothing
2088  */
2089 static int
uvideo_set_format(void * addr,struct video_format * format)2090 uvideo_set_format(void *addr, struct video_format *format)
2091 {
2092 	struct uvideo_stream *vs = addr;
2093 	struct uvideo_softc *sc = vs->vs_parent;
2094 	struct uvideo_format *uvfmt;
2095 	uvideo_probe_and_commit_data_t probe, maxprobe;
2096 	usbd_status err;
2097 
2098 	DPRINTF(("uvideo_set_format: sc=%p\n", sc));
2099 	if (sc->sc_dying)
2100 		return EIO;
2101 
2102 	uvfmt =	uvideo_stream_guess_format(vs, format->pixel_format,
2103 					   format->width, format->height);
2104 	if (uvfmt == NULL) {
2105 		DPRINTF(("uvideo: uvideo_stream_guess_format couldn't find "
2106 			 "%dx%d format %d\n", format->width, format->height,
2107 			 format->pixel_format));
2108 		return EINVAL;
2109 	}
2110 
2111 	uvideo_init_probe_data(&probe);
2112 	probe.bFormatIndex = UVIDEO_FORMAT_GET_FORMAT_INDEX(uvfmt);
2113 	probe.bFrameIndex = UVIDEO_FORMAT_GET_FRAME_INDEX(uvfmt);
2114 	USETDW(probe.dwFrameInterval, vs->vs_frame_interval);	/* XXX */
2115 
2116 	maxprobe = probe;
2117 	err = uvideo_stream_probe(vs, UR_GET_MAX, &maxprobe);
2118 	if (err) {
2119 		DPRINTF(("uvideo: error probe/GET_MAX: %s (%d)\n",
2120 			 usbd_errstr(err), err));
2121 	} else {
2122 		USETW(probe.wCompQuality, UGETW(maxprobe.wCompQuality));
2123 	}
2124 
2125 	err = uvideo_stream_probe(vs, UR_SET_CUR, &probe);
2126 	if (err) {
2127 		DPRINTF(("uvideo: error commit/SET_CUR: %s (%d)\n",
2128 			 usbd_errstr(err), err));
2129 		return EIO;
2130 	}
2131 
2132 	uvideo_init_probe_data(&probe);
2133 	err = uvideo_stream_probe(vs, UR_GET_CUR, &probe);
2134 	if (err) {
2135 		DPRINTF(("uvideo: error commit/SET_CUR: %s (%d)\n",
2136 			 usbd_errstr(err), err));
2137 		return EIO;
2138 	}
2139 
2140 	if (probe.bFormatIndex != UVIDEO_FORMAT_GET_FORMAT_INDEX(uvfmt)) {
2141 		DPRINTF(("uvideo: probe/GET_CUR returned format index %d "
2142 			 "(expected %d)\n", probe.bFormatIndex,
2143 			 UVIDEO_FORMAT_GET_FORMAT_INDEX(uvfmt)));
2144 		probe.bFormatIndex = UVIDEO_FORMAT_GET_FORMAT_INDEX(uvfmt);
2145 	}
2146 	if (probe.bFrameIndex != UVIDEO_FORMAT_GET_FRAME_INDEX(uvfmt)) {
2147 		DPRINTF(("uvideo: probe/GET_CUR returned frame index %d "
2148 			 "(expected %d)\n", probe.bFrameIndex,
2149 			 UVIDEO_FORMAT_GET_FRAME_INDEX(uvfmt)));
2150 		probe.bFrameIndex = UVIDEO_FORMAT_GET_FRAME_INDEX(uvfmt);
2151 	}
2152 	USETDW(probe.dwFrameInterval, vs->vs_frame_interval);	/* XXX */
2153 
2154 	/*
2155 	 * commit/SET_CUR. Fourth step is to set the alternate
2156 	 * interface.  Currently the fourth step is in
2157 	 * uvideo_start_transfer.  Maybe move it here?
2158 	 */
2159 	err = uvideo_stream_commit(vs, UR_SET_CUR, &probe);
2160 	if (err) {
2161 		DPRINTF(("uvideo: error commit/SET_CUR: %s (%d)\n",
2162 			 usbd_errstr(err), err));
2163 		return EIO;
2164 	}
2165 
2166 	DPRINTFN(15, ("uvideo_set_format: committing to format: "
2167 		      "bmHint=0x%04x bFormatIndex=%d bFrameIndex=%d "
2168 		      "dwFrameInterval=%u wKeyFrameRate=%d wPFrameRate=%d "
2169 		      "wCompQuality=%d wCompWindowSize=%d wDelay=%d "
2170 		      "dwMaxVideoFrameSize=%u dwMaxPayloadTransferSize=%u",
2171 		      UGETW(probe.bmHint),
2172 		      probe.bFormatIndex,
2173 		      probe.bFrameIndex,
2174 		      UGETDW(probe.dwFrameInterval),
2175 		      UGETW(probe.wKeyFrameRate),
2176 		      UGETW(probe.wPFrameRate),
2177 		      UGETW(probe.wCompQuality),
2178 		      UGETW(probe.wCompWindowSize),
2179 		      UGETW(probe.wDelay),
2180 		      UGETDW(probe.dwMaxVideoFrameSize),
2181 		      UGETDW(probe.dwMaxPayloadTransferSize)));
2182 	if (vs->vs_probelen == 34) {
2183 		DPRINTFN(15, (" dwClockFrequency=%u bmFramingInfo=0x%02x "
2184 			      "bPreferedVersion=%d bMinVersion=%d "
2185 			      "bMaxVersion=%d",
2186 			      UGETDW(probe.dwClockFrequency),
2187 			      probe.bmFramingInfo,
2188 			      probe.bPreferedVersion,
2189 			      probe.bMinVersion,
2190 			      probe.bMaxVersion));
2191 	}
2192 	DPRINTFN(15, ("\n"));
2193 
2194 	vs->vs_frame_interval = UGETDW(probe.dwFrameInterval);
2195 	vs->vs_max_payload_size = UGETDW(probe.dwMaxPayloadTransferSize);
2196 
2197 	*format = uvfmt->format;
2198 	vs->vs_current_format = *format;
2199 	DPRINTF(("uvideo_set_format: pixeltype is %d\n", format->pixel_format));
2200 
2201 	return 0;
2202 }
2203 
2204 static int
uvideo_try_format(void * addr,struct video_format * format)2205 uvideo_try_format(void *addr, struct video_format *format)
2206 {
2207 	struct uvideo_stream *vs = addr;
2208 	struct uvideo_format *uvfmt;
2209 
2210 	uvfmt =	uvideo_stream_guess_format(vs, format->pixel_format,
2211 					   format->width, format->height);
2212 	if (uvfmt == NULL)
2213 		return EINVAL;
2214 
2215 	*format = uvfmt->format;
2216 	return 0;
2217 }
2218 
2219 static int
uvideo_get_framerate(void * addr,struct video_fract * fract)2220 uvideo_get_framerate(void *addr, struct video_fract *fract)
2221 {
2222 	struct uvideo_stream *vs = addr;
2223 
2224 	switch (vs->vs_frame_interval) {
2225 	case 41666:	/* 240 */
2226 	case 83333:	/* 120 */
2227 	case 166666:	/* 60 */
2228 	case 200000:	/* 50 */
2229 	case 333333:	/* 30 */
2230 	case 400000:	/* 25 */
2231 	case 500000:	/* 20 */
2232 	case 666666:	/* 15 */
2233 	case 1000000:	/* 10 */
2234 		fract->numerator = 1;
2235 		fract->denominator = 10000000 / vs->vs_frame_interval;
2236 		break;
2237 	case 166833:	/* 59.94 */
2238 		fract->numerator = 60;
2239 		fract->denominator = 1001;
2240 		break;
2241 	case 333667:	/* 29.97 */
2242 		fract->numerator = 30;
2243 		fract->denominator = 1001;
2244 		break;
2245 	default:
2246 		fract->numerator = vs->vs_frame_interval;
2247 		fract->denominator = 10000000;
2248 		break;
2249 	}
2250 
2251 	return 0;
2252 }
2253 
2254 static int
uvideo_set_framerate(void * addr,struct video_fract * fract)2255 uvideo_set_framerate(void *addr, struct video_fract *fract)
2256 {
2257 	/* XXX setting framerate is not supported yet, return actual rate */
2258 	return uvideo_get_framerate(addr, fract);
2259 }
2260 
2261 static int
uvideo_start_transfer(void * addr)2262 uvideo_start_transfer(void *addr)
2263 {
2264 	struct uvideo_stream *vs = addr;
2265 	int s, err;
2266 
2267 	s = splusb();
2268 	err = uvideo_stream_start_xfer(vs);
2269 	splx(s);
2270 
2271 	return err;
2272 }
2273 
2274 static int
uvideo_stop_transfer(void * addr)2275 uvideo_stop_transfer(void *addr)
2276 {
2277 	struct uvideo_stream *vs = addr;
2278 	int err, s;
2279 
2280 	s = splusb();
2281 	err = uvideo_stream_stop_xfer(vs);
2282 	splx(s);
2283 
2284 	return err;
2285 }
2286 
2287 
2288 static int
uvideo_get_control_group(void * addr,struct video_control_group * group)2289 uvideo_get_control_group(void *addr, struct video_control_group *group)
2290 {
2291 	struct uvideo_stream *vs = addr;
2292 	struct uvideo_softc *sc = vs->vs_parent;
2293 	usb_device_request_t req;
2294 	usbd_status err;
2295 	uint8_t control_id, ent_id, data[16];
2296 	uint16_t len;
2297 	int s;
2298 
2299 	/* request setup */
2300 	switch (group->group_id) {
2301 	case VIDEO_CONTROL_PANTILT_RELATIVE:
2302 		if (group->length != 4)
2303 			return EINVAL;
2304 
2305 		return EINVAL;
2306 	case VIDEO_CONTROL_SHARPNESS:
2307 		if (group->length != 1)
2308 			return EINVAL;
2309 
2310 		control_id = UVIDEO_PU_SHARPNESS_CONTROL;
2311 		ent_id = 2; /* TODO: hardcoded logitech processing unit */
2312 		len = 2;
2313 		break;
2314 	default:
2315 		return EINVAL;
2316 	}
2317 
2318 	/* do request */
2319 	req.bmRequestType = UVIDEO_REQUEST_TYPE_INTERFACE |
2320 	    UVIDEO_REQUEST_TYPE_CLASS_SPECIFIC |
2321 	    UVIDEO_REQUEST_TYPE_GET;
2322 	req.bRequest = UR_GET_CUR;
2323 	USETW(req.wValue, control_id << 8);
2324 	USETW(req.wIndex, (ent_id << 8) | sc->sc_ifaceno);
2325 	USETW(req.wLength, len);
2326 
2327 	s = splusb();
2328 	err = usbd_do_request(sc->sc_udev, &req, data);
2329 	splx(s);
2330 	if (err != USBD_NORMAL_COMPLETION) {
2331 		DPRINTF(("uvideo_set_control: error %s (%d)\n",
2332 			 usbd_errstr(err), err));
2333 		return EIO;	/* TODO: more detail here? */
2334 	}
2335 
2336 	/* extract request data */
2337 	switch (group->group_id) {
2338 	case VIDEO_CONTROL_SHARPNESS:
2339 		group->control[0].value = UGETW(data);
2340 		break;
2341 	default:
2342 		return EINVAL;
2343 	}
2344 
2345 	return 0;
2346 }
2347 
2348 
2349 static int
uvideo_set_control_group(void * addr,const struct video_control_group * group)2350 uvideo_set_control_group(void *addr, const struct video_control_group *group)
2351 {
2352 	struct uvideo_stream *vs = addr;
2353 	struct uvideo_softc *sc = vs->vs_parent;
2354 	usb_device_request_t req;
2355 	usbd_status err;
2356 	uint8_t control_id, ent_id, data[16]; /* long enough for all controls */
2357 	uint16_t len;
2358 	int s;
2359 
2360 	switch (group->group_id) {
2361 	case VIDEO_CONTROL_PANTILT_RELATIVE:
2362 		if (group->length != 4)
2363 			return EINVAL;
2364 
2365 		if (group->control[0].value != 0 ||
2366 		    group->control[0].value != 1 ||
2367 		    group->control[0].value != 0xff)
2368 			return ERANGE;
2369 
2370 		if (group->control[2].value != 0 ||
2371 		    group->control[2].value != 1 ||
2372 		    group->control[2].value != 0xff)
2373 			return ERANGE;
2374 
2375 		control_id = UVIDEO_CT_PANTILT_RELATIVE_CONTROL;
2376 		ent_id = 1;	/* TODO: hardcoded logitech camera terminal  */
2377 		len = 4;
2378 		data[0] = group->control[0].value;
2379 		data[1] = group->control[1].value;
2380 		data[2] = group->control[2].value;
2381 		data[3] = group->control[3].value;
2382 		break;
2383 	case VIDEO_CONTROL_BRIGHTNESS:
2384 		if (group->length != 1)
2385 			return EINVAL;
2386 		control_id = UVIDEO_PU_BRIGHTNESS_CONTROL;
2387 		ent_id = 2;
2388 		len = 2;
2389 		USETW(data, group->control[0].value);
2390 		break;
2391 	case VIDEO_CONTROL_GAIN:
2392 		if (group->length != 1)
2393 			return EINVAL;
2394 		control_id = UVIDEO_PU_GAIN_CONTROL;
2395 		ent_id = 2;
2396 		len = 2;
2397 		USETW(data, group->control[0].value);
2398 		break;
2399 	case VIDEO_CONTROL_SHARPNESS:
2400 		if (group->length != 1)
2401 			return EINVAL;
2402 		control_id = UVIDEO_PU_SHARPNESS_CONTROL;
2403 		ent_id = 2; /* TODO: hardcoded logitech processing unit */
2404 		len = 2;
2405 		USETW(data, group->control[0].value);
2406 		break;
2407 	default:
2408 		return EINVAL;
2409 	}
2410 
2411 	req.bmRequestType = UVIDEO_REQUEST_TYPE_INTERFACE |
2412 	    UVIDEO_REQUEST_TYPE_CLASS_SPECIFIC |
2413 	    UVIDEO_REQUEST_TYPE_SET;
2414 	req.bRequest = UR_SET_CUR;
2415 	USETW(req.wValue, control_id << 8);
2416 	USETW(req.wIndex, (ent_id << 8) | sc->sc_ifaceno);
2417 	USETW(req.wLength, len);
2418 
2419 	s = splusb();
2420 	err = usbd_do_request(sc->sc_udev, &req, data);
2421 	splx(s);
2422 	if (err != USBD_NORMAL_COMPLETION) {
2423 		DPRINTF(("uvideo_set_control: error %s (%d)\n",
2424 			 usbd_errstr(err), err));
2425 		return EIO;	/* TODO: more detail here? */
2426 	}
2427 
2428 	return 0;
2429 }
2430 
2431 static usbd_status
uvideo_stream_probe_and_commit(struct uvideo_stream * vs,uint8_t action,uint8_t control,void * data)2432 uvideo_stream_probe_and_commit(struct uvideo_stream *vs,
2433 			       uint8_t action, uint8_t control,
2434 			       void *data)
2435 {
2436 	usb_device_request_t req;
2437 
2438 	switch (action) {
2439 	case UR_SET_CUR:
2440 		req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
2441 		USETW(req.wLength, vs->vs_probelen);
2442 		break;
2443 	case UR_GET_CUR:
2444 	case UR_GET_MIN:
2445 	case UR_GET_MAX:
2446 	case UR_GET_DEF:
2447 		req.bmRequestType = UT_READ_CLASS_INTERFACE;
2448 		USETW(req.wLength, vs->vs_probelen);
2449 		break;
2450 	case UR_GET_INFO:
2451 		req.bmRequestType = UT_READ_CLASS_INTERFACE;
2452 		USETW(req.wLength, sizeof(uByte));
2453 		break;
2454 	case UR_GET_LEN:
2455 		req.bmRequestType = UT_READ_CLASS_INTERFACE;
2456 		USETW(req.wLength, sizeof(uWord)); /* is this right? */
2457 		break;
2458 	default:
2459 		DPRINTF(("uvideo_probe_and_commit: "
2460 			 "unknown request action %d\n", action));
2461 		return USBD_NOT_STARTED;
2462 	}
2463 
2464 	req.bRequest = action;
2465 	USETW2(req.wValue, control, 0);
2466 	USETW2(req.wIndex, 0, vs->vs_ifaceno);
2467 
2468 	return (usbd_do_request_flags(vs->vs_parent->sc_udev, &req, data,
2469 				      0, 0,
2470 				      USBD_DEFAULT_TIMEOUT));
2471 }
2472 
2473 static void
uvideo_init_probe_data(uvideo_probe_and_commit_data_t * probe)2474 uvideo_init_probe_data(uvideo_probe_and_commit_data_t *probe)
2475 {
2476 	/* all zeroes tells camera to choose what it wants */
2477 	memset(probe, 0, sizeof(*probe));
2478 }
2479 
2480 
2481 #ifdef _MODULE
2482 
2483 MODULE(MODULE_CLASS_DRIVER, uvideo, NULL);
2484 static const struct cfiattrdata videobuscf_iattrdata = {
2485         "videobus", 0, {
2486 		{ NULL, NULL, 0 },
2487 	}
2488 };
2489 static const struct cfiattrdata * const uvideo_attrs[] = {
2490 	&videobuscf_iattrdata, NULL
2491 };
2492 CFDRIVER_DECL(uvideo, DV_DULL, uvideo_attrs);
2493 extern struct cfattach uvideo_ca;
2494 extern struct cfattach uvideo_ca;
2495 static int uvideoloc[6] = { -1, -1, -1, -1, -1, -1 };
2496 static struct cfparent uhubparent = {
2497         "usbifif", NULL, DVUNIT_ANY
2498 };
2499 static struct cfdata uvideo_cfdata[] = {
2500 	{
2501 		.cf_name = "uvideo",
2502 		.cf_atname = "uvideo",
2503 		.cf_unit = 0,
2504 		.cf_fstate = FSTATE_STAR,
2505 		.cf_loc = uvideoloc,
2506 		.cf_flags = 0,
2507 		.cf_pspec = &uhubparent,
2508 	},
2509 	{ NULL, NULL, 0, 0, NULL, 0, NULL },
2510 };
2511 
2512 static int
uvideo_modcmd(modcmd_t cmd,void * arg)2513 uvideo_modcmd(modcmd_t cmd, void *arg)
2514 {
2515 	int err;
2516 
2517 
2518 	switch (cmd) {
2519 	case MODULE_CMD_INIT:
2520 		DPRINTF(("uvideo: attempting to load\n"));
2521 
2522 		err = config_cfdriver_attach(&uvideo_cd);
2523 		if (err)
2524 			return err;
2525 		err = config_cfattach_attach("uvideo", &uvideo_ca);
2526 		if (err) {
2527 			config_cfdriver_detach(&uvideo_cd);
2528 			return err;
2529 		}
2530 		err = config_cfdata_attach(uvideo_cfdata, 1);
2531 		if (err) {
2532 			config_cfattach_detach("uvideo", &uvideo_ca);
2533 			config_cfdriver_detach(&uvideo_cd);
2534 			return err;
2535 		}
2536 		DPRINTF(("uvideo: loaded module\n"));
2537 		return 0;
2538 	case MODULE_CMD_FINI:
2539 		DPRINTF(("uvideo: attempting to unload module\n"));
2540 		err = config_cfdata_detach(uvideo_cfdata);
2541 		if (err)
2542 			return err;
2543 		config_cfattach_detach("uvideo", &uvideo_ca);
2544 		config_cfdriver_detach(&uvideo_cd);
2545 		DPRINTF(("uvideo: module unload\n"));
2546 		return 0;
2547 	default:
2548 		return ENOTTY;
2549 	}
2550 }
2551 
2552 #endif	/* _MODULE */
2553 
2554 
2555 #ifdef UVIDEO_DEBUG
2556 /*
2557  * Some functions to print out descriptors.  Mostly useless other than
2558  * debugging/exploration purposes.
2559  */
2560 
2561 
2562 static void
print_bitmap(const uByte * start,uByte nbytes)2563 print_bitmap(const uByte *start, uByte nbytes)
2564 {
2565 	int byte, bit;
2566 
2567 	/* most significant first */
2568 	for (byte = nbytes-1; byte >= 0; --byte) {
2569 		if (byte < nbytes-1) printf("-");
2570 		for (bit = 7; bit >= 0; --bit)
2571 			printf("%01d", (start[byte] >> bit) &1);
2572 	}
2573 }
2574 
2575 static void
print_descriptor(const usb_descriptor_t * desc)2576 print_descriptor(const usb_descriptor_t *desc)
2577 {
2578 	static int current_class = -1;
2579 	static int current_subclass = -1;
2580 
2581 	if (desc->bDescriptorType == UDESC_INTERFACE) {
2582 		const usb_interface_descriptor_t *id;
2583 
2584 		if (desc->bLength < sizeof(*id)) {
2585 			printf("[truncated interface]\n");
2586 			return;
2587 		}
2588 		id = (const usb_interface_descriptor_t *)desc;
2589 		current_class = id->bInterfaceClass;
2590 		current_subclass = id->bInterfaceSubClass;
2591 		print_interface_descriptor(id);
2592 		printf("\n");
2593 		return;
2594 	}
2595 
2596 	printf("  ");		/* indent */
2597 
2598 	if (current_class == UICLASS_VIDEO) {
2599 		switch (current_subclass) {
2600 		case UISUBCLASS_VIDEOCONTROL:
2601 			print_vc_descriptor(desc);
2602 			break;
2603 		case UISUBCLASS_VIDEOSTREAMING:
2604 			print_vs_descriptor(desc);
2605 			break;
2606 		case UISUBCLASS_VIDEOCOLLECTION:
2607 			printf("uvc collection: len=%d type=0x%02x",
2608 			    desc->bLength, desc->bDescriptorType);
2609 			break;
2610 		}
2611 	} else {
2612 		printf("non uvc descriptor len=%d type=0x%02x",
2613 		    desc->bLength, desc->bDescriptorType);
2614 	}
2615 
2616 	printf("\n");
2617 }
2618 
2619 static void
print_vc_descriptor(const usb_descriptor_t * desc)2620 print_vc_descriptor(const usb_descriptor_t *desc)
2621 {
2622 	const uvideo_descriptor_t *vcdesc;
2623 
2624 	printf("VC ");
2625 
2626 	switch (desc->bDescriptorType) {
2627 	case UDESC_ENDPOINT:
2628 		if (desc->bLength < sizeof(usb_endpoint_descriptor_t)) {
2629 			printf("[truncated endpoint]");
2630 			break;
2631 		}
2632 		print_endpoint_descriptor(
2633 			(const usb_endpoint_descriptor_t *)desc);
2634 		break;
2635 	case UDESC_CS_INTERFACE:
2636 		if (desc->bLength < sizeof(*vcdesc)) {
2637 			printf("[truncated class-specific]");
2638 			break;
2639 		}
2640 		vcdesc = (const uvideo_descriptor_t *)desc;
2641 		switch (vcdesc->bDescriptorSubtype) {
2642 		case UDESC_VC_HEADER:
2643 			if (desc->bLength <
2644 			    sizeof(uvideo_vc_header_descriptor_t)) {
2645 				printf("[truncated videocontrol header]");
2646 				break;
2647 			}
2648 			print_vc_header_descriptor(
2649 			  (const uvideo_vc_header_descriptor_t *)
2650 				vcdesc);
2651 			break;
2652 		case UDESC_INPUT_TERMINAL:
2653 			if (desc->bLength <
2654 			    sizeof(uvideo_input_terminal_descriptor_t)) {
2655 				printf("[truncated input terminal]");
2656 				break;
2657 			}
2658 			switch (UGETW(
2659 			   ((const uvideo_input_terminal_descriptor_t *)
2660 				    vcdesc)->wTerminalType)) {
2661 			case UVIDEO_ITT_CAMERA:
2662 				if (desc->bLength <
2663 				    sizeof(uvideo_camera_terminal_descriptor_t)) {
2664 					printf("[truncated camera terminal]");
2665 					break;
2666 				}
2667 				print_camera_terminal_descriptor(
2668 			  (const uvideo_camera_terminal_descriptor_t *)vcdesc);
2669 				break;
2670 			default:
2671 				print_input_terminal_descriptor(
2672 			  (const uvideo_input_terminal_descriptor_t *)vcdesc);
2673 				break;
2674 			}
2675 			break;
2676 		case UDESC_OUTPUT_TERMINAL:
2677 			if (desc->bLength <
2678 			    sizeof(uvideo_output_terminal_descriptor_t)) {
2679 				printf("[truncated output terminal]");
2680 				break;
2681 			}
2682 			print_output_terminal_descriptor(
2683 				(const uvideo_output_terminal_descriptor_t *)
2684 				vcdesc);
2685 			break;
2686 		case UDESC_SELECTOR_UNIT:
2687 			if (desc->bLength <
2688 			    sizeof(uvideo_selector_unit_descriptor_t)) {
2689 				printf("[truncated selector unit]");
2690 				break;
2691 			}
2692 			print_selector_unit_descriptor(
2693 				(const uvideo_selector_unit_descriptor_t *)
2694 				vcdesc);
2695 			break;
2696 		case UDESC_PROCESSING_UNIT:
2697 			if (desc->bLength <
2698 			    sizeof(uvideo_processing_unit_descriptor_t)) {
2699 				printf("[truncated processing unit]");
2700 				break;
2701 			}
2702 			print_processing_unit_descriptor(
2703 				(const uvideo_processing_unit_descriptor_t *)
2704 				vcdesc);
2705 			break;
2706 		case UDESC_EXTENSION_UNIT:
2707 			if (desc->bLength <
2708 			    sizeof(uvideo_extension_unit_descriptor_t)) {
2709 				printf("[truncated extension unit]");
2710 				break;
2711 			}
2712 			print_extension_unit_descriptor(
2713 				(const uvideo_extension_unit_descriptor_t *)
2714 				vcdesc);
2715 			break;
2716 		default:
2717 			printf("class specific interface "
2718 			    "len=%d type=0x%02x subtype=0x%02x",
2719 			    vcdesc->bLength,
2720 			    vcdesc->bDescriptorType,
2721 			    vcdesc->bDescriptorSubtype);
2722 			break;
2723 		}
2724 		break;
2725 	case UDESC_CS_ENDPOINT:
2726 		if (desc->bLength < sizeof(*vcdesc)) {
2727 			printf("[truncated class-specific]");
2728 			break;
2729 		}
2730 		vcdesc = (const uvideo_descriptor_t *)desc;
2731 		switch (vcdesc->bDescriptorSubtype) {
2732 		case UDESC_VC_INTERRUPT_ENDPOINT:
2733 			if (desc->bLength <
2734 			    sizeof(uvideo_vc_interrupt_endpoint_descriptor_t)) {
2735 				printf("[truncated "
2736 				    "videocontrol interrupt endpoint]");
2737 				break;
2738 			}
2739 			print_interrupt_endpoint_descriptor(
2740 			    (const uvideo_vc_interrupt_endpoint_descriptor_t *)
2741 				vcdesc);
2742 			break;
2743 		default:
2744 			printf("class specific endpoint "
2745 			    "len=%d type=0x%02x subtype=0x%02x",
2746 			    vcdesc->bLength,
2747 			    vcdesc->bDescriptorType,
2748 			    vcdesc->bDescriptorSubtype);
2749 			break;
2750 		}
2751 		break;
2752 	default:
2753 		printf("unknown: len=%d type=0x%02x",
2754 		    desc->bLength, desc->bDescriptorType);
2755 		break;
2756 	}
2757 }
2758 
2759 static void
print_vs_descriptor(const usb_descriptor_t * desc)2760 print_vs_descriptor(const usb_descriptor_t *desc)
2761 {
2762 	const uvideo_descriptor_t * vsdesc;
2763 	printf("VS ");
2764 
2765 	switch (desc->bDescriptorType) {
2766 	case UDESC_ENDPOINT:
2767 		if (desc->bLength < sizeof(usb_endpoint_descriptor_t)) {
2768 			printf("[truncated endpoint]");
2769 			break;
2770 		}
2771 		print_endpoint_descriptor(
2772 			(const usb_endpoint_descriptor_t *)desc);
2773 		break;
2774 	case UDESC_CS_INTERFACE:
2775 		if (desc->bLength < sizeof(*vsdesc)) {
2776 			printf("[truncated class-specific]");
2777 			break;
2778 		}
2779 		vsdesc = (const uvideo_descriptor_t *)desc;
2780 		switch (vsdesc->bDescriptorSubtype) {
2781 		case UDESC_VS_INPUT_HEADER:
2782 			if (desc->bLength <
2783 			    sizeof(uvideo_vs_input_header_descriptor_t)) {
2784 				printf("[truncated videostream input header]");
2785 				break;
2786 			}
2787 			print_vs_input_header_descriptor(
2788 			 (const uvideo_vs_input_header_descriptor_t *)
2789 				vsdesc);
2790 			break;
2791 		case UDESC_VS_OUTPUT_HEADER:
2792 			if (desc->bLength <
2793 			    sizeof(uvideo_vs_output_header_descriptor_t)) {
2794 				printf("[truncated "
2795 				    "videostream output header]");
2796 				break;
2797 			}
2798 			print_vs_output_header_descriptor(
2799 			(const uvideo_vs_output_header_descriptor_t *)
2800 				vsdesc);
2801 			break;
2802 		case UDESC_VS_FORMAT_UNCOMPRESSED:
2803 			if (desc->bLength <
2804 			    sizeof(uvideo_vs_format_uncompressed_descriptor_t))
2805 			{
2806 				printf("[truncated "
2807 				    "videostream format uncompressed]");
2808 				break;
2809 			}
2810 			print_vs_format_uncompressed_descriptor(
2811 			   (const uvideo_vs_format_uncompressed_descriptor_t *)
2812 				vsdesc);
2813 			break;
2814 		case UDESC_VS_FRAME_UNCOMPRESSED:
2815 			if (desc->bLength <
2816 			    sizeof(uvideo_vs_frame_uncompressed_descriptor_t))
2817 			{
2818 				printf("[truncated "
2819 				    "videostream frame uncompressed]");
2820 				break;
2821 			}
2822 			print_vs_frame_uncompressed_descriptor(
2823 			    (const uvideo_vs_frame_uncompressed_descriptor_t *)
2824 				vsdesc);
2825 			break;
2826 		case UDESC_VS_FORMAT_MJPEG:
2827 			if (desc->bLength <
2828 			    sizeof(uvideo_vs_format_mjpeg_descriptor_t)) {
2829 				printf("[truncated videostream format mjpeg]");
2830 				break;
2831 			}
2832 			print_vs_format_mjpeg_descriptor(
2833 				(const uvideo_vs_format_mjpeg_descriptor_t *)
2834 				vsdesc);
2835 			break;
2836 		case UDESC_VS_FRAME_MJPEG:
2837 			if (desc->bLength <
2838 			    sizeof(uvideo_vs_frame_mjpeg_descriptor_t)) {
2839 				printf("[truncated videostream frame mjpeg]");
2840 				break;
2841 			}
2842 			print_vs_frame_mjpeg_descriptor(
2843 				(const uvideo_vs_frame_mjpeg_descriptor_t *)
2844 				vsdesc);
2845 			break;
2846 		case UDESC_VS_FORMAT_DV:
2847 			if (desc->bLength <
2848 			    sizeof(uvideo_vs_format_dv_descriptor_t)) {
2849 				printf("[truncated videostream format dv]");
2850 				break;
2851 			}
2852 			print_vs_format_dv_descriptor(
2853 				(const uvideo_vs_format_dv_descriptor_t *)
2854 				vsdesc);
2855 			break;
2856 		default:
2857 			printf("unknown cs interface: len=%d type=0x%02x "
2858 			    "subtype=0x%02x",
2859 			    vsdesc->bLength, vsdesc->bDescriptorType,
2860 			    vsdesc->bDescriptorSubtype);
2861 		}
2862 		break;
2863 	default:
2864 		printf("unknown: len=%d type=0x%02x",
2865 		    desc->bLength, desc->bDescriptorType);
2866 		break;
2867 	}
2868 }
2869 
2870 static void
print_interface_descriptor(const usb_interface_descriptor_t * id)2871 print_interface_descriptor(const usb_interface_descriptor_t *id)
2872 {
2873 	printf("Interface: Len=%d Type=0x%02x "
2874 	    "bInterfaceNumber=0x%02x "
2875 	    "bAlternateSetting=0x%02x bNumEndpoints=0x%02x "
2876 	    "bInterfaceClass=0x%02x bInterfaceSubClass=0x%02x "
2877 	    "bInterfaceProtocol=0x%02x iInterface=0x%02x",
2878 	    id->bLength,
2879 	    id->bDescriptorType,
2880 	    id->bInterfaceNumber,
2881 	    id->bAlternateSetting,
2882 	    id->bNumEndpoints,
2883 	    id->bInterfaceClass,
2884 	    id->bInterfaceSubClass,
2885 	    id->bInterfaceProtocol,
2886 	    id->iInterface);
2887 }
2888 
2889 static void
print_endpoint_descriptor(const usb_endpoint_descriptor_t * desc)2890 print_endpoint_descriptor(const usb_endpoint_descriptor_t *desc)
2891 {
2892 	printf("Endpoint: Len=%d Type=0x%02x "
2893 	    "bEndpointAddress=0x%02x ",
2894 	    desc->bLength,
2895 	    desc->bDescriptorType,
2896 	    desc->bEndpointAddress);
2897 	printf("bmAttributes=");
2898 	print_bitmap(&desc->bmAttributes, 1);
2899 	printf(" wMaxPacketSize=%d bInterval=%d",
2900 	    UGETW(desc->wMaxPacketSize),
2901 	    desc->bInterval);
2902 }
2903 
2904 static void
print_vc_header_descriptor(const uvideo_vc_header_descriptor_t * desc)2905 print_vc_header_descriptor(
2906 	const uvideo_vc_header_descriptor_t *desc)
2907 {
2908 	printf("Interface Header: "
2909 	    "Len=%d Type=0x%02x Subtype=0x%02x "
2910 	    "bcdUVC=%d wTotalLength=%d "
2911 	    "dwClockFrequency=%u bInCollection=%d",
2912 	    desc->bLength,
2913 	    desc->bDescriptorType,
2914 	    desc->bDescriptorSubtype,
2915 	    UGETW(desc->bcdUVC),
2916 	    UGETW(desc->wTotalLength),
2917 	    UGETDW(desc->dwClockFrequency),
2918 	    desc->bInCollection);
2919 }
2920 
2921 static void
print_input_terminal_descriptor(const uvideo_input_terminal_descriptor_t * desc)2922 print_input_terminal_descriptor(
2923 	const uvideo_input_terminal_descriptor_t *desc)
2924 {
2925 	printf("Input Terminal: "
2926 	    "Len=%d Type=0x%02x Subtype=0x%02x "
2927 	    "bTerminalID=%d wTerminalType=%x bAssocTerminal=%d "
2928 	    "iTerminal=%d",
2929 	    desc->bLength,
2930 	    desc->bDescriptorType,
2931 	    desc->bDescriptorSubtype,
2932 	    desc->bTerminalID,
2933 	    UGETW(desc->wTerminalType),
2934 	    desc->bAssocTerminal,
2935 	    desc->iTerminal);
2936 }
2937 
2938 static void
print_output_terminal_descriptor(const uvideo_output_terminal_descriptor_t * desc)2939 print_output_terminal_descriptor(
2940 	const uvideo_output_terminal_descriptor_t *desc)
2941 {
2942 	printf("Output Terminal: "
2943 	    "Len=%d Type=0x%02x Subtype=0x%02x "
2944 	    "bTerminalID=%d wTerminalType=%x bAssocTerminal=%d "
2945 	    "bSourceID=%d iTerminal=%d",
2946 	    desc->bLength,
2947 	    desc->bDescriptorType,
2948 	    desc->bDescriptorSubtype,
2949 	    desc->bTerminalID,
2950 	    UGETW(desc->wTerminalType),
2951 	    desc->bAssocTerminal,
2952 	    desc->bSourceID,
2953 	    desc->iTerminal);
2954 }
2955 
2956 static void
print_camera_terminal_descriptor(const uvideo_camera_terminal_descriptor_t * desc)2957 print_camera_terminal_descriptor(
2958 	const uvideo_camera_terminal_descriptor_t *desc)
2959 {
2960 	printf("Camera Terminal: "
2961 	    "Len=%d Type=0x%02x Subtype=0x%02x "
2962 	    "bTerminalID=%d wTerminalType=%x bAssocTerminal=%d "
2963 	    "iTerminal=%d "
2964 	    "wObjectiveFocalLengthMin/Max=%d/%d "
2965 	    "wOcularFocalLength=%d "
2966 	    "bControlSize=%d ",
2967 	    desc->bLength,
2968 	    desc->bDescriptorType,
2969 	    desc->bDescriptorSubtype,
2970 	    desc->bTerminalID,
2971 	    UGETW(desc->wTerminalType),
2972 	    desc->bAssocTerminal,
2973 	    desc->iTerminal,
2974 	    UGETW(desc->wObjectiveFocalLengthMin),
2975 	    UGETW(desc->wObjectiveFocalLengthMax),
2976 	    UGETW(desc->wOcularFocalLength),
2977 	    desc->bControlSize);
2978 	printf("bmControls=");
2979 	print_bitmap(desc->bmControls, desc->bControlSize);
2980 }
2981 
2982 static void
print_selector_unit_descriptor(const uvideo_selector_unit_descriptor_t * desc)2983 print_selector_unit_descriptor(
2984 	const uvideo_selector_unit_descriptor_t *desc)
2985 {
2986 	int i;
2987 	const uByte *b;
2988 	printf("Selector Unit: "
2989 	    "Len=%d Type=0x%02x Subtype=0x%02x "
2990 	    "bUnitID=%d bNrInPins=%d ",
2991 	    desc->bLength,
2992 	    desc->bDescriptorType,
2993 	    desc->bDescriptorSubtype,
2994 	    desc->bUnitID,
2995 	    desc->bNrInPins);
2996 	printf("baSourceIDs=");
2997 	b = &desc->baSourceID[0];
2998 	for (i = 0; i < desc->bNrInPins; ++i)
2999 		printf("%d ", *b++);
3000 	printf("iSelector=%d", *b);
3001 }
3002 
3003 static void
print_processing_unit_descriptor(const uvideo_processing_unit_descriptor_t * desc)3004 print_processing_unit_descriptor(
3005 	const uvideo_processing_unit_descriptor_t *desc)
3006 {
3007 	const uByte *b;
3008 
3009 	printf("Processing Unit: "
3010 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3011 	    "bUnitID=%d bSourceID=%d wMaxMultiplier=%d bControlSize=%d ",
3012 	    desc->bLength,
3013 	    desc->bDescriptorType,
3014 	    desc->bDescriptorSubtype,
3015 	    desc->bUnitID,
3016 	    desc->bSourceID,
3017 	    UGETW(desc->wMaxMultiplier),
3018 	    desc->bControlSize);
3019 	printf("bmControls=");
3020 	print_bitmap(desc->bmControls, desc->bControlSize);
3021 	b = &desc->bControlSize + desc->bControlSize + 1;
3022 	printf(" iProcessing=%d bmVideoStandards=", *b);
3023 	b += 1;
3024 	print_bitmap(b, 1);
3025 }
3026 
3027 static void
print_extension_unit_descriptor(const uvideo_extension_unit_descriptor_t * desc)3028 print_extension_unit_descriptor(
3029 	const uvideo_extension_unit_descriptor_t *desc)
3030 {
3031 	const uByte * byte;
3032 	uByte controlbytes;
3033 	int i;
3034 
3035 	printf("Extension Unit: "
3036 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3037 	    "bUnitID=%d ",
3038 	    desc->bLength,
3039 	    desc->bDescriptorType,
3040 	    desc->bDescriptorSubtype,
3041 	    desc->bUnitID);
3042 
3043 	printf("guidExtensionCode=");
3044 	usb_guid_print(&desc->guidExtensionCode);
3045 	printf(" ");
3046 
3047 	printf("bNumControls=%d bNrInPins=%d ",
3048 	    desc->bNumControls,
3049 	    desc->bNrInPins);
3050 
3051 	printf("baSourceIDs=");
3052 	byte = &desc->baSourceID[0];
3053 	for (i = 0; i < desc->bNrInPins; ++i)
3054 		printf("%d ", *byte++);
3055 
3056 	controlbytes = *byte++;
3057 	printf("bControlSize=%d ", controlbytes);
3058 	printf("bmControls=");
3059 	print_bitmap(byte, controlbytes);
3060 
3061 	byte += controlbytes;
3062 	printf(" iExtension=%d", *byte);
3063 }
3064 
3065 static void
print_interrupt_endpoint_descriptor(const uvideo_vc_interrupt_endpoint_descriptor_t * desc)3066 print_interrupt_endpoint_descriptor(
3067 	const uvideo_vc_interrupt_endpoint_descriptor_t *desc)
3068 {
3069 	printf("Interrupt Endpoint: "
3070 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3071 	    "wMaxTransferSize=%d ",
3072 	    desc->bLength,
3073 	    desc->bDescriptorType,
3074 	    desc->bDescriptorSubtype,
3075 	    UGETW(desc->wMaxTransferSize));
3076 }
3077 
3078 
3079 static void
print_vs_output_header_descriptor(const uvideo_vs_output_header_descriptor_t * desc)3080 print_vs_output_header_descriptor(
3081 	const uvideo_vs_output_header_descriptor_t *desc)
3082 {
3083 	printf("Interface Output Header: "
3084 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3085 	    "bNumFormats=%d wTotalLength=%d bEndpointAddress=%d "
3086 	    "bTerminalLink=%d bControlSize=%d",
3087 	    desc->bLength,
3088 	    desc->bDescriptorType,
3089 	    desc->bDescriptorSubtype,
3090 	    desc->bNumFormats,
3091 	    UGETW(desc->wTotalLength),
3092 	    desc->bEndpointAddress,
3093 	    desc->bTerminalLink,
3094 	    desc->bControlSize);
3095 }
3096 
3097 static void
print_vs_input_header_descriptor(const uvideo_vs_input_header_descriptor_t * desc)3098 print_vs_input_header_descriptor(
3099 	const uvideo_vs_input_header_descriptor_t *desc)
3100 {
3101 	printf("Interface Input Header: "
3102 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3103 	    "bNumFormats=%d wTotalLength=%d bEndpointAddress=%d "
3104 	    "bmInfo=%x bTerminalLink=%d bStillCaptureMethod=%d "
3105 	    "bTriggerSupport=%d bTriggerUsage=%d bControlSize=%d ",
3106 	    desc->bLength,
3107 	    desc->bDescriptorType,
3108 	    desc->bDescriptorSubtype,
3109 	    desc->bNumFormats,
3110 	    UGETW(desc->wTotalLength),
3111 	    desc->bEndpointAddress,
3112 	    desc->bmInfo,
3113 	    desc->bTerminalLink,
3114 	    desc->bStillCaptureMethod,
3115 	    desc->bTriggerSupport,
3116 	    desc->bTriggerUsage,
3117 	    desc->bControlSize);
3118 	print_bitmap(desc->bmaControls, desc->bControlSize);
3119 }
3120 
3121 static void
print_vs_format_uncompressed_descriptor(const uvideo_vs_format_uncompressed_descriptor_t * desc)3122 print_vs_format_uncompressed_descriptor(
3123 	const uvideo_vs_format_uncompressed_descriptor_t *desc)
3124 {
3125 	printf("Format Uncompressed: "
3126 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3127 	    "bFormatIndex=%d bNumFrameDescriptors=%d ",
3128 	    desc->bLength,
3129 	    desc->bDescriptorType,
3130 	    desc->bDescriptorSubtype,
3131 	    desc->bFormatIndex,
3132 	    desc->bNumFrameDescriptors);
3133 	usb_guid_print(&desc->guidFormat);
3134 	printf(" bBitsPerPixel=%d bDefaultFrameIndex=%d "
3135 	    "bAspectRatioX=%d bAspectRatioY=%d "
3136 	    "bmInterlaceFlags=0x%02x bCopyProtect=%d",
3137 	    desc->bBitsPerPixel,
3138 	    desc->bDefaultFrameIndex,
3139 	    desc->bAspectRatioX,
3140 	    desc->bAspectRatioY,
3141 	    desc->bmInterlaceFlags,
3142 	    desc->bCopyProtect);
3143 }
3144 
3145 static void
print_vs_frame_uncompressed_descriptor(const uvideo_vs_frame_uncompressed_descriptor_t * desc)3146 print_vs_frame_uncompressed_descriptor(
3147 	const uvideo_vs_frame_uncompressed_descriptor_t *desc)
3148 {
3149 	printf("Frame Uncompressed: "
3150 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3151 	    "bFrameIndex=%d bmCapabilities=0x%02x "
3152 	    "wWidth=%d wHeight=%d dwMinBitRate=%u dwMaxBitRate=%u "
3153 	    "dwMaxVideoFrameBufferSize=%u dwDefaultFrameInterval=%u "
3154 	    "bFrameIntervalType=%d",
3155 	    desc->bLength,
3156 	    desc->bDescriptorType,
3157 	    desc->bDescriptorSubtype,
3158 	    desc->bFrameIndex,
3159 	    desc->bmCapabilities,
3160 	    UGETW(desc->wWidth),
3161 	    UGETW(desc->wHeight),
3162 	    UGETDW(desc->dwMinBitRate),
3163 	    UGETDW(desc->dwMaxBitRate),
3164 	    UGETDW(desc->dwMaxVideoFrameBufferSize),
3165 	    UGETDW(desc->dwDefaultFrameInterval),
3166 	    desc->bFrameIntervalType);
3167 }
3168 
3169 static void
print_vs_format_mjpeg_descriptor(const uvideo_vs_format_mjpeg_descriptor_t * desc)3170 print_vs_format_mjpeg_descriptor(
3171 	const uvideo_vs_format_mjpeg_descriptor_t *desc)
3172 {
3173 	printf("MJPEG format: "
3174 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3175 	    "bFormatIndex=%d bNumFrameDescriptors=%d bmFlags=0x%02x "
3176 	    "bDefaultFrameIndex=%d bAspectRatioX=%d bAspectRatioY=%d "
3177 	    "bmInterlaceFlags=0x%02x bCopyProtect=%d",
3178 	    desc->bLength,
3179 	    desc->bDescriptorType,
3180 	    desc->bDescriptorSubtype,
3181 	    desc->bFormatIndex,
3182 	    desc->bNumFrameDescriptors,
3183 	    desc->bmFlags,
3184 	    desc->bDefaultFrameIndex,
3185 	    desc->bAspectRatioX,
3186 	    desc->bAspectRatioY,
3187 	    desc->bmInterlaceFlags,
3188 	    desc->bCopyProtect);
3189 }
3190 
3191 static void
print_vs_frame_mjpeg_descriptor(const uvideo_vs_frame_mjpeg_descriptor_t * desc)3192 print_vs_frame_mjpeg_descriptor(
3193 	const uvideo_vs_frame_mjpeg_descriptor_t *desc)
3194 {
3195 	printf("MJPEG frame: "
3196 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3197 	    "bFrameIndex=%d bmCapabilities=0x%02x "
3198 	    "wWidth=%d wHeight=%d dwMinBitRate=%u dwMaxBitRate=%u "
3199 	    "dwMaxVideoFrameBufferSize=%u dwDefaultFrameInterval=%u "
3200 	    "bFrameIntervalType=%d",
3201 	    desc->bLength,
3202 	    desc->bDescriptorType,
3203 	    desc->bDescriptorSubtype,
3204 	    desc->bFrameIndex,
3205 	    desc->bmCapabilities,
3206 	    UGETW(desc->wWidth),
3207 	    UGETW(desc->wHeight),
3208 	    UGETDW(desc->dwMinBitRate),
3209 	    UGETDW(desc->dwMaxBitRate),
3210 	    UGETDW(desc->dwMaxVideoFrameBufferSize),
3211 	    UGETDW(desc->dwDefaultFrameInterval),
3212 	    desc->bFrameIntervalType);
3213 }
3214 
3215 static void
print_vs_format_dv_descriptor(const uvideo_vs_format_dv_descriptor_t * desc)3216 print_vs_format_dv_descriptor(
3217 	const uvideo_vs_format_dv_descriptor_t *desc)
3218 {
3219 	printf("MJPEG format: "
3220 	    "Len=%d Type=0x%02x Subtype=0x%02x "
3221 	    "bFormatIndex=%d dwMaxVideoFrameBufferSize=%u "
3222 	    "bFormatType/Rate=%d bFormatType/Format=%d",
3223 	    desc->bLength,
3224 	    desc->bDescriptorType,
3225 	    desc->bDescriptorSubtype,
3226 	    desc->bFormatIndex,
3227 	    UGETDW(desc->dwMaxVideoFrameBufferSize),
3228 	    UVIDEO_GET_DV_FREQ(desc->bFormatType),
3229 	    UVIDEO_GET_DV_FORMAT(desc->bFormatType));
3230 }
3231 
3232 #endif /* !UVIDEO_DEBUG */
3233 
3234 #ifdef UVIDEO_DEBUG
3235 static void
usb_guid_print(const usb_guid_t * guid)3236 usb_guid_print(const usb_guid_t *guid)
3237 {
3238 	printf("%04X-%02X-%02X-",
3239 	       UGETDW(guid->data1),
3240 	       UGETW(guid->data2),
3241 	       UGETW(guid->data3));
3242 	printf("%02X%02X-",
3243 	       guid->data4[0],
3244 	       guid->data4[1]);
3245 	printf("%02X%02X%02X%02X%02X%02X",
3246 	       guid->data4[2],
3247 	       guid->data4[3],
3248 	       guid->data4[4],
3249 	       guid->data4[5],
3250 	       guid->data4[6],
3251 	       guid->data4[7]);
3252 }
3253 #endif /* !UVIDEO_DEBUG */
3254 
3255 /*
3256  * Returns less than zero, zero, or greater than zero if uguid is less
3257  * than, equal to, or greater than guid.
3258  */
3259 static int
usb_guid_cmp(const usb_guid_t * uguid,const guid_t * guid)3260 usb_guid_cmp(const usb_guid_t *uguid, const guid_t *guid)
3261 {
3262 	if (guid->data1 > UGETDW(uguid->data1))
3263 		return 1;
3264 	else if (guid->data1 < UGETDW(uguid->data1))
3265 		return -1;
3266 
3267 	if (guid->data2 > UGETW(uguid->data2))
3268 		return 1;
3269 	else if (guid->data2 < UGETW(uguid->data2))
3270 		return -1;
3271 
3272 	if (guid->data3 > UGETW(uguid->data3))
3273 		return 1;
3274 	else if (guid->data3 < UGETW(uguid->data3))
3275 		return -1;
3276 
3277 	return memcmp(guid->data4, uguid->data4, 8);
3278 }
3279