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