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