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