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