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