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