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