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