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