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