1 1.48 mlelstv /* $NetBSD: video.c,v 1.48 2025/07/05 11:44:23 mlelstv Exp $ */ 2 1.1 jmcneill 3 1.1 jmcneill /* 4 1.1 jmcneill * Copyright (c) 2008 Patrick Mahoney <pat (at) polycrystal.org> 5 1.1 jmcneill * All rights reserved. 6 1.1 jmcneill * 7 1.1 jmcneill * This code was written by Patrick Mahoney (pat (at) polycrystal.org) as 8 1.1 jmcneill * part of Google Summer of Code 2008. 9 1.1 jmcneill * 10 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 11 1.1 jmcneill * modification, are permitted provided that the following conditions 12 1.1 jmcneill * are met: 13 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 14 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 15 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 17 1.1 jmcneill * documentation and/or other materials provided with the distribution. 18 1.1 jmcneill * 19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jmcneill */ 31 1.1 jmcneill 32 1.1 jmcneill /* 33 1.1 jmcneill * This ia a Video4Linux 2 compatible /dev/video driver for NetBSD 34 1.1 jmcneill * 35 1.1 jmcneill * See http://v4l2spec.bytesex.org/ for Video4Linux 2 specifications 36 1.1 jmcneill */ 37 1.1 jmcneill 38 1.1 jmcneill #include <sys/cdefs.h> 39 1.48 mlelstv __KERNEL_RCSID(0, "$NetBSD: video.c,v 1.48 2025/07/05 11:44:23 mlelstv Exp $"); 40 1.1 jmcneill 41 1.1 jmcneill #include "video.h" 42 1.1 jmcneill #if NVIDEO > 0 43 1.1 jmcneill 44 1.1 jmcneill #include <sys/param.h> 45 1.1 jmcneill #include <sys/ioctl.h> 46 1.1 jmcneill #include <sys/fcntl.h> 47 1.1 jmcneill #include <sys/vnode.h> 48 1.1 jmcneill #include <sys/poll.h> 49 1.7 jmcneill #include <sys/select.h> 50 1.1 jmcneill #include <sys/kmem.h> 51 1.1 jmcneill #include <sys/pool.h> 52 1.1 jmcneill #include <sys/conf.h> 53 1.1 jmcneill #include <sys/types.h> 54 1.1 jmcneill #include <sys/device.h> 55 1.1 jmcneill #include <sys/condvar.h> 56 1.1 jmcneill #include <sys/queue.h> 57 1.1 jmcneill #include <sys/videoio.h> 58 1.1 jmcneill 59 1.1 jmcneill #include <dev/video_if.h> 60 1.1 jmcneill 61 1.34 riastrad #include "ioconf.h" 62 1.34 riastrad 63 1.1 jmcneill /* #define VIDEO_DEBUG 1 */ 64 1.1 jmcneill 65 1.1 jmcneill #ifdef VIDEO_DEBUG 66 1.1 jmcneill #define DPRINTF(x) do { if (videodebug) printf x; } while (0) 67 1.1 jmcneill #define DPRINTFN(n,x) do { if (videodebug>(n)) printf x; } while (0) 68 1.1 jmcneill int videodebug = VIDEO_DEBUG; 69 1.1 jmcneill #else 70 1.1 jmcneill #define DPRINTF(x) 71 1.1 jmcneill #define DPRINTFN(n,x) 72 1.1 jmcneill #endif 73 1.1 jmcneill 74 1.22 christos #define PAGE_ALIGN(a) (((a) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) 75 1.22 christos 76 1.25 jmcneill #define VIDEO_DRIVER_VERSION \ 77 1.25 jmcneill (((__NetBSD_Version__ / 100000000) << 16) | \ 78 1.25 jmcneill ((__NetBSD_Version__ / 1000000 % 100) << 8) | \ 79 1.25 jmcneill (__NetBSD_Version__ / 100 % 100)) 80 1.1 jmcneill 81 1.1 jmcneill /* TODO: move to sys/intr.h */ 82 1.1 jmcneill #define IPL_VIDEO IPL_VM 83 1.1 jmcneill #define splvideo() splvm() 84 1.1 jmcneill 85 1.1 jmcneill #define VIDEO_MIN_BUFS 2 86 1.6 jmcneill #define VIDEO_MAX_BUFS 32 87 1.1 jmcneill #define VIDEO_NUM_BUFS 4 88 1.1 jmcneill 89 1.1 jmcneill /* Scatter Buffer - an array of fixed size (PAGE_SIZE) chunks 90 1.1 jmcneill * allocated non-contiguously and functions to get data into and out 91 1.1 jmcneill * of the scatter buffer. */ 92 1.1 jmcneill struct scatter_buf { 93 1.1 jmcneill pool_cache_t sb_pool; 94 1.1 jmcneill size_t sb_size; /* size in bytes */ 95 1.1 jmcneill size_t sb_npages; /* number of pages */ 96 1.1 jmcneill uint8_t **sb_page_ary; /* array of page pointers */ 97 1.1 jmcneill }; 98 1.1 jmcneill 99 1.1 jmcneill struct scatter_io { 100 1.1 jmcneill struct scatter_buf *sio_buf; 101 1.1 jmcneill off_t sio_offset; 102 1.1 jmcneill size_t sio_resid; 103 1.1 jmcneill }; 104 1.1 jmcneill 105 1.48 mlelstv static void scatter_buf_init(struct scatter_buf *, const char *); 106 1.1 jmcneill static void scatter_buf_destroy(struct scatter_buf *); 107 1.1 jmcneill static int scatter_buf_set_size(struct scatter_buf *, size_t); 108 1.1 jmcneill static paddr_t scatter_buf_map(struct scatter_buf *, off_t); 109 1.1 jmcneill 110 1.1 jmcneill static bool scatter_io_init(struct scatter_buf *, off_t, size_t, struct scatter_io *); 111 1.1 jmcneill static bool scatter_io_next(struct scatter_io *, void **, size_t *); 112 1.1 jmcneill static void scatter_io_undo(struct scatter_io *, size_t); 113 1.1 jmcneill static void scatter_io_copyin(struct scatter_io *, const void *); 114 1.1 jmcneill /* static void scatter_io_copyout(struct scatter_io *, void *); */ 115 1.1 jmcneill static int scatter_io_uiomove(struct scatter_io *, struct uio *); 116 1.1 jmcneill 117 1.1 jmcneill 118 1.1 jmcneill enum video_stream_method { 119 1.1 jmcneill VIDEO_STREAM_METHOD_NONE, 120 1.1 jmcneill VIDEO_STREAM_METHOD_READ, 121 1.1 jmcneill VIDEO_STREAM_METHOD_MMAP, 122 1.1 jmcneill VIDEO_STREAM_METHOD_USERPTR 123 1.1 jmcneill }; 124 1.1 jmcneill 125 1.1 jmcneill struct video_buffer { 126 1.1 jmcneill struct v4l2_buffer *vb_buf; 127 1.1 jmcneill SIMPLEQ_ENTRY(video_buffer) entries; 128 1.46 mlelstv u_int busy; 129 1.1 jmcneill }; 130 1.1 jmcneill 131 1.1 jmcneill SIMPLEQ_HEAD(sample_queue, video_buffer); 132 1.1 jmcneill 133 1.1 jmcneill struct video_stream { 134 1.1 jmcneill int vs_flags; /* flags given to open() */ 135 1.1 jmcneill 136 1.1 jmcneill struct video_format vs_format; 137 1.1 jmcneill 138 1.1 jmcneill int vs_frameno; /* toggles between 0 and 1, 139 1.1 jmcneill * or -1 if new */ 140 1.43 andvar uint32_t vs_sequence; /* absolute frame/sample number in 141 1.1 jmcneill * sequence, wraps around */ 142 1.1 jmcneill bool vs_drop; /* drop payloads from current 143 1.1 jmcneill * frameno? */ 144 1.39 riastrad 145 1.1 jmcneill enum v4l2_buf_type vs_type; 146 1.1 jmcneill uint8_t vs_nbufs; 147 1.1 jmcneill struct video_buffer **vs_buf; 148 1.1 jmcneill 149 1.1 jmcneill struct scatter_buf vs_data; /* stores video data for MMAP 150 1.1 jmcneill * and READ */ 151 1.1 jmcneill 152 1.1 jmcneill /* Video samples may exist in different locations. Initially, 153 1.1 jmcneill * samples are queued into the ingress queue. The driver 154 1.1 jmcneill * grabs these in turn and fills them with video data. Once 155 1.1 jmcneill * filled, they are moved to the egress queue. Samples are 156 1.1 jmcneill * dequeued either by user with MMAP method or, with READ 157 1.42 andvar * method, videoread() works from the first sample in the 158 1.1 jmcneill * ingress queue without dequeing. In the first case, the 159 1.1 jmcneill * user re-queues the buffer when finished, and videoread() 160 1.1 jmcneill * does the same when all data has been read. The sample now 161 1.1 jmcneill * returns to the ingress queue. */ 162 1.1 jmcneill struct sample_queue vs_ingress; /* samples under driver control */ 163 1.1 jmcneill struct sample_queue vs_egress; /* samples headed for userspace */ 164 1.1 jmcneill 165 1.1 jmcneill bool vs_streaming; 166 1.1 jmcneill enum video_stream_method vs_method; /* method by which 167 1.1 jmcneill * userspace will read 168 1.1 jmcneill * samples */ 169 1.1 jmcneill 170 1.1 jmcneill kmutex_t vs_lock; /* Lock to manipulate queues. 171 1.1 jmcneill * Should also be held when 172 1.1 jmcneill * changing number of 173 1.1 jmcneill * buffers. */ 174 1.1 jmcneill kcondvar_t vs_sample_cv; /* signaled on new 175 1.1 jmcneill * ingress sample */ 176 1.7 jmcneill struct selinfo vs_sel; 177 1.1 jmcneill 178 1.1 jmcneill uint32_t vs_bytesread; /* bytes read() from current 179 1.1 jmcneill * sample thus far */ 180 1.1 jmcneill }; 181 1.1 jmcneill 182 1.1 jmcneill struct video_softc { 183 1.1 jmcneill device_t sc_dev; 184 1.1 jmcneill device_t hw_dev; /* Hardware (parent) device */ 185 1.1 jmcneill void * hw_softc; /* Hardware device private softc */ 186 1.1 jmcneill const struct video_hw_if *hw_if; /* Hardware interface */ 187 1.1 jmcneill 188 1.1 jmcneill u_int sc_open; 189 1.1 jmcneill int sc_refcnt; 190 1.1 jmcneill int sc_opencnt; 191 1.1 jmcneill bool sc_dying; 192 1.1 jmcneill 193 1.1 jmcneill struct video_stream sc_stream_in; 194 1.1 jmcneill }; 195 1.1 jmcneill static int video_print(void *, const char *); 196 1.1 jmcneill 197 1.1 jmcneill static int video_match(device_t, cfdata_t, void *); 198 1.1 jmcneill static void video_attach(device_t, device_t, void *); 199 1.1 jmcneill static int video_detach(device_t, int); 200 1.1 jmcneill static int video_activate(device_t, enum devact); 201 1.1 jmcneill 202 1.1 jmcneill dev_type_open(videoopen); 203 1.1 jmcneill dev_type_close(videoclose); 204 1.1 jmcneill dev_type_read(videoread); 205 1.1 jmcneill dev_type_write(videowrite); 206 1.1 jmcneill dev_type_ioctl(videoioctl); 207 1.1 jmcneill dev_type_poll(videopoll); 208 1.1 jmcneill dev_type_mmap(videommap); 209 1.1 jmcneill 210 1.1 jmcneill const struct cdevsw video_cdevsw = { 211 1.31 dholland .d_open = videoopen, 212 1.31 dholland .d_close = videoclose, 213 1.31 dholland .d_read = videoread, 214 1.31 dholland .d_write = videowrite, 215 1.31 dholland .d_ioctl = videoioctl, 216 1.31 dholland .d_stop = nostop, 217 1.31 dholland .d_tty = notty, 218 1.31 dholland .d_poll = videopoll, 219 1.31 dholland .d_mmap = videommap, 220 1.31 dholland .d_kqfilter = nokqfilter, 221 1.32 dholland .d_discard = nodiscard, 222 1.31 dholland .d_flag = D_OTHER 223 1.1 jmcneill }; 224 1.1 jmcneill 225 1.1 jmcneill #define VIDEOUNIT(n) (minor(n)) 226 1.1 jmcneill 227 1.1 jmcneill CFATTACH_DECL_NEW(video, sizeof(struct video_softc), 228 1.1 jmcneill video_match, video_attach, video_detach, video_activate); 229 1.1 jmcneill 230 1.1 jmcneill static const char * video_pixel_format_str(enum video_pixel_format); 231 1.1 jmcneill 232 1.1 jmcneill /* convert various values from V4L2 to native values of this driver */ 233 1.1 jmcneill static uint16_t v4l2id_to_control_id(uint32_t); 234 1.1 jmcneill static uint32_t control_flags_to_v4l2flags(uint32_t); 235 1.1 jmcneill static enum v4l2_ctrl_type control_type_to_v4l2type(enum video_control_type); 236 1.1 jmcneill 237 1.1 jmcneill static void v4l2_format_to_video_format(const struct v4l2_format *, 238 1.1 jmcneill struct video_format *); 239 1.1 jmcneill static void video_format_to_v4l2_format(const struct video_format *, 240 1.1 jmcneill struct v4l2_format *); 241 1.24 jmcneill static void v4l2_standard_to_video_standard(v4l2_std_id, 242 1.24 jmcneill enum video_standard *); 243 1.24 jmcneill static void video_standard_to_v4l2_standard(enum video_standard, 244 1.24 jmcneill struct v4l2_standard *); 245 1.24 jmcneill static void v4l2_input_to_video_input(const struct v4l2_input *, 246 1.24 jmcneill struct video_input *); 247 1.24 jmcneill static void video_input_to_v4l2_input(const struct video_input *, 248 1.24 jmcneill struct v4l2_input *); 249 1.24 jmcneill static void v4l2_audio_to_video_audio(const struct v4l2_audio *, 250 1.24 jmcneill struct video_audio *); 251 1.24 jmcneill static void video_audio_to_v4l2_audio(const struct video_audio *, 252 1.24 jmcneill struct v4l2_audio *); 253 1.24 jmcneill static void v4l2_tuner_to_video_tuner(const struct v4l2_tuner *, 254 1.24 jmcneill struct video_tuner *); 255 1.24 jmcneill static void video_tuner_to_v4l2_tuner(const struct video_tuner *, 256 1.24 jmcneill struct v4l2_tuner *); 257 1.1 jmcneill 258 1.24 jmcneill /* V4L2 api functions, typically called from videoioctl() */ 259 1.1 jmcneill static int video_enum_format(struct video_softc *, struct v4l2_fmtdesc *); 260 1.1 jmcneill static int video_get_format(struct video_softc *, 261 1.1 jmcneill struct v4l2_format *); 262 1.1 jmcneill static int video_set_format(struct video_softc *, 263 1.1 jmcneill struct v4l2_format *); 264 1.1 jmcneill static int video_try_format(struct video_softc *, 265 1.1 jmcneill struct v4l2_format *); 266 1.37 jmcneill static int video_get_parm(struct video_softc *, 267 1.37 jmcneill struct v4l2_streamparm *); 268 1.37 jmcneill static int video_set_parm(struct video_softc *, 269 1.37 jmcneill struct v4l2_streamparm *); 270 1.24 jmcneill static int video_enum_standard(struct video_softc *, 271 1.24 jmcneill struct v4l2_standard *); 272 1.24 jmcneill static int video_get_standard(struct video_softc *, v4l2_std_id *); 273 1.24 jmcneill static int video_set_standard(struct video_softc *, v4l2_std_id); 274 1.24 jmcneill static int video_enum_input(struct video_softc *, struct v4l2_input *); 275 1.24 jmcneill static int video_get_input(struct video_softc *, int *); 276 1.24 jmcneill static int video_set_input(struct video_softc *, int); 277 1.24 jmcneill static int video_enum_audio(struct video_softc *, struct v4l2_audio *); 278 1.24 jmcneill static int video_get_audio(struct video_softc *, struct v4l2_audio *); 279 1.24 jmcneill static int video_set_audio(struct video_softc *, struct v4l2_audio *); 280 1.24 jmcneill static int video_get_tuner(struct video_softc *, struct v4l2_tuner *); 281 1.24 jmcneill static int video_set_tuner(struct video_softc *, struct v4l2_tuner *); 282 1.24 jmcneill static int video_get_frequency(struct video_softc *, 283 1.24 jmcneill struct v4l2_frequency *); 284 1.24 jmcneill static int video_set_frequency(struct video_softc *, 285 1.24 jmcneill struct v4l2_frequency *); 286 1.1 jmcneill static int video_query_control(struct video_softc *, 287 1.1 jmcneill struct v4l2_queryctrl *); 288 1.1 jmcneill static int video_get_control(struct video_softc *, 289 1.1 jmcneill struct v4l2_control *); 290 1.1 jmcneill static int video_set_control(struct video_softc *, 291 1.1 jmcneill const struct v4l2_control *); 292 1.1 jmcneill static int video_request_bufs(struct video_softc *, 293 1.1 jmcneill struct v4l2_requestbuffers *); 294 1.1 jmcneill static int video_query_buf(struct video_softc *, struct v4l2_buffer *); 295 1.1 jmcneill static int video_queue_buf(struct video_softc *, struct v4l2_buffer *); 296 1.1 jmcneill static int video_dequeue_buf(struct video_softc *, struct v4l2_buffer *); 297 1.1 jmcneill static int video_stream_on(struct video_softc *, enum v4l2_buf_type); 298 1.1 jmcneill static int video_stream_off(struct video_softc *, enum v4l2_buf_type); 299 1.1 jmcneill 300 1.1 jmcneill static struct video_buffer * video_buffer_alloc(void); 301 1.1 jmcneill static void video_buffer_free(struct video_buffer *); 302 1.1 jmcneill 303 1.1 jmcneill 304 1.1 jmcneill /* functions for video_stream */ 305 1.48 mlelstv static void video_stream_init(struct video_stream *, const char *name); 306 1.1 jmcneill static void video_stream_fini(struct video_stream *); 307 1.1 jmcneill 308 1.1 jmcneill static int video_stream_setup_bufs(struct video_stream *, 309 1.1 jmcneill enum video_stream_method, 310 1.1 jmcneill uint8_t); 311 1.1 jmcneill static void video_stream_teardown_bufs(struct video_stream *); 312 1.1 jmcneill 313 1.1 jmcneill static int video_stream_realloc_bufs(struct video_stream *, uint8_t); 314 1.1 jmcneill #define video_stream_free_bufs(vs) \ 315 1.1 jmcneill video_stream_realloc_bufs((vs), 0) 316 1.1 jmcneill 317 1.1 jmcneill static void video_stream_enqueue(struct video_stream *, 318 1.1 jmcneill struct video_buffer *); 319 1.1 jmcneill static struct video_buffer * video_stream_dequeue(struct video_stream *); 320 1.1 jmcneill static void video_stream_write(struct video_stream *, 321 1.1 jmcneill const struct video_payload *); 322 1.1 jmcneill static void video_stream_sample_done(struct video_stream *); 323 1.1 jmcneill 324 1.1 jmcneill #ifdef VIDEO_DEBUG 325 1.1 jmcneill /* debugging */ 326 1.1 jmcneill static const char * video_ioctl_str(u_long); 327 1.1 jmcneill #endif 328 1.1 jmcneill 329 1.39 riastrad 330 1.1 jmcneill static int 331 1.1 jmcneill video_match(device_t parent, cfdata_t match, void *aux) 332 1.1 jmcneill { 333 1.30 christos #ifdef VIDEO_DEBUG 334 1.1 jmcneill struct video_attach_args *args; 335 1.1 jmcneill 336 1.1 jmcneill args = aux; 337 1.1 jmcneill DPRINTF(("video_match: hw=%p\n", args->hw_if)); 338 1.30 christos #endif 339 1.1 jmcneill return 1; 340 1.1 jmcneill } 341 1.1 jmcneill 342 1.1 jmcneill 343 1.1 jmcneill static void 344 1.1 jmcneill video_attach(device_t parent, device_t self, void *aux) 345 1.1 jmcneill { 346 1.1 jmcneill struct video_softc *sc; 347 1.1 jmcneill struct video_attach_args *args; 348 1.1 jmcneill 349 1.1 jmcneill sc = device_private(self); 350 1.1 jmcneill args = aux; 351 1.39 riastrad 352 1.1 jmcneill sc->sc_dev = self; 353 1.1 jmcneill sc->hw_dev = parent; 354 1.1 jmcneill sc->hw_if = args->hw_if; 355 1.44 riastrad sc->hw_softc = args->hw_softc; 356 1.1 jmcneill 357 1.1 jmcneill sc->sc_open = 0; 358 1.1 jmcneill sc->sc_refcnt = 0; 359 1.1 jmcneill sc->sc_opencnt = 0; 360 1.1 jmcneill sc->sc_dying = false; 361 1.1 jmcneill 362 1.48 mlelstv video_stream_init(&sc->sc_stream_in, device_xname(self)); 363 1.1 jmcneill 364 1.5 jmcneill aprint_naive("\n"); 365 1.5 jmcneill aprint_normal(": %s\n", sc->hw_if->get_devname(sc->hw_softc)); 366 1.5 jmcneill 367 1.1 jmcneill DPRINTF(("video_attach: sc=%p hwif=%p\n", sc, sc->hw_if)); 368 1.17 jmcneill 369 1.17 jmcneill if (!pmf_device_register(self, NULL, NULL)) 370 1.17 jmcneill aprint_error_dev(self, "couldn't establish power handler\n"); 371 1.1 jmcneill } 372 1.1 jmcneill 373 1.1 jmcneill 374 1.1 jmcneill static int 375 1.1 jmcneill video_activate(device_t self, enum devact act) 376 1.1 jmcneill { 377 1.23 dyoung struct video_softc *sc = device_private(self); 378 1.1 jmcneill 379 1.1 jmcneill DPRINTF(("video_activate: sc=%p\n", sc)); 380 1.1 jmcneill switch (act) { 381 1.1 jmcneill case DVACT_DEACTIVATE: 382 1.1 jmcneill sc->sc_dying = true; 383 1.23 dyoung return 0; 384 1.23 dyoung default: 385 1.23 dyoung return EOPNOTSUPP; 386 1.1 jmcneill } 387 1.1 jmcneill } 388 1.1 jmcneill 389 1.1 jmcneill 390 1.1 jmcneill static int 391 1.1 jmcneill video_detach(device_t self, int flags) 392 1.1 jmcneill { 393 1.1 jmcneill struct video_softc *sc; 394 1.1 jmcneill int maj, mn; 395 1.1 jmcneill 396 1.1 jmcneill sc = device_private(self); 397 1.1 jmcneill DPRINTF(("video_detach: sc=%p flags=%d\n", sc, flags)); 398 1.1 jmcneill 399 1.1 jmcneill sc->sc_dying = true; 400 1.17 jmcneill 401 1.17 jmcneill pmf_device_deregister(self); 402 1.39 riastrad 403 1.1 jmcneill maj = cdevsw_lookup_major(&video_cdevsw); 404 1.1 jmcneill mn = device_unit(self); 405 1.1 jmcneill /* close open instances */ 406 1.1 jmcneill vdevgone(maj, mn, mn, VCHR); 407 1.1 jmcneill 408 1.1 jmcneill video_stream_fini(&sc->sc_stream_in); 409 1.1 jmcneill 410 1.1 jmcneill return 0; 411 1.1 jmcneill } 412 1.1 jmcneill 413 1.1 jmcneill 414 1.1 jmcneill static int 415 1.1 jmcneill video_print(void *aux, const char *pnp) 416 1.1 jmcneill { 417 1.1 jmcneill if (pnp != NULL) { 418 1.1 jmcneill DPRINTF(("video_print: have pnp\n")); 419 1.1 jmcneill aprint_normal("%s at %s\n", "video", pnp); 420 1.1 jmcneill } else { 421 1.1 jmcneill DPRINTF(("video_print: pnp is NULL\n")); 422 1.1 jmcneill } 423 1.1 jmcneill return UNCONF; 424 1.1 jmcneill } 425 1.1 jmcneill 426 1.1 jmcneill 427 1.1 jmcneill /* 428 1.1 jmcneill * Called from hardware driver. This is where the MI audio driver 429 1.1 jmcneill * gets probed/attached to the hardware driver. 430 1.1 jmcneill */ 431 1.1 jmcneill device_t 432 1.45 riastrad video_attach_mi(const struct video_hw_if *hw_if, device_t parent, void *sc) 433 1.44 riastrad { 434 1.44 riastrad struct video_attach_args args; 435 1.44 riastrad 436 1.44 riastrad args.hw_if = hw_if; 437 1.44 riastrad args.hw_softc = sc; 438 1.40 thorpej return config_found(parent, &args, video_print, 439 1.41 thorpej CFARGS(.iattr = "videobus")); 440 1.1 jmcneill } 441 1.1 jmcneill 442 1.1 jmcneill /* video_submit_payload - called by hardware driver to submit payload data */ 443 1.1 jmcneill void 444 1.1 jmcneill video_submit_payload(device_t self, const struct video_payload *payload) 445 1.1 jmcneill { 446 1.1 jmcneill struct video_softc *sc; 447 1.1 jmcneill 448 1.1 jmcneill sc = device_private(self); 449 1.1 jmcneill 450 1.1 jmcneill if (sc == NULL) 451 1.1 jmcneill return; 452 1.1 jmcneill 453 1.1 jmcneill video_stream_write(&sc->sc_stream_in, payload); 454 1.1 jmcneill } 455 1.1 jmcneill 456 1.1 jmcneill static const char * 457 1.1 jmcneill video_pixel_format_str(enum video_pixel_format px) 458 1.1 jmcneill { 459 1.1 jmcneill switch (px) { 460 1.16 jmcneill case VIDEO_FORMAT_UYVY: return "UYVY"; 461 1.14 jmcneill case VIDEO_FORMAT_YUV420: return "YUV420"; 462 1.1 jmcneill case VIDEO_FORMAT_YUY2: return "YUYV"; 463 1.1 jmcneill case VIDEO_FORMAT_NV12: return "NV12"; 464 1.11 jmcneill case VIDEO_FORMAT_RGB24: return "RGB24"; 465 1.16 jmcneill case VIDEO_FORMAT_RGB555: return "RGB555"; 466 1.16 jmcneill case VIDEO_FORMAT_RGB565: return "RGB565"; 467 1.15 jmcneill case VIDEO_FORMAT_SBGGR8: return "SBGGR8"; 468 1.1 jmcneill case VIDEO_FORMAT_MJPEG: return "MJPEG"; 469 1.1 jmcneill case VIDEO_FORMAT_DV: return "DV"; 470 1.1 jmcneill case VIDEO_FORMAT_MPEG: return "MPEG"; 471 1.1 jmcneill default: return "Unknown"; 472 1.1 jmcneill } 473 1.1 jmcneill } 474 1.1 jmcneill 475 1.1 jmcneill /* Takes a V4L2 id and returns a "native" video driver control id. 476 1.1 jmcneill * TODO: is there a better way to do this? some kind of array? */ 477 1.1 jmcneill static uint16_t 478 1.1 jmcneill v4l2id_to_control_id(uint32_t v4l2id) 479 1.1 jmcneill { 480 1.1 jmcneill /* mask includes class bits and control id bits */ 481 1.1 jmcneill switch (v4l2id & 0xffffff) { 482 1.1 jmcneill case V4L2_CID_BRIGHTNESS: return VIDEO_CONTROL_BRIGHTNESS; 483 1.1 jmcneill case V4L2_CID_CONTRAST: return VIDEO_CONTROL_CONTRAST; 484 1.1 jmcneill case V4L2_CID_SATURATION: return VIDEO_CONTROL_SATURATION; 485 1.1 jmcneill case V4L2_CID_HUE: return VIDEO_CONTROL_HUE; 486 1.1 jmcneill case V4L2_CID_HUE_AUTO: return VIDEO_CONTROL_HUE_AUTO; 487 1.1 jmcneill case V4L2_CID_SHARPNESS: return VIDEO_CONTROL_SHARPNESS; 488 1.1 jmcneill case V4L2_CID_GAMMA: return VIDEO_CONTROL_GAMMA; 489 1.1 jmcneill 490 1.1 jmcneill /* "black level" means the same as "brightness", but V4L2 491 1.1 jmcneill * defines two separate controls that are not identical. 492 1.1 jmcneill * V4L2_CID_BLACK_LEVEL is deprecated however in V4L2. */ 493 1.1 jmcneill case V4L2_CID_BLACK_LEVEL: return VIDEO_CONTROL_BRIGHTNESS; 494 1.1 jmcneill 495 1.1 jmcneill case V4L2_CID_AUDIO_VOLUME: return VIDEO_CONTROL_UNDEFINED; 496 1.1 jmcneill case V4L2_CID_AUDIO_BALANCE: return VIDEO_CONTROL_UNDEFINED; 497 1.1 jmcneill case V4L2_CID_AUDIO_BASS: return VIDEO_CONTROL_UNDEFINED; 498 1.1 jmcneill case V4L2_CID_AUDIO_TREBLE: return VIDEO_CONTROL_UNDEFINED; 499 1.1 jmcneill case V4L2_CID_AUDIO_MUTE: return VIDEO_CONTROL_UNDEFINED; 500 1.1 jmcneill case V4L2_CID_AUDIO_LOUDNESS: return VIDEO_CONTROL_UNDEFINED; 501 1.39 riastrad 502 1.1 jmcneill case V4L2_CID_AUTO_WHITE_BALANCE: 503 1.1 jmcneill return VIDEO_CONTROL_WHITE_BALANCE_AUTO; 504 1.1 jmcneill case V4L2_CID_DO_WHITE_BALANCE: 505 1.1 jmcneill return VIDEO_CONTROL_WHITE_BALANCE_ACTION; 506 1.1 jmcneill case V4L2_CID_RED_BALANCE: 507 1.1 jmcneill case V4L2_CID_BLUE_BALANCE: 508 1.1 jmcneill /* This might not fit in with the control_id/value_id scheme */ 509 1.1 jmcneill return VIDEO_CONTROL_WHITE_BALANCE_COMPONENT; 510 1.1 jmcneill case V4L2_CID_WHITE_BALANCE_TEMPERATURE: 511 1.1 jmcneill return VIDEO_CONTROL_WHITE_BALANCE_TEMPERATURE; 512 1.1 jmcneill case V4L2_CID_EXPOSURE: 513 1.1 jmcneill return VIDEO_CONTROL_EXPOSURE_TIME_ABSOLUTE; 514 1.1 jmcneill case V4L2_CID_GAIN: return VIDEO_CONTROL_GAIN; 515 1.1 jmcneill case V4L2_CID_AUTOGAIN: return VIDEO_CONTROL_GAIN_AUTO; 516 1.1 jmcneill case V4L2_CID_HFLIP: return VIDEO_CONTROL_HFLIP; 517 1.1 jmcneill case V4L2_CID_VFLIP: return VIDEO_CONTROL_VFLIP; 518 1.1 jmcneill case V4L2_CID_HCENTER_DEPRECATED: 519 1.1 jmcneill case V4L2_CID_VCENTER_DEPRECATED: 520 1.1 jmcneill return VIDEO_CONTROL_UNDEFINED; 521 1.1 jmcneill case V4L2_CID_POWER_LINE_FREQUENCY: 522 1.1 jmcneill return VIDEO_CONTROL_POWER_LINE_FREQUENCY; 523 1.1 jmcneill case V4L2_CID_BACKLIGHT_COMPENSATION: 524 1.1 jmcneill return VIDEO_CONTROL_BACKLIGHT_COMPENSATION; 525 1.1 jmcneill default: return V4L2_CTRL_ID2CID(v4l2id); 526 1.1 jmcneill } 527 1.1 jmcneill } 528 1.1 jmcneill 529 1.1 jmcneill 530 1.1 jmcneill static uint32_t 531 1.1 jmcneill control_flags_to_v4l2flags(uint32_t flags) 532 1.1 jmcneill { 533 1.1 jmcneill uint32_t v4l2flags = 0; 534 1.1 jmcneill 535 1.1 jmcneill if (flags & VIDEO_CONTROL_FLAG_DISABLED) 536 1.1 jmcneill v4l2flags |= V4L2_CTRL_FLAG_INACTIVE; 537 1.1 jmcneill 538 1.1 jmcneill if (!(flags & VIDEO_CONTROL_FLAG_WRITE)) 539 1.1 jmcneill v4l2flags |= V4L2_CTRL_FLAG_READ_ONLY; 540 1.1 jmcneill 541 1.1 jmcneill if (flags & VIDEO_CONTROL_FLAG_AUTOUPDATE) 542 1.1 jmcneill v4l2flags |= V4L2_CTRL_FLAG_GRABBED; 543 1.1 jmcneill 544 1.1 jmcneill return v4l2flags; 545 1.1 jmcneill } 546 1.1 jmcneill 547 1.1 jmcneill 548 1.1 jmcneill static enum v4l2_ctrl_type 549 1.1 jmcneill control_type_to_v4l2type(enum video_control_type type) { 550 1.1 jmcneill switch (type) { 551 1.1 jmcneill case VIDEO_CONTROL_TYPE_INT: return V4L2_CTRL_TYPE_INTEGER; 552 1.1 jmcneill case VIDEO_CONTROL_TYPE_BOOL: return V4L2_CTRL_TYPE_BOOLEAN; 553 1.1 jmcneill case VIDEO_CONTROL_TYPE_LIST: return V4L2_CTRL_TYPE_MENU; 554 1.1 jmcneill case VIDEO_CONTROL_TYPE_ACTION: return V4L2_CTRL_TYPE_BUTTON; 555 1.1 jmcneill default: return V4L2_CTRL_TYPE_INTEGER; /* err? */ 556 1.1 jmcneill } 557 1.1 jmcneill } 558 1.1 jmcneill 559 1.1 jmcneill 560 1.1 jmcneill static int 561 1.1 jmcneill video_query_control(struct video_softc *sc, 562 1.1 jmcneill struct v4l2_queryctrl *query) 563 1.1 jmcneill { 564 1.1 jmcneill const struct video_hw_if *hw; 565 1.1 jmcneill struct video_control_desc_group desc_group; 566 1.1 jmcneill struct video_control_desc desc; 567 1.1 jmcneill int err; 568 1.1 jmcneill 569 1.1 jmcneill hw = sc->hw_if; 570 1.1 jmcneill if (hw->get_control_desc_group) { 571 1.1 jmcneill desc.group_id = desc.control_id = 572 1.1 jmcneill v4l2id_to_control_id(query->id); 573 1.1 jmcneill 574 1.1 jmcneill desc_group.group_id = desc.group_id; 575 1.1 jmcneill desc_group.length = 1; 576 1.1 jmcneill desc_group.desc = &desc; 577 1.39 riastrad 578 1.1 jmcneill err = hw->get_control_desc_group(sc->hw_softc, &desc_group); 579 1.1 jmcneill if (err != 0) 580 1.1 jmcneill return err; 581 1.1 jmcneill 582 1.1 jmcneill query->type = control_type_to_v4l2type(desc.type); 583 1.1 jmcneill memcpy(query->name, desc.name, 32); 584 1.1 jmcneill query->minimum = desc.min; 585 1.1 jmcneill query->maximum = desc.max; 586 1.1 jmcneill query->step = desc.step; 587 1.1 jmcneill query->default_value = desc.def; 588 1.1 jmcneill query->flags = control_flags_to_v4l2flags(desc.flags); 589 1.1 jmcneill 590 1.1 jmcneill return 0; 591 1.1 jmcneill } else { 592 1.1 jmcneill return EINVAL; 593 1.1 jmcneill } 594 1.1 jmcneill } 595 1.1 jmcneill 596 1.1 jmcneill 597 1.1 jmcneill /* Takes a single Video4Linux2 control and queries the driver for the 598 1.1 jmcneill * current value. */ 599 1.1 jmcneill static int 600 1.1 jmcneill video_get_control(struct video_softc *sc, 601 1.1 jmcneill struct v4l2_control *vcontrol) 602 1.1 jmcneill { 603 1.1 jmcneill const struct video_hw_if *hw; 604 1.1 jmcneill struct video_control_group group; 605 1.1 jmcneill struct video_control control; 606 1.1 jmcneill int err; 607 1.1 jmcneill 608 1.1 jmcneill hw = sc->hw_if; 609 1.1 jmcneill if (hw->get_control_group) { 610 1.1 jmcneill control.group_id = control.control_id = 611 1.1 jmcneill v4l2id_to_control_id(vcontrol->id); 612 1.1 jmcneill /* ?? if "control_id" is arbitrarily defined by the 613 1.1 jmcneill * driver, then we need some way to store it... Maybe 614 1.1 jmcneill * it doesn't matter for single value controls. */ 615 1.1 jmcneill control.value = 0; 616 1.1 jmcneill 617 1.1 jmcneill group.group_id = control.group_id; 618 1.1 jmcneill group.length = 1; 619 1.1 jmcneill group.control = &control; 620 1.1 jmcneill 621 1.1 jmcneill err = hw->get_control_group(sc->hw_softc, &group); 622 1.1 jmcneill if (err != 0) 623 1.1 jmcneill return err; 624 1.39 riastrad 625 1.1 jmcneill vcontrol->value = control.value; 626 1.1 jmcneill return 0; 627 1.1 jmcneill } else { 628 1.1 jmcneill return EINVAL; 629 1.1 jmcneill } 630 1.1 jmcneill } 631 1.1 jmcneill 632 1.1 jmcneill static void 633 1.1 jmcneill video_format_to_v4l2_format(const struct video_format *src, 634 1.1 jmcneill struct v4l2_format *dest) 635 1.1 jmcneill { 636 1.1 jmcneill /* TODO: what about win and vbi formats? */ 637 1.1 jmcneill dest->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 638 1.1 jmcneill dest->fmt.pix.width = src->width; 639 1.1 jmcneill dest->fmt.pix.height = src->height; 640 1.24 jmcneill if (VIDEO_INTERLACED(src->interlace_flags)) 641 1.24 jmcneill dest->fmt.pix.field = V4L2_FIELD_INTERLACED; 642 1.24 jmcneill else 643 1.24 jmcneill dest->fmt.pix.field = V4L2_FIELD_NONE; 644 1.1 jmcneill dest->fmt.pix.bytesperline = src->stride; 645 1.1 jmcneill dest->fmt.pix.sizeimage = src->sample_size; 646 1.15 jmcneill dest->fmt.pix.priv = src->priv; 647 1.39 riastrad 648 1.24 jmcneill switch (src->color.primaries) { 649 1.24 jmcneill case VIDEO_COLOR_PRIMARIES_SMPTE_170M: 650 1.24 jmcneill dest->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 651 1.24 jmcneill break; 652 1.24 jmcneill /* XXX */ 653 1.24 jmcneill case VIDEO_COLOR_PRIMARIES_UNSPECIFIED: 654 1.24 jmcneill default: 655 1.24 jmcneill dest->fmt.pix.colorspace = 0; 656 1.24 jmcneill break; 657 1.24 jmcneill } 658 1.24 jmcneill 659 1.1 jmcneill switch (src->pixel_format) { 660 1.16 jmcneill case VIDEO_FORMAT_UYVY: 661 1.16 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; 662 1.16 jmcneill break; 663 1.14 jmcneill case VIDEO_FORMAT_YUV420: 664 1.14 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420; 665 1.14 jmcneill break; 666 1.1 jmcneill case VIDEO_FORMAT_YUY2: 667 1.1 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 668 1.1 jmcneill break; 669 1.1 jmcneill case VIDEO_FORMAT_NV12: 670 1.1 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; 671 1.1 jmcneill break; 672 1.11 jmcneill case VIDEO_FORMAT_RGB24: 673 1.11 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24; 674 1.11 jmcneill break; 675 1.16 jmcneill case VIDEO_FORMAT_RGB555: 676 1.16 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB555; 677 1.16 jmcneill break; 678 1.16 jmcneill case VIDEO_FORMAT_RGB565: 679 1.16 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565; 680 1.16 jmcneill break; 681 1.15 jmcneill case VIDEO_FORMAT_SBGGR8: 682 1.15 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8; 683 1.15 jmcneill break; 684 1.1 jmcneill case VIDEO_FORMAT_MJPEG: 685 1.8 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; 686 1.1 jmcneill break; 687 1.1 jmcneill case VIDEO_FORMAT_DV: 688 1.1 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_DV; 689 1.1 jmcneill break; 690 1.1 jmcneill case VIDEO_FORMAT_MPEG: 691 1.1 jmcneill dest->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; 692 1.1 jmcneill break; 693 1.1 jmcneill case VIDEO_FORMAT_UNDEFINED: 694 1.1 jmcneill default: 695 1.1 jmcneill DPRINTF(("video_get_format: unknown pixel format %d\n", 696 1.1 jmcneill src->pixel_format)); 697 1.1 jmcneill dest->fmt.pix.pixelformat = 0; /* V4L2 doesn't define 698 1.1 jmcneill * and "undefined" 699 1.1 jmcneill * format? */ 700 1.1 jmcneill break; 701 1.1 jmcneill } 702 1.1 jmcneill 703 1.1 jmcneill } 704 1.1 jmcneill 705 1.1 jmcneill static void 706 1.1 jmcneill v4l2_format_to_video_format(const struct v4l2_format *src, 707 1.1 jmcneill struct video_format *dest) 708 1.1 jmcneill { 709 1.1 jmcneill switch (src->type) { 710 1.1 jmcneill case V4L2_BUF_TYPE_VIDEO_CAPTURE: 711 1.1 jmcneill dest->width = src->fmt.pix.width; 712 1.1 jmcneill dest->height = src->fmt.pix.height; 713 1.1 jmcneill 714 1.1 jmcneill dest->stride = src->fmt.pix.bytesperline; 715 1.1 jmcneill dest->sample_size = src->fmt.pix.sizeimage; 716 1.1 jmcneill 717 1.24 jmcneill if (src->fmt.pix.field == V4L2_FIELD_INTERLACED) 718 1.24 jmcneill dest->interlace_flags = VIDEO_INTERLACE_ON; 719 1.24 jmcneill else 720 1.24 jmcneill dest->interlace_flags = VIDEO_INTERLACE_OFF; 721 1.24 jmcneill 722 1.24 jmcneill switch (src->fmt.pix.colorspace) { 723 1.24 jmcneill case V4L2_COLORSPACE_SMPTE170M: 724 1.24 jmcneill dest->color.primaries = 725 1.24 jmcneill VIDEO_COLOR_PRIMARIES_SMPTE_170M; 726 1.24 jmcneill break; 727 1.24 jmcneill /* XXX */ 728 1.24 jmcneill default: 729 1.24 jmcneill dest->color.primaries = 730 1.24 jmcneill VIDEO_COLOR_PRIMARIES_UNSPECIFIED; 731 1.24 jmcneill break; 732 1.24 jmcneill } 733 1.24 jmcneill 734 1.1 jmcneill switch (src->fmt.pix.pixelformat) { 735 1.16 jmcneill case V4L2_PIX_FMT_UYVY: 736 1.16 jmcneill dest->pixel_format = VIDEO_FORMAT_UYVY; 737 1.16 jmcneill break; 738 1.14 jmcneill case V4L2_PIX_FMT_YUV420: 739 1.14 jmcneill dest->pixel_format = VIDEO_FORMAT_YUV420; 740 1.14 jmcneill break; 741 1.1 jmcneill case V4L2_PIX_FMT_YUYV: 742 1.1 jmcneill dest->pixel_format = VIDEO_FORMAT_YUY2; 743 1.1 jmcneill break; 744 1.1 jmcneill case V4L2_PIX_FMT_NV12: 745 1.1 jmcneill dest->pixel_format = VIDEO_FORMAT_NV12; 746 1.1 jmcneill break; 747 1.11 jmcneill case V4L2_PIX_FMT_RGB24: 748 1.11 jmcneill dest->pixel_format = VIDEO_FORMAT_RGB24; 749 1.11 jmcneill break; 750 1.16 jmcneill case V4L2_PIX_FMT_RGB555: 751 1.16 jmcneill dest->pixel_format = VIDEO_FORMAT_RGB555; 752 1.16 jmcneill break; 753 1.16 jmcneill case V4L2_PIX_FMT_RGB565: 754 1.16 jmcneill dest->pixel_format = VIDEO_FORMAT_RGB565; 755 1.16 jmcneill break; 756 1.15 jmcneill case V4L2_PIX_FMT_SBGGR8: 757 1.15 jmcneill dest->pixel_format = VIDEO_FORMAT_SBGGR8; 758 1.15 jmcneill break; 759 1.9 jmcneill case V4L2_PIX_FMT_MJPEG: 760 1.1 jmcneill dest->pixel_format = VIDEO_FORMAT_MJPEG; 761 1.1 jmcneill break; 762 1.1 jmcneill case V4L2_PIX_FMT_DV: 763 1.1 jmcneill dest->pixel_format = VIDEO_FORMAT_DV; 764 1.1 jmcneill break; 765 1.1 jmcneill case V4L2_PIX_FMT_MPEG: 766 1.9 jmcneill dest->pixel_format = VIDEO_FORMAT_MPEG; 767 1.1 jmcneill break; 768 1.1 jmcneill default: 769 1.1 jmcneill DPRINTF(("video: unknown v4l2 pixel format %d\n", 770 1.1 jmcneill src->fmt.pix.pixelformat)); 771 1.1 jmcneill dest->pixel_format = VIDEO_FORMAT_UNDEFINED; 772 1.1 jmcneill break; 773 1.1 jmcneill } 774 1.1 jmcneill break; 775 1.1 jmcneill default: 776 1.1 jmcneill /* TODO: other v4l2 format types */ 777 1.1 jmcneill DPRINTF(("video: unsupported v4l2 format type %d\n", 778 1.1 jmcneill src->type)); 779 1.1 jmcneill break; 780 1.1 jmcneill } 781 1.1 jmcneill } 782 1.1 jmcneill 783 1.1 jmcneill static int 784 1.1 jmcneill video_enum_format(struct video_softc *sc, struct v4l2_fmtdesc *fmtdesc) 785 1.1 jmcneill { 786 1.1 jmcneill const struct video_hw_if *hw; 787 1.1 jmcneill struct video_format vfmt; 788 1.1 jmcneill struct v4l2_format fmt; 789 1.1 jmcneill int err; 790 1.1 jmcneill 791 1.1 jmcneill hw = sc->hw_if; 792 1.1 jmcneill if (hw->enum_format == NULL) 793 1.3 jmcneill return ENOTTY; 794 1.1 jmcneill 795 1.1 jmcneill err = hw->enum_format(sc->hw_softc, fmtdesc->index, &vfmt); 796 1.1 jmcneill if (err != 0) 797 1.1 jmcneill return err; 798 1.1 jmcneill 799 1.1 jmcneill video_format_to_v4l2_format(&vfmt, &fmt); 800 1.1 jmcneill 801 1.1 jmcneill fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* TODO: only one type for now */ 802 1.24 jmcneill fmtdesc->flags = 0; 803 1.1 jmcneill if (vfmt.pixel_format >= VIDEO_FORMAT_MJPEG) 804 1.1 jmcneill fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED; 805 1.1 jmcneill strlcpy(fmtdesc->description, 806 1.1 jmcneill video_pixel_format_str(vfmt.pixel_format), 807 1.1 jmcneill sizeof(fmtdesc->description)); 808 1.1 jmcneill fmtdesc->pixelformat = fmt.fmt.pix.pixelformat; 809 1.1 jmcneill 810 1.1 jmcneill return 0; 811 1.1 jmcneill } 812 1.1 jmcneill 813 1.1 jmcneill static int 814 1.38 rjs video_enum_framesizes(struct video_softc *sc, struct v4l2_frmsizeenum *frmdesc) 815 1.38 rjs { 816 1.38 rjs const struct video_hw_if *hw; 817 1.38 rjs struct video_format vfmt; 818 1.38 rjs struct v4l2_format fmt; 819 1.47 mlelstv u_int32_t n, index; 820 1.38 rjs int err; 821 1.38 rjs 822 1.38 rjs hw = sc->hw_if; 823 1.38 rjs if (hw->enum_format == NULL) 824 1.38 rjs return ENOTTY; 825 1.38 rjs 826 1.47 mlelstv /* 827 1.47 mlelstv * scan all formats for entries with the correct pixel format 828 1.47 mlelstv * return entry number frmdesc->index 829 1.47 mlelstv */ 830 1.47 mlelstv index = 0; 831 1.47 mlelstv for (n=0; ;++n) { 832 1.47 mlelstv err = hw->enum_format(sc->hw_softc, n, &vfmt); 833 1.47 mlelstv if (err != 0) 834 1.47 mlelstv return err; 835 1.47 mlelstv 836 1.47 mlelstv video_format_to_v4l2_format(&vfmt, &fmt); 837 1.47 mlelstv if (fmt.fmt.pix.pixelformat != frmdesc->pixel_format) 838 1.47 mlelstv continue; 839 1.38 rjs 840 1.47 mlelstv if (index++ == frmdesc->index) 841 1.47 mlelstv break; 842 1.38 rjs } 843 1.39 riastrad 844 1.38 rjs frmdesc->type = V4L2_FRMSIZE_TYPE_DISCRETE; /* TODO: only one type for now */ 845 1.38 rjs frmdesc->discrete.width = vfmt.width; 846 1.38 rjs frmdesc->discrete.height = vfmt.height; 847 1.38 rjs return 0; 848 1.38 rjs } 849 1.38 rjs 850 1.38 rjs static int 851 1.38 rjs video_enum_frameival(struct video_softc *sc, struct v4l2_frmivalenum *frmdesc) 852 1.38 rjs { 853 1.38 rjs const struct video_hw_if *hw; 854 1.38 rjs 855 1.38 rjs hw = sc->hw_if; 856 1.38 rjs if (hw->enum_format == NULL) 857 1.38 rjs return ENOTTY; 858 1.38 rjs 859 1.38 rjs frmdesc->type = V4L2_FRMSIZE_TYPE_DISCRETE; 860 1.38 rjs frmdesc->discrete.numerator = 1; 861 1.38 rjs frmdesc->discrete.denominator = 15; 862 1.38 rjs return 0; 863 1.38 rjs } 864 1.38 rjs 865 1.38 rjs static int 866 1.1 jmcneill video_get_format(struct video_softc *sc, 867 1.1 jmcneill struct v4l2_format *format) 868 1.1 jmcneill { 869 1.1 jmcneill const struct video_hw_if *hw; 870 1.1 jmcneill struct video_format vfmt; 871 1.1 jmcneill int err; 872 1.1 jmcneill 873 1.1 jmcneill hw = sc->hw_if; 874 1.1 jmcneill if (hw->get_format == NULL) 875 1.3 jmcneill return ENOTTY; 876 1.1 jmcneill 877 1.1 jmcneill err = hw->get_format(sc->hw_softc, &vfmt); 878 1.1 jmcneill if (err != 0) 879 1.1 jmcneill return err; 880 1.1 jmcneill 881 1.1 jmcneill video_format_to_v4l2_format(&vfmt, format); 882 1.39 riastrad 883 1.1 jmcneill return 0; 884 1.1 jmcneill } 885 1.1 jmcneill 886 1.1 jmcneill static int 887 1.1 jmcneill video_set_format(struct video_softc *sc, struct v4l2_format *fmt) 888 1.1 jmcneill { 889 1.1 jmcneill const struct video_hw_if *hw; 890 1.1 jmcneill struct video_format vfmt; 891 1.1 jmcneill int err; 892 1.1 jmcneill 893 1.1 jmcneill hw = sc->hw_if; 894 1.20 jmcneill if (hw->set_format == NULL) 895 1.3 jmcneill return ENOTTY; 896 1.1 jmcneill 897 1.1 jmcneill v4l2_format_to_video_format(fmt, &vfmt); 898 1.1 jmcneill 899 1.1 jmcneill err = hw->set_format(sc->hw_softc, &vfmt); 900 1.1 jmcneill if (err != 0) 901 1.1 jmcneill return err; 902 1.1 jmcneill 903 1.1 jmcneill video_format_to_v4l2_format(&vfmt, fmt); 904 1.18 jmorse sc->sc_stream_in.vs_format = vfmt; 905 1.39 riastrad 906 1.1 jmcneill return 0; 907 1.1 jmcneill } 908 1.1 jmcneill 909 1.1 jmcneill 910 1.1 jmcneill static int 911 1.1 jmcneill video_try_format(struct video_softc *sc, 912 1.1 jmcneill struct v4l2_format *format) 913 1.1 jmcneill { 914 1.1 jmcneill const struct video_hw_if *hw; 915 1.1 jmcneill struct video_format vfmt; 916 1.1 jmcneill int err; 917 1.1 jmcneill 918 1.1 jmcneill hw = sc->hw_if; 919 1.1 jmcneill if (hw->try_format == NULL) 920 1.3 jmcneill return ENOTTY; 921 1.1 jmcneill 922 1.1 jmcneill v4l2_format_to_video_format(format, &vfmt); 923 1.1 jmcneill 924 1.1 jmcneill err = hw->try_format(sc->hw_softc, &vfmt); 925 1.1 jmcneill if (err != 0) 926 1.1 jmcneill return err; 927 1.1 jmcneill 928 1.1 jmcneill video_format_to_v4l2_format(&vfmt, format); 929 1.1 jmcneill 930 1.1 jmcneill return 0; 931 1.1 jmcneill } 932 1.1 jmcneill 933 1.37 jmcneill static int 934 1.37 jmcneill video_get_parm(struct video_softc *sc, struct v4l2_streamparm *parm) 935 1.37 jmcneill { 936 1.37 jmcneill struct video_fract fract; 937 1.37 jmcneill const struct video_hw_if *hw; 938 1.37 jmcneill int error; 939 1.37 jmcneill 940 1.37 jmcneill if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 941 1.37 jmcneill return EINVAL; 942 1.37 jmcneill 943 1.37 jmcneill hw = sc->hw_if; 944 1.37 jmcneill if (hw == NULL) 945 1.37 jmcneill return ENXIO; 946 1.37 jmcneill 947 1.37 jmcneill memset(&parm->parm, 0, sizeof(parm->parm)); 948 1.37 jmcneill if (hw->get_framerate != NULL) { 949 1.37 jmcneill error = hw->get_framerate(sc->hw_softc, &fract); 950 1.37 jmcneill if (error != 0) 951 1.37 jmcneill return error; 952 1.37 jmcneill parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 953 1.37 jmcneill parm->parm.capture.timeperframe.numerator = fract.numerator; 954 1.37 jmcneill parm->parm.capture.timeperframe.denominator = fract.denominator; 955 1.37 jmcneill } 956 1.37 jmcneill 957 1.37 jmcneill return 0; 958 1.37 jmcneill } 959 1.37 jmcneill 960 1.37 jmcneill static int 961 1.37 jmcneill video_set_parm(struct video_softc *sc, struct v4l2_streamparm *parm) 962 1.37 jmcneill { 963 1.37 jmcneill struct video_fract fract; 964 1.37 jmcneill const struct video_hw_if *hw; 965 1.37 jmcneill int error; 966 1.37 jmcneill 967 1.37 jmcneill if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 968 1.37 jmcneill return EINVAL; 969 1.37 jmcneill 970 1.37 jmcneill hw = sc->hw_if; 971 1.37 jmcneill if (hw == NULL || hw->set_framerate == NULL) 972 1.37 jmcneill return ENXIO; 973 1.37 jmcneill 974 1.37 jmcneill error = hw->set_framerate(sc->hw_softc, &fract); 975 1.37 jmcneill if (error != 0) 976 1.37 jmcneill return error; 977 1.37 jmcneill 978 1.37 jmcneill parm->parm.capture.timeperframe.numerator = fract.numerator; 979 1.37 jmcneill parm->parm.capture.timeperframe.denominator = fract.denominator; 980 1.37 jmcneill 981 1.37 jmcneill return 0; 982 1.37 jmcneill } 983 1.37 jmcneill 984 1.24 jmcneill static void 985 1.24 jmcneill v4l2_standard_to_video_standard(v4l2_std_id stdid, 986 1.24 jmcneill enum video_standard *vstd) 987 1.24 jmcneill { 988 1.24 jmcneill #define VSTD(id, vid) case (id): *vstd = (vid); break; 989 1.24 jmcneill switch (stdid) { 990 1.24 jmcneill VSTD(V4L2_STD_NTSC_M, VIDEO_STANDARD_NTSC_M) 991 1.24 jmcneill default: 992 1.24 jmcneill *vstd = VIDEO_STANDARD_UNKNOWN; 993 1.24 jmcneill break; 994 1.24 jmcneill } 995 1.24 jmcneill #undef VSTD 996 1.24 jmcneill } 997 1.24 jmcneill 998 1.24 jmcneill static void 999 1.24 jmcneill video_standard_to_v4l2_standard(enum video_standard vstd, 1000 1.24 jmcneill struct v4l2_standard *std) 1001 1.24 jmcneill { 1002 1.24 jmcneill switch (vstd) { 1003 1.24 jmcneill case VIDEO_STANDARD_NTSC_M: 1004 1.24 jmcneill std->id = V4L2_STD_NTSC_M; 1005 1.24 jmcneill strlcpy(std->name, "NTSC-M", sizeof(std->name)); 1006 1.24 jmcneill std->frameperiod.numerator = 1001; 1007 1.24 jmcneill std->frameperiod.denominator = 30000; 1008 1.24 jmcneill std->framelines = 525; 1009 1.24 jmcneill break; 1010 1.24 jmcneill default: 1011 1.24 jmcneill std->id = V4L2_STD_UNKNOWN; 1012 1.24 jmcneill strlcpy(std->name, "Unknown", sizeof(std->name)); 1013 1.24 jmcneill break; 1014 1.24 jmcneill } 1015 1.24 jmcneill } 1016 1.24 jmcneill 1017 1.24 jmcneill static int 1018 1.24 jmcneill video_enum_standard(struct video_softc *sc, struct v4l2_standard *std) 1019 1.24 jmcneill { 1020 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1021 1.24 jmcneill enum video_standard vstd; 1022 1.24 jmcneill int err; 1023 1.24 jmcneill 1024 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1025 1.24 jmcneill if (hw->enum_standard == NULL) { 1026 1.24 jmcneill if (std->index != 0) 1027 1.24 jmcneill return EINVAL; 1028 1.24 jmcneill std->id = V4L2_STD_UNKNOWN; 1029 1.24 jmcneill strlcpy(std->name, "webcam", sizeof(std->name)); 1030 1.24 jmcneill return 0; 1031 1.24 jmcneill } 1032 1.24 jmcneill 1033 1.24 jmcneill v4l2_standard_to_video_standard(std->id, &vstd); 1034 1.24 jmcneill 1035 1.24 jmcneill err = hw->enum_standard(sc->hw_softc, std->index, &vstd); 1036 1.24 jmcneill if (err != 0) 1037 1.24 jmcneill return err; 1038 1.24 jmcneill 1039 1.24 jmcneill video_standard_to_v4l2_standard(vstd, std); 1040 1.24 jmcneill 1041 1.24 jmcneill return 0; 1042 1.24 jmcneill } 1043 1.24 jmcneill 1044 1.24 jmcneill static int 1045 1.24 jmcneill video_get_standard(struct video_softc *sc, v4l2_std_id *stdid) 1046 1.24 jmcneill { 1047 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1048 1.24 jmcneill struct v4l2_standard std; 1049 1.24 jmcneill enum video_standard vstd; 1050 1.24 jmcneill int err; 1051 1.24 jmcneill 1052 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1053 1.24 jmcneill if (hw->get_standard == NULL) { 1054 1.24 jmcneill *stdid = V4L2_STD_UNKNOWN; 1055 1.24 jmcneill return 0; 1056 1.24 jmcneill } 1057 1.24 jmcneill 1058 1.24 jmcneill err = hw->get_standard(sc->hw_softc, &vstd); 1059 1.24 jmcneill if (err != 0) 1060 1.24 jmcneill return err; 1061 1.24 jmcneill 1062 1.24 jmcneill video_standard_to_v4l2_standard(vstd, &std); 1063 1.24 jmcneill *stdid = std.id; 1064 1.39 riastrad 1065 1.24 jmcneill return 0; 1066 1.24 jmcneill } 1067 1.24 jmcneill 1068 1.24 jmcneill static int 1069 1.24 jmcneill video_set_standard(struct video_softc *sc, v4l2_std_id stdid) 1070 1.24 jmcneill { 1071 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1072 1.24 jmcneill enum video_standard vstd; 1073 1.24 jmcneill 1074 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1075 1.24 jmcneill if (hw->set_standard == NULL) { 1076 1.24 jmcneill if (stdid != V4L2_STD_UNKNOWN) 1077 1.24 jmcneill return EINVAL; 1078 1.24 jmcneill return 0; 1079 1.24 jmcneill } 1080 1.24 jmcneill 1081 1.24 jmcneill v4l2_standard_to_video_standard(stdid, &vstd); 1082 1.24 jmcneill 1083 1.24 jmcneill return hw->set_standard(sc->hw_softc, vstd); 1084 1.24 jmcneill } 1085 1.24 jmcneill 1086 1.24 jmcneill static void 1087 1.24 jmcneill v4l2_input_to_video_input(const struct v4l2_input *input, 1088 1.24 jmcneill struct video_input *vi) 1089 1.24 jmcneill { 1090 1.24 jmcneill vi->index = input->index; 1091 1.24 jmcneill strlcpy(vi->name, input->name, sizeof(vi->name)); 1092 1.24 jmcneill switch (input->type) { 1093 1.24 jmcneill case V4L2_INPUT_TYPE_TUNER: 1094 1.24 jmcneill vi->type = VIDEO_INPUT_TYPE_TUNER; 1095 1.24 jmcneill break; 1096 1.24 jmcneill case V4L2_INPUT_TYPE_CAMERA: 1097 1.24 jmcneill vi->type = VIDEO_INPUT_TYPE_CAMERA; 1098 1.24 jmcneill break; 1099 1.24 jmcneill } 1100 1.24 jmcneill vi->audiomask = input->audioset; 1101 1.24 jmcneill vi->tuner_index = input->tuner; 1102 1.24 jmcneill vi->standards = input->std; /* ... values are the same */ 1103 1.24 jmcneill vi->status = 0; 1104 1.24 jmcneill if (input->status & V4L2_IN_ST_NO_POWER) 1105 1.24 jmcneill vi->status |= VIDEO_STATUS_NO_POWER; 1106 1.24 jmcneill if (input->status & V4L2_IN_ST_NO_SIGNAL) 1107 1.24 jmcneill vi->status |= VIDEO_STATUS_NO_SIGNAL; 1108 1.24 jmcneill if (input->status & V4L2_IN_ST_NO_COLOR) 1109 1.24 jmcneill vi->status |= VIDEO_STATUS_NO_COLOR; 1110 1.24 jmcneill if (input->status & V4L2_IN_ST_NO_H_LOCK) 1111 1.24 jmcneill vi->status |= VIDEO_STATUS_NO_HLOCK; 1112 1.24 jmcneill if (input->status & V4L2_IN_ST_MACROVISION) 1113 1.24 jmcneill vi->status |= VIDEO_STATUS_MACROVISION; 1114 1.24 jmcneill } 1115 1.24 jmcneill 1116 1.24 jmcneill static void 1117 1.24 jmcneill video_input_to_v4l2_input(const struct video_input *vi, 1118 1.24 jmcneill struct v4l2_input *input) 1119 1.24 jmcneill { 1120 1.24 jmcneill input->index = vi->index; 1121 1.24 jmcneill strlcpy(input->name, vi->name, sizeof(input->name)); 1122 1.24 jmcneill switch (vi->type) { 1123 1.24 jmcneill case VIDEO_INPUT_TYPE_TUNER: 1124 1.24 jmcneill input->type = V4L2_INPUT_TYPE_TUNER; 1125 1.24 jmcneill break; 1126 1.24 jmcneill case VIDEO_INPUT_TYPE_CAMERA: 1127 1.24 jmcneill input->type = V4L2_INPUT_TYPE_CAMERA; 1128 1.24 jmcneill break; 1129 1.24 jmcneill } 1130 1.24 jmcneill input->audioset = vi->audiomask; 1131 1.24 jmcneill input->tuner = vi->tuner_index; 1132 1.24 jmcneill input->std = vi->standards; /* ... values are the same */ 1133 1.24 jmcneill input->status = 0; 1134 1.24 jmcneill if (vi->status & VIDEO_STATUS_NO_POWER) 1135 1.24 jmcneill input->status |= V4L2_IN_ST_NO_POWER; 1136 1.24 jmcneill if (vi->status & VIDEO_STATUS_NO_SIGNAL) 1137 1.24 jmcneill input->status |= V4L2_IN_ST_NO_SIGNAL; 1138 1.24 jmcneill if (vi->status & VIDEO_STATUS_NO_COLOR) 1139 1.24 jmcneill input->status |= V4L2_IN_ST_NO_COLOR; 1140 1.24 jmcneill if (vi->status & VIDEO_STATUS_NO_HLOCK) 1141 1.24 jmcneill input->status |= V4L2_IN_ST_NO_H_LOCK; 1142 1.24 jmcneill if (vi->status & VIDEO_STATUS_MACROVISION) 1143 1.24 jmcneill input->status |= V4L2_IN_ST_MACROVISION; 1144 1.24 jmcneill } 1145 1.24 jmcneill 1146 1.24 jmcneill static int 1147 1.24 jmcneill video_enum_input(struct video_softc *sc, struct v4l2_input *input) 1148 1.24 jmcneill { 1149 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1150 1.24 jmcneill struct video_input vi; 1151 1.24 jmcneill int err; 1152 1.24 jmcneill 1153 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1154 1.24 jmcneill if (hw->enum_input == NULL) { 1155 1.24 jmcneill if (input->index != 0) 1156 1.24 jmcneill return EINVAL; 1157 1.24 jmcneill memset(input, 0, sizeof(*input)); 1158 1.24 jmcneill input->index = 0; 1159 1.24 jmcneill strlcpy(input->name, "Camera", sizeof(input->name)); 1160 1.24 jmcneill input->type = V4L2_INPUT_TYPE_CAMERA; 1161 1.24 jmcneill return 0; 1162 1.24 jmcneill } 1163 1.24 jmcneill 1164 1.24 jmcneill v4l2_input_to_video_input(input, &vi); 1165 1.24 jmcneill 1166 1.24 jmcneill err = hw->enum_input(sc->hw_softc, input->index, &vi); 1167 1.24 jmcneill if (err != 0) 1168 1.24 jmcneill return err; 1169 1.24 jmcneill 1170 1.24 jmcneill video_input_to_v4l2_input(&vi, input); 1171 1.24 jmcneill 1172 1.24 jmcneill return 0; 1173 1.24 jmcneill } 1174 1.24 jmcneill 1175 1.24 jmcneill static int 1176 1.24 jmcneill video_get_input(struct video_softc *sc, int *index) 1177 1.24 jmcneill { 1178 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1179 1.24 jmcneill struct video_input vi; 1180 1.24 jmcneill struct v4l2_input input; 1181 1.24 jmcneill int err; 1182 1.24 jmcneill 1183 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1184 1.24 jmcneill if (hw->get_input == NULL) { 1185 1.24 jmcneill *index = 0; 1186 1.24 jmcneill return 0; 1187 1.24 jmcneill } 1188 1.24 jmcneill 1189 1.24 jmcneill input.index = *index; 1190 1.24 jmcneill v4l2_input_to_video_input(&input, &vi); 1191 1.24 jmcneill 1192 1.24 jmcneill err = hw->get_input(sc->hw_softc, &vi); 1193 1.24 jmcneill if (err != 0) 1194 1.24 jmcneill return err; 1195 1.24 jmcneill 1196 1.24 jmcneill video_input_to_v4l2_input(&vi, &input); 1197 1.24 jmcneill *index = input.index; 1198 1.24 jmcneill 1199 1.24 jmcneill return 0; 1200 1.24 jmcneill } 1201 1.24 jmcneill 1202 1.24 jmcneill static int 1203 1.24 jmcneill video_set_input(struct video_softc *sc, int index) 1204 1.24 jmcneill { 1205 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1206 1.24 jmcneill struct video_input vi; 1207 1.24 jmcneill struct v4l2_input input; 1208 1.24 jmcneill 1209 1.24 jmcneill /* simple webcam drivers don't need to implement this callback */ 1210 1.24 jmcneill if (hw->set_input == NULL) { 1211 1.24 jmcneill if (index != 0) 1212 1.24 jmcneill return EINVAL; 1213 1.24 jmcneill return 0; 1214 1.24 jmcneill } 1215 1.24 jmcneill 1216 1.24 jmcneill input.index = index; 1217 1.24 jmcneill v4l2_input_to_video_input(&input, &vi); 1218 1.24 jmcneill 1219 1.24 jmcneill return hw->set_input(sc->hw_softc, &vi); 1220 1.24 jmcneill } 1221 1.24 jmcneill 1222 1.24 jmcneill static void 1223 1.24 jmcneill v4l2_audio_to_video_audio(const struct v4l2_audio *audio, 1224 1.24 jmcneill struct video_audio *va) 1225 1.24 jmcneill { 1226 1.24 jmcneill va->index = audio->index; 1227 1.24 jmcneill strlcpy(va->name, audio->name, sizeof(va->name)); 1228 1.24 jmcneill va->caps = va->mode = 0; 1229 1.24 jmcneill if (audio->capability & V4L2_AUDCAP_STEREO) 1230 1.24 jmcneill va->caps |= VIDEO_AUDIO_F_STEREO; 1231 1.24 jmcneill if (audio->capability & V4L2_AUDCAP_AVL) 1232 1.24 jmcneill va->caps |= VIDEO_AUDIO_F_AVL; 1233 1.24 jmcneill if (audio->mode & V4L2_AUDMODE_AVL) 1234 1.24 jmcneill va->mode |= VIDEO_AUDIO_F_AVL; 1235 1.24 jmcneill } 1236 1.24 jmcneill 1237 1.24 jmcneill static void 1238 1.24 jmcneill video_audio_to_v4l2_audio(const struct video_audio *va, 1239 1.24 jmcneill struct v4l2_audio *audio) 1240 1.24 jmcneill { 1241 1.24 jmcneill audio->index = va->index; 1242 1.24 jmcneill strlcpy(audio->name, va->name, sizeof(audio->name)); 1243 1.24 jmcneill audio->capability = audio->mode = 0; 1244 1.24 jmcneill if (va->caps & VIDEO_AUDIO_F_STEREO) 1245 1.24 jmcneill audio->capability |= V4L2_AUDCAP_STEREO; 1246 1.24 jmcneill if (va->caps & VIDEO_AUDIO_F_AVL) 1247 1.24 jmcneill audio->capability |= V4L2_AUDCAP_AVL; 1248 1.24 jmcneill if (va->mode & VIDEO_AUDIO_F_AVL) 1249 1.24 jmcneill audio->mode |= V4L2_AUDMODE_AVL; 1250 1.24 jmcneill } 1251 1.24 jmcneill 1252 1.24 jmcneill static int 1253 1.24 jmcneill video_enum_audio(struct video_softc *sc, struct v4l2_audio *audio) 1254 1.24 jmcneill { 1255 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1256 1.24 jmcneill struct video_audio va; 1257 1.24 jmcneill int err; 1258 1.24 jmcneill 1259 1.24 jmcneill if (hw->enum_audio == NULL) 1260 1.24 jmcneill return ENOTTY; 1261 1.24 jmcneill 1262 1.24 jmcneill v4l2_audio_to_video_audio(audio, &va); 1263 1.24 jmcneill 1264 1.24 jmcneill err = hw->enum_audio(sc->hw_softc, audio->index, &va); 1265 1.24 jmcneill if (err != 0) 1266 1.24 jmcneill return err; 1267 1.24 jmcneill 1268 1.24 jmcneill video_audio_to_v4l2_audio(&va, audio); 1269 1.24 jmcneill 1270 1.24 jmcneill return 0; 1271 1.24 jmcneill } 1272 1.24 jmcneill 1273 1.24 jmcneill static int 1274 1.24 jmcneill video_get_audio(struct video_softc *sc, struct v4l2_audio *audio) 1275 1.24 jmcneill { 1276 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1277 1.24 jmcneill struct video_audio va; 1278 1.24 jmcneill int err; 1279 1.24 jmcneill 1280 1.24 jmcneill if (hw->get_audio == NULL) 1281 1.24 jmcneill return ENOTTY; 1282 1.24 jmcneill 1283 1.24 jmcneill v4l2_audio_to_video_audio(audio, &va); 1284 1.24 jmcneill 1285 1.24 jmcneill err = hw->get_audio(sc->hw_softc, &va); 1286 1.24 jmcneill if (err != 0) 1287 1.24 jmcneill return err; 1288 1.24 jmcneill 1289 1.24 jmcneill video_audio_to_v4l2_audio(&va, audio); 1290 1.24 jmcneill 1291 1.24 jmcneill return 0; 1292 1.24 jmcneill } 1293 1.24 jmcneill 1294 1.24 jmcneill static int 1295 1.24 jmcneill video_set_audio(struct video_softc *sc, struct v4l2_audio *audio) 1296 1.24 jmcneill { 1297 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1298 1.24 jmcneill struct video_audio va; 1299 1.24 jmcneill 1300 1.24 jmcneill if (hw->set_audio == NULL) 1301 1.24 jmcneill return ENOTTY; 1302 1.24 jmcneill 1303 1.24 jmcneill v4l2_audio_to_video_audio(audio, &va); 1304 1.24 jmcneill 1305 1.24 jmcneill return hw->set_audio(sc->hw_softc, &va); 1306 1.24 jmcneill } 1307 1.24 jmcneill 1308 1.24 jmcneill static void 1309 1.24 jmcneill v4l2_tuner_to_video_tuner(const struct v4l2_tuner *tuner, 1310 1.24 jmcneill struct video_tuner *vt) 1311 1.24 jmcneill { 1312 1.24 jmcneill vt->index = tuner->index; 1313 1.24 jmcneill strlcpy(vt->name, tuner->name, sizeof(vt->name)); 1314 1.24 jmcneill vt->freq_lo = tuner->rangelow; 1315 1.24 jmcneill vt->freq_hi = tuner->rangehigh; 1316 1.24 jmcneill vt->signal = tuner->signal; 1317 1.24 jmcneill vt->afc = tuner->afc; 1318 1.24 jmcneill vt->caps = 0; 1319 1.24 jmcneill if (tuner->capability & V4L2_TUNER_CAP_STEREO) 1320 1.24 jmcneill vt->caps |= VIDEO_TUNER_F_STEREO; 1321 1.24 jmcneill if (tuner->capability & V4L2_TUNER_CAP_LANG1) 1322 1.24 jmcneill vt->caps |= VIDEO_TUNER_F_LANG1; 1323 1.24 jmcneill if (tuner->capability & V4L2_TUNER_CAP_LANG2) 1324 1.24 jmcneill vt->caps |= VIDEO_TUNER_F_LANG2; 1325 1.24 jmcneill switch (tuner->audmode) { 1326 1.24 jmcneill case V4L2_TUNER_MODE_MONO: 1327 1.24 jmcneill vt->mode = VIDEO_TUNER_F_MONO; 1328 1.24 jmcneill break; 1329 1.24 jmcneill case V4L2_TUNER_MODE_STEREO: 1330 1.24 jmcneill vt->mode = VIDEO_TUNER_F_STEREO; 1331 1.24 jmcneill break; 1332 1.24 jmcneill case V4L2_TUNER_MODE_LANG1: 1333 1.24 jmcneill vt->mode = VIDEO_TUNER_F_LANG1; 1334 1.24 jmcneill break; 1335 1.24 jmcneill case V4L2_TUNER_MODE_LANG2: 1336 1.24 jmcneill vt->mode = VIDEO_TUNER_F_LANG2; 1337 1.24 jmcneill break; 1338 1.24 jmcneill case V4L2_TUNER_MODE_LANG1_LANG2: 1339 1.24 jmcneill vt->mode = VIDEO_TUNER_F_LANG1 | VIDEO_TUNER_F_LANG2; 1340 1.24 jmcneill break; 1341 1.24 jmcneill } 1342 1.24 jmcneill } 1343 1.24 jmcneill 1344 1.24 jmcneill static void 1345 1.24 jmcneill video_tuner_to_v4l2_tuner(const struct video_tuner *vt, 1346 1.24 jmcneill struct v4l2_tuner *tuner) 1347 1.24 jmcneill { 1348 1.24 jmcneill tuner->index = vt->index; 1349 1.24 jmcneill strlcpy(tuner->name, vt->name, sizeof(tuner->name)); 1350 1.24 jmcneill tuner->rangelow = vt->freq_lo; 1351 1.24 jmcneill tuner->rangehigh = vt->freq_hi; 1352 1.24 jmcneill tuner->signal = vt->signal; 1353 1.24 jmcneill tuner->afc = vt->afc; 1354 1.24 jmcneill tuner->capability = 0; 1355 1.24 jmcneill if (vt->caps & VIDEO_TUNER_F_STEREO) 1356 1.24 jmcneill tuner->capability |= V4L2_TUNER_CAP_STEREO; 1357 1.24 jmcneill if (vt->caps & VIDEO_TUNER_F_LANG1) 1358 1.24 jmcneill tuner->capability |= V4L2_TUNER_CAP_LANG1; 1359 1.24 jmcneill if (vt->caps & VIDEO_TUNER_F_LANG2) 1360 1.24 jmcneill tuner->capability |= V4L2_TUNER_CAP_LANG2; 1361 1.24 jmcneill switch (vt->mode) { 1362 1.24 jmcneill case VIDEO_TUNER_F_MONO: 1363 1.24 jmcneill tuner->audmode = V4L2_TUNER_MODE_MONO; 1364 1.24 jmcneill break; 1365 1.24 jmcneill case VIDEO_TUNER_F_STEREO: 1366 1.24 jmcneill tuner->audmode = V4L2_TUNER_MODE_STEREO; 1367 1.24 jmcneill break; 1368 1.24 jmcneill case VIDEO_TUNER_F_LANG1: 1369 1.24 jmcneill tuner->audmode = V4L2_TUNER_MODE_LANG1; 1370 1.24 jmcneill break; 1371 1.24 jmcneill case VIDEO_TUNER_F_LANG2: 1372 1.24 jmcneill tuner->audmode = V4L2_TUNER_MODE_LANG2; 1373 1.24 jmcneill break; 1374 1.24 jmcneill case VIDEO_TUNER_F_LANG1|VIDEO_TUNER_F_LANG2: 1375 1.24 jmcneill tuner->audmode = V4L2_TUNER_MODE_LANG1_LANG2; 1376 1.24 jmcneill break; 1377 1.24 jmcneill } 1378 1.24 jmcneill } 1379 1.24 jmcneill 1380 1.24 jmcneill static int 1381 1.24 jmcneill video_get_tuner(struct video_softc *sc, struct v4l2_tuner *tuner) 1382 1.24 jmcneill { 1383 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1384 1.24 jmcneill struct video_tuner vt; 1385 1.24 jmcneill int err; 1386 1.24 jmcneill 1387 1.24 jmcneill if (hw->get_tuner == NULL) 1388 1.24 jmcneill return ENOTTY; 1389 1.24 jmcneill 1390 1.24 jmcneill v4l2_tuner_to_video_tuner(tuner, &vt); 1391 1.24 jmcneill 1392 1.24 jmcneill err = hw->get_tuner(sc->hw_softc, &vt); 1393 1.24 jmcneill if (err != 0) 1394 1.24 jmcneill return err; 1395 1.24 jmcneill 1396 1.24 jmcneill video_tuner_to_v4l2_tuner(&vt, tuner); 1397 1.24 jmcneill 1398 1.24 jmcneill return 0; 1399 1.24 jmcneill } 1400 1.24 jmcneill 1401 1.24 jmcneill static int 1402 1.24 jmcneill video_set_tuner(struct video_softc *sc, struct v4l2_tuner *tuner) 1403 1.24 jmcneill { 1404 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1405 1.24 jmcneill struct video_tuner vt; 1406 1.24 jmcneill 1407 1.24 jmcneill if (hw->set_tuner == NULL) 1408 1.24 jmcneill return ENOTTY; 1409 1.24 jmcneill 1410 1.24 jmcneill v4l2_tuner_to_video_tuner(tuner, &vt); 1411 1.24 jmcneill 1412 1.24 jmcneill return hw->set_tuner(sc->hw_softc, &vt); 1413 1.24 jmcneill } 1414 1.24 jmcneill 1415 1.24 jmcneill static int 1416 1.24 jmcneill video_get_frequency(struct video_softc *sc, struct v4l2_frequency *freq) 1417 1.24 jmcneill { 1418 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1419 1.24 jmcneill struct video_frequency vfreq; 1420 1.24 jmcneill int err; 1421 1.24 jmcneill 1422 1.24 jmcneill if (hw->get_frequency == NULL) 1423 1.24 jmcneill return ENOTTY; 1424 1.24 jmcneill 1425 1.24 jmcneill err = hw->get_frequency(sc->hw_softc, &vfreq); 1426 1.24 jmcneill if (err) 1427 1.24 jmcneill return err; 1428 1.24 jmcneill 1429 1.24 jmcneill freq->tuner = vfreq.tuner_index; 1430 1.24 jmcneill freq->type = V4L2_TUNER_ANALOG_TV; 1431 1.24 jmcneill freq->frequency = vfreq.frequency; 1432 1.24 jmcneill 1433 1.24 jmcneill return 0; 1434 1.24 jmcneill } 1435 1.24 jmcneill 1436 1.24 jmcneill static int 1437 1.24 jmcneill video_set_frequency(struct video_softc *sc, struct v4l2_frequency *freq) 1438 1.24 jmcneill { 1439 1.24 jmcneill const struct video_hw_if *hw = sc->hw_if; 1440 1.24 jmcneill struct video_frequency vfreq; 1441 1.26 jmcneill struct video_tuner vt; 1442 1.26 jmcneill int error; 1443 1.24 jmcneill 1444 1.26 jmcneill if (hw->set_frequency == NULL || hw->get_tuner == NULL) 1445 1.24 jmcneill return ENOTTY; 1446 1.24 jmcneill if (freq->type != V4L2_TUNER_ANALOG_TV) 1447 1.24 jmcneill return EINVAL; 1448 1.24 jmcneill 1449 1.26 jmcneill vt.index = freq->tuner; 1450 1.26 jmcneill error = hw->get_tuner(sc->hw_softc, &vt); 1451 1.26 jmcneill if (error) 1452 1.26 jmcneill return error; 1453 1.26 jmcneill 1454 1.26 jmcneill if (freq->frequency < vt.freq_lo) 1455 1.26 jmcneill freq->frequency = vt.freq_lo; 1456 1.26 jmcneill else if (freq->frequency > vt.freq_hi) 1457 1.26 jmcneill freq->frequency = vt.freq_hi; 1458 1.26 jmcneill 1459 1.24 jmcneill vfreq.tuner_index = freq->tuner; 1460 1.24 jmcneill vfreq.frequency = freq->frequency; 1461 1.24 jmcneill 1462 1.24 jmcneill return hw->set_frequency(sc->hw_softc, &vfreq); 1463 1.24 jmcneill } 1464 1.24 jmcneill 1465 1.1 jmcneill /* Takes a single Video4Linux2 control, converts it to a struct 1466 1.1 jmcneill * video_control, and calls the hardware driver. */ 1467 1.1 jmcneill static int 1468 1.1 jmcneill video_set_control(struct video_softc *sc, 1469 1.1 jmcneill const struct v4l2_control *vcontrol) 1470 1.1 jmcneill { 1471 1.1 jmcneill const struct video_hw_if *hw; 1472 1.1 jmcneill struct video_control_group group; 1473 1.1 jmcneill struct video_control control; 1474 1.1 jmcneill 1475 1.1 jmcneill hw = sc->hw_if; 1476 1.1 jmcneill if (hw->set_control_group) { 1477 1.1 jmcneill control.group_id = control.control_id = 1478 1.1 jmcneill v4l2id_to_control_id(vcontrol->id); 1479 1.1 jmcneill /* ?? if "control_id" is arbitrarily defined by the 1480 1.1 jmcneill * driver, then we need some way to store it... Maybe 1481 1.1 jmcneill * it doesn't matter for single value controls. */ 1482 1.1 jmcneill control.value = vcontrol->value; 1483 1.1 jmcneill 1484 1.1 jmcneill group.group_id = control.group_id; 1485 1.1 jmcneill group.length = 1; 1486 1.1 jmcneill group.control = &control; 1487 1.39 riastrad 1488 1.1 jmcneill return (hw->set_control_group(sc->hw_softc, &group)); 1489 1.1 jmcneill } else { 1490 1.1 jmcneill return EINVAL; 1491 1.1 jmcneill } 1492 1.1 jmcneill } 1493 1.1 jmcneill 1494 1.1 jmcneill static int 1495 1.1 jmcneill video_request_bufs(struct video_softc *sc, 1496 1.1 jmcneill struct v4l2_requestbuffers *req) 1497 1.1 jmcneill { 1498 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1499 1.1 jmcneill struct v4l2_buffer *buf; 1500 1.1 jmcneill int i, err; 1501 1.1 jmcneill 1502 1.1 jmcneill if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 1503 1.1 jmcneill return EINVAL; 1504 1.1 jmcneill 1505 1.1 jmcneill vs->vs_type = req->type; 1506 1.1 jmcneill 1507 1.1 jmcneill switch (req->memory) { 1508 1.1 jmcneill case V4L2_MEMORY_MMAP: 1509 1.1 jmcneill if (req->count < VIDEO_MIN_BUFS) 1510 1.1 jmcneill req->count = VIDEO_MIN_BUFS; 1511 1.1 jmcneill else if (req->count > VIDEO_MAX_BUFS) 1512 1.1 jmcneill req->count = VIDEO_MAX_BUFS; 1513 1.1 jmcneill 1514 1.1 jmcneill err = video_stream_setup_bufs(vs, 1515 1.1 jmcneill VIDEO_STREAM_METHOD_MMAP, 1516 1.1 jmcneill req->count); 1517 1.1 jmcneill if (err != 0) 1518 1.1 jmcneill return err; 1519 1.1 jmcneill 1520 1.1 jmcneill for (i = 0; i < req->count; ++i) { 1521 1.1 jmcneill buf = vs->vs_buf[i]->vb_buf; 1522 1.1 jmcneill buf->memory = V4L2_MEMORY_MMAP; 1523 1.1 jmcneill buf->flags |= V4L2_BUF_FLAG_MAPPED; 1524 1.1 jmcneill } 1525 1.1 jmcneill break; 1526 1.1 jmcneill case V4L2_MEMORY_USERPTR: 1527 1.1 jmcneill default: 1528 1.1 jmcneill return EINVAL; 1529 1.1 jmcneill } 1530 1.1 jmcneill 1531 1.1 jmcneill return 0; 1532 1.1 jmcneill } 1533 1.1 jmcneill 1534 1.1 jmcneill static int 1535 1.1 jmcneill video_query_buf(struct video_softc *sc, 1536 1.1 jmcneill struct v4l2_buffer *buf) 1537 1.1 jmcneill { 1538 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1539 1.1 jmcneill 1540 1.1 jmcneill if (buf->type != vs->vs_type) 1541 1.1 jmcneill return EINVAL; 1542 1.1 jmcneill if (buf->index >= vs->vs_nbufs) 1543 1.1 jmcneill return EINVAL; 1544 1.39 riastrad 1545 1.1 jmcneill memcpy(buf, vs->vs_buf[buf->index]->vb_buf, sizeof(*buf)); 1546 1.1 jmcneill 1547 1.1 jmcneill return 0; 1548 1.1 jmcneill } 1549 1.1 jmcneill 1550 1.1 jmcneill /* Accept a buffer descriptor from userspace and return the indicated 1551 1.1 jmcneill * buffer to the driver's queue. */ 1552 1.1 jmcneill static int 1553 1.1 jmcneill video_queue_buf(struct video_softc *sc, struct v4l2_buffer *userbuf) 1554 1.1 jmcneill { 1555 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1556 1.1 jmcneill struct video_buffer *vb; 1557 1.1 jmcneill struct v4l2_buffer *driverbuf; 1558 1.39 riastrad 1559 1.1 jmcneill if (userbuf->type != vs->vs_type) { 1560 1.1 jmcneill DPRINTF(("video_queue_buf: expected type=%d got type=%d\n", 1561 1.1 jmcneill userbuf->type, vs->vs_type)); 1562 1.1 jmcneill return EINVAL; 1563 1.1 jmcneill } 1564 1.1 jmcneill if (userbuf->index >= vs->vs_nbufs) { 1565 1.1 jmcneill DPRINTF(("video_queue_buf: invalid index %d >= %d\n", 1566 1.1 jmcneill userbuf->index, vs->vs_nbufs)); 1567 1.1 jmcneill return EINVAL; 1568 1.1 jmcneill } 1569 1.1 jmcneill 1570 1.1 jmcneill switch (vs->vs_method) { 1571 1.1 jmcneill case VIDEO_STREAM_METHOD_MMAP: 1572 1.1 jmcneill if (userbuf->memory != V4L2_MEMORY_MMAP) { 1573 1.1 jmcneill DPRINTF(("video_queue_buf: invalid memory=%d\n", 1574 1.1 jmcneill userbuf->memory)); 1575 1.1 jmcneill return EINVAL; 1576 1.1 jmcneill } 1577 1.39 riastrad 1578 1.1 jmcneill mutex_enter(&vs->vs_lock); 1579 1.39 riastrad 1580 1.1 jmcneill vb = vs->vs_buf[userbuf->index]; 1581 1.1 jmcneill driverbuf = vb->vb_buf; 1582 1.1 jmcneill if (driverbuf->flags & V4L2_BUF_FLAG_QUEUED) { 1583 1.1 jmcneill DPRINTF(("video_queue_buf: buf already queued; " 1584 1.1 jmcneill "flags=0x%x\n", driverbuf->flags)); 1585 1.1 jmcneill mutex_exit(&vs->vs_lock); 1586 1.1 jmcneill return EINVAL; 1587 1.1 jmcneill } 1588 1.1 jmcneill video_stream_enqueue(vs, vb); 1589 1.1 jmcneill memcpy(userbuf, driverbuf, sizeof(*driverbuf)); 1590 1.39 riastrad 1591 1.1 jmcneill mutex_exit(&vs->vs_lock); 1592 1.1 jmcneill break; 1593 1.1 jmcneill default: 1594 1.1 jmcneill return EINVAL; 1595 1.1 jmcneill } 1596 1.1 jmcneill 1597 1.1 jmcneill return 0; 1598 1.1 jmcneill } 1599 1.1 jmcneill 1600 1.1 jmcneill /* Dequeue the described buffer from the driver queue, making it 1601 1.1 jmcneill * available for reading via mmap. */ 1602 1.1 jmcneill static int 1603 1.1 jmcneill video_dequeue_buf(struct video_softc *sc, struct v4l2_buffer *buf) 1604 1.1 jmcneill { 1605 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1606 1.1 jmcneill struct video_buffer *vb; 1607 1.1 jmcneill int err; 1608 1.39 riastrad 1609 1.15 jmcneill if (buf->type != vs->vs_type) { 1610 1.15 jmcneill aprint_debug_dev(sc->sc_dev, 1611 1.15 jmcneill "requested type %d (expected %d)\n", 1612 1.15 jmcneill buf->type, vs->vs_type); 1613 1.1 jmcneill return EINVAL; 1614 1.15 jmcneill } 1615 1.39 riastrad 1616 1.1 jmcneill switch (vs->vs_method) { 1617 1.1 jmcneill case VIDEO_STREAM_METHOD_MMAP: 1618 1.15 jmcneill if (buf->memory != V4L2_MEMORY_MMAP) { 1619 1.15 jmcneill aprint_debug_dev(sc->sc_dev, 1620 1.15 jmcneill "requested memory %d (expected %d)\n", 1621 1.15 jmcneill buf->memory, V4L2_MEMORY_MMAP); 1622 1.1 jmcneill return EINVAL; 1623 1.15 jmcneill } 1624 1.39 riastrad 1625 1.1 jmcneill mutex_enter(&vs->vs_lock); 1626 1.1 jmcneill 1627 1.1 jmcneill if (vs->vs_flags & O_NONBLOCK) { 1628 1.1 jmcneill vb = video_stream_dequeue(vs); 1629 1.1 jmcneill if (vb == NULL) { 1630 1.1 jmcneill mutex_exit(&vs->vs_lock); 1631 1.1 jmcneill return EAGAIN; 1632 1.1 jmcneill } 1633 1.1 jmcneill } else { 1634 1.1 jmcneill /* Block until we have sample */ 1635 1.1 jmcneill while ((vb = video_stream_dequeue(vs)) == NULL) { 1636 1.19 drochner if (!vs->vs_streaming) { 1637 1.19 drochner mutex_exit(&vs->vs_lock); 1638 1.19 drochner return EINVAL; 1639 1.19 drochner } 1640 1.1 jmcneill err = cv_wait_sig(&vs->vs_sample_cv, 1641 1.1 jmcneill &vs->vs_lock); 1642 1.1 jmcneill if (err != 0) { 1643 1.1 jmcneill mutex_exit(&vs->vs_lock); 1644 1.1 jmcneill return EINTR; 1645 1.1 jmcneill } 1646 1.1 jmcneill } 1647 1.1 jmcneill } 1648 1.1 jmcneill 1649 1.1 jmcneill memcpy(buf, vb->vb_buf, sizeof(*buf)); 1650 1.39 riastrad 1651 1.1 jmcneill mutex_exit(&vs->vs_lock); 1652 1.1 jmcneill break; 1653 1.1 jmcneill default: 1654 1.15 jmcneill aprint_debug_dev(sc->sc_dev, "unknown vs_method %d\n", 1655 1.15 jmcneill vs->vs_method); 1656 1.1 jmcneill return EINVAL; 1657 1.1 jmcneill } 1658 1.1 jmcneill 1659 1.1 jmcneill return 0; 1660 1.1 jmcneill } 1661 1.1 jmcneill 1662 1.1 jmcneill static int 1663 1.1 jmcneill video_stream_on(struct video_softc *sc, enum v4l2_buf_type type) 1664 1.1 jmcneill { 1665 1.1 jmcneill int err; 1666 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1667 1.1 jmcneill const struct video_hw_if *hw; 1668 1.39 riastrad 1669 1.1 jmcneill if (vs->vs_streaming) 1670 1.1 jmcneill return 0; 1671 1.1 jmcneill if (type != vs->vs_type) 1672 1.1 jmcneill return EINVAL; 1673 1.1 jmcneill 1674 1.1 jmcneill hw = sc->hw_if; 1675 1.1 jmcneill if (hw == NULL) 1676 1.1 jmcneill return ENXIO; 1677 1.1 jmcneill 1678 1.1 jmcneill 1679 1.1 jmcneill err = hw->start_transfer(sc->hw_softc); 1680 1.1 jmcneill if (err != 0) 1681 1.1 jmcneill return err; 1682 1.1 jmcneill 1683 1.1 jmcneill vs->vs_streaming = true; 1684 1.1 jmcneill return 0; 1685 1.1 jmcneill } 1686 1.1 jmcneill 1687 1.1 jmcneill static int 1688 1.1 jmcneill video_stream_off(struct video_softc *sc, enum v4l2_buf_type type) 1689 1.1 jmcneill { 1690 1.1 jmcneill int err; 1691 1.1 jmcneill struct video_stream *vs = &sc->sc_stream_in; 1692 1.1 jmcneill const struct video_hw_if *hw; 1693 1.39 riastrad 1694 1.1 jmcneill if (!vs->vs_streaming) 1695 1.1 jmcneill return 0; 1696 1.1 jmcneill if (type != vs->vs_type) 1697 1.1 jmcneill return EINVAL; 1698 1.1 jmcneill 1699 1.1 jmcneill hw = sc->hw_if; 1700 1.1 jmcneill if (hw == NULL) 1701 1.1 jmcneill return ENXIO; 1702 1.1 jmcneill 1703 1.1 jmcneill err = hw->stop_transfer(sc->hw_softc); 1704 1.1 jmcneill if (err != 0) 1705 1.1 jmcneill return err; 1706 1.1 jmcneill 1707 1.1 jmcneill vs->vs_frameno = -1; 1708 1.1 jmcneill vs->vs_sequence = 0; 1709 1.1 jmcneill vs->vs_streaming = false; 1710 1.39 riastrad 1711 1.1 jmcneill return 0; 1712 1.1 jmcneill } 1713 1.1 jmcneill 1714 1.1 jmcneill int 1715 1.1 jmcneill videoopen(dev_t dev, int flags, int ifmt, struct lwp *l) 1716 1.1 jmcneill { 1717 1.1 jmcneill struct video_softc *sc; 1718 1.1 jmcneill const struct video_hw_if *hw; 1719 1.1 jmcneill struct video_stream *vs; 1720 1.1 jmcneill int err; 1721 1.1 jmcneill 1722 1.1 jmcneill DPRINTF(("videoopen\n")); 1723 1.1 jmcneill 1724 1.1 jmcneill sc = device_private(device_lookup(&video_cd, VIDEOUNIT(dev))); 1725 1.1 jmcneill if (sc == NULL) { 1726 1.29 prlw1 DPRINTF(("videoopen: failed to get softc for unit %d\n", 1727 1.29 prlw1 VIDEOUNIT(dev))); 1728 1.1 jmcneill return ENXIO; 1729 1.1 jmcneill } 1730 1.39 riastrad 1731 1.1 jmcneill if (sc->sc_dying) { 1732 1.1 jmcneill DPRINTF(("videoopen: dying\n")); 1733 1.1 jmcneill return EIO; 1734 1.1 jmcneill } 1735 1.1 jmcneill 1736 1.1 jmcneill sc->sc_stream_in.vs_flags = flags; 1737 1.1 jmcneill 1738 1.1 jmcneill DPRINTF(("videoopen: flags=0x%x sc=%p parent=%p\n", 1739 1.1 jmcneill flags, sc, sc->hw_dev)); 1740 1.1 jmcneill 1741 1.1 jmcneill hw = sc->hw_if; 1742 1.1 jmcneill if (hw == NULL) 1743 1.1 jmcneill return ENXIO; 1744 1.1 jmcneill 1745 1.1 jmcneill device_active(sc->sc_dev, DVA_SYSTEM); 1746 1.1 jmcneill 1747 1.1 jmcneill sc->sc_opencnt++; 1748 1.1 jmcneill 1749 1.1 jmcneill if (hw->open != NULL) { 1750 1.1 jmcneill err = hw->open(sc->hw_softc, flags); 1751 1.1 jmcneill if (err) 1752 1.1 jmcneill return err; 1753 1.1 jmcneill } 1754 1.1 jmcneill 1755 1.1 jmcneill /* set up input stream. TODO: check flags to determine if 1756 1.1 jmcneill * "read" is desired? */ 1757 1.1 jmcneill vs = &sc->sc_stream_in; 1758 1.1 jmcneill 1759 1.15 jmcneill if (hw->get_format != NULL) { 1760 1.15 jmcneill err = hw->get_format(sc->hw_softc, &vs->vs_format); 1761 1.1 jmcneill if (err != 0) 1762 1.1 jmcneill return err; 1763 1.1 jmcneill } 1764 1.1 jmcneill return 0; 1765 1.1 jmcneill } 1766 1.1 jmcneill 1767 1.1 jmcneill 1768 1.1 jmcneill int 1769 1.1 jmcneill videoclose(dev_t dev, int flags, int ifmt, struct lwp *l) 1770 1.1 jmcneill { 1771 1.1 jmcneill struct video_softc *sc; 1772 1.1 jmcneill const struct video_hw_if *hw; 1773 1.1 jmcneill 1774 1.1 jmcneill sc = device_private(device_lookup(&video_cd, VIDEOUNIT(dev))); 1775 1.1 jmcneill if (sc == NULL) 1776 1.1 jmcneill return ENXIO; 1777 1.1 jmcneill 1778 1.1 jmcneill DPRINTF(("videoclose: sc=%p\n", sc)); 1779 1.1 jmcneill 1780 1.1 jmcneill hw = sc->hw_if; 1781 1.1 jmcneill if (hw == NULL) 1782 1.1 jmcneill return ENXIO; 1783 1.1 jmcneill 1784 1.1 jmcneill device_active(sc->sc_dev, DVA_SYSTEM); 1785 1.1 jmcneill 1786 1.1 jmcneill video_stream_off(sc, sc->sc_stream_in.vs_type); 1787 1.1 jmcneill 1788 1.1 jmcneill /* ignore error */ 1789 1.1 jmcneill if (hw->close != NULL) 1790 1.1 jmcneill hw->close(sc->hw_softc); 1791 1.1 jmcneill 1792 1.1 jmcneill video_stream_teardown_bufs(&sc->sc_stream_in); 1793 1.39 riastrad 1794 1.1 jmcneill sc->sc_open = 0; 1795 1.1 jmcneill sc->sc_opencnt--; 1796 1.39 riastrad 1797 1.1 jmcneill return 0; 1798 1.1 jmcneill } 1799 1.1 jmcneill 1800 1.1 jmcneill 1801 1.1 jmcneill int 1802 1.1 jmcneill videoread(dev_t dev, struct uio *uio, int ioflag) 1803 1.1 jmcneill { 1804 1.1 jmcneill struct video_softc *sc; 1805 1.1 jmcneill struct video_stream *vs; 1806 1.1 jmcneill struct video_buffer *vb; 1807 1.1 jmcneill struct scatter_io sio; 1808 1.1 jmcneill int err; 1809 1.46 mlelstv size_t len, done; 1810 1.1 jmcneill off_t offset; 1811 1.1 jmcneill 1812 1.1 jmcneill sc = device_private(device_lookup(&video_cd, VIDEOUNIT(dev))); 1813 1.1 jmcneill if (sc == NULL) 1814 1.1 jmcneill return ENXIO; 1815 1.1 jmcneill 1816 1.1 jmcneill if (sc->sc_dying) 1817 1.1 jmcneill return EIO; 1818 1.1 jmcneill 1819 1.1 jmcneill vs = &sc->sc_stream_in; 1820 1.1 jmcneill 1821 1.1 jmcneill /* userspace has chosen read() method */ 1822 1.1 jmcneill if (vs->vs_method == VIDEO_STREAM_METHOD_NONE) { 1823 1.1 jmcneill err = video_stream_setup_bufs(vs, 1824 1.1 jmcneill VIDEO_STREAM_METHOD_READ, 1825 1.1 jmcneill VIDEO_NUM_BUFS); 1826 1.1 jmcneill if (err != 0) 1827 1.1 jmcneill return err; 1828 1.1 jmcneill 1829 1.1 jmcneill err = video_stream_on(sc, vs->vs_type); 1830 1.1 jmcneill if (err != 0) 1831 1.1 jmcneill return err; 1832 1.1 jmcneill } else if (vs->vs_method != VIDEO_STREAM_METHOD_READ) { 1833 1.1 jmcneill return EBUSY; 1834 1.1 jmcneill } 1835 1.1 jmcneill 1836 1.1 jmcneill mutex_enter(&vs->vs_lock); 1837 1.39 riastrad 1838 1.1 jmcneill retry: 1839 1.1 jmcneill if (SIMPLEQ_EMPTY(&vs->vs_egress)) { 1840 1.1 jmcneill if (vs->vs_flags & O_NONBLOCK) { 1841 1.1 jmcneill mutex_exit(&vs->vs_lock); 1842 1.1 jmcneill return EAGAIN; 1843 1.1 jmcneill } 1844 1.39 riastrad 1845 1.1 jmcneill /* Block until we have a sample */ 1846 1.1 jmcneill while (SIMPLEQ_EMPTY(&vs->vs_egress)) { 1847 1.1 jmcneill err = cv_wait_sig(&vs->vs_sample_cv, 1848 1.1 jmcneill &vs->vs_lock); 1849 1.1 jmcneill if (err != 0) { 1850 1.1 jmcneill mutex_exit(&vs->vs_lock); 1851 1.1 jmcneill return EINTR; 1852 1.1 jmcneill } 1853 1.1 jmcneill } 1854 1.1 jmcneill 1855 1.1 jmcneill vb = SIMPLEQ_FIRST(&vs->vs_egress); 1856 1.1 jmcneill } else { 1857 1.1 jmcneill vb = SIMPLEQ_FIRST(&vs->vs_egress); 1858 1.1 jmcneill } 1859 1.1 jmcneill 1860 1.1 jmcneill /* Oops, empty sample buffer. */ 1861 1.1 jmcneill if (vb->vb_buf->bytesused == 0) { 1862 1.1 jmcneill vb = video_stream_dequeue(vs); 1863 1.1 jmcneill video_stream_enqueue(vs, vb); 1864 1.1 jmcneill vs->vs_bytesread = 0; 1865 1.1 jmcneill goto retry; 1866 1.1 jmcneill } 1867 1.1 jmcneill 1868 1.46 mlelstv if (vb->busy) { 1869 1.46 mlelstv if (vs->vs_flags & O_NONBLOCK) { 1870 1.46 mlelstv mutex_exit(&vs->vs_lock); 1871 1.46 mlelstv return EAGAIN; 1872 1.46 mlelstv } 1873 1.46 mlelstv 1874 1.46 mlelstv while (vb->busy > 0) { 1875 1.46 mlelstv err = cv_wait_sig(&vs->vs_sample_cv, &vs->vs_lock); 1876 1.46 mlelstv if (err != 0) { 1877 1.46 mlelstv mutex_exit(&vs->vs_lock); 1878 1.46 mlelstv return EINTR; 1879 1.46 mlelstv } 1880 1.46 mlelstv } 1881 1.46 mlelstv } 1882 1.46 mlelstv 1883 1.46 mlelstv vb->busy++; 1884 1.39 riastrad 1885 1.35 riastrad len = uimin(uio->uio_resid, vb->vb_buf->bytesused - vs->vs_bytesread); 1886 1.1 jmcneill offset = vb->vb_buf->m.offset + vs->vs_bytesread; 1887 1.1 jmcneill 1888 1.46 mlelstv mutex_exit(&vs->vs_lock); 1889 1.46 mlelstv 1890 1.46 mlelstv done = 0; 1891 1.1 jmcneill if (scatter_io_init(&vs->vs_data, offset, len, &sio)) { 1892 1.1 jmcneill err = scatter_io_uiomove(&sio, uio); 1893 1.1 jmcneill if (err == EFAULT) 1894 1.1 jmcneill return EFAULT; 1895 1.46 mlelstv done = len - sio.sio_resid; 1896 1.1 jmcneill } else { 1897 1.1 jmcneill DPRINTF(("video: invalid read\n")); 1898 1.1 jmcneill } 1899 1.39 riastrad 1900 1.1 jmcneill /* Move the sample to the ingress queue if everything has 1901 1.1 jmcneill * been read */ 1902 1.46 mlelstv mutex_enter(&vs->vs_lock); 1903 1.46 mlelstv 1904 1.46 mlelstv if (--vb->busy <= 0) 1905 1.46 mlelstv cv_signal(&vs->vs_sample_cv); 1906 1.46 mlelstv 1907 1.46 mlelstv vs->vs_bytesread += done; 1908 1.1 jmcneill if (vs->vs_bytesread >= vb->vb_buf->bytesused) { 1909 1.1 jmcneill vb = video_stream_dequeue(vs); 1910 1.1 jmcneill video_stream_enqueue(vs, vb); 1911 1.1 jmcneill vs->vs_bytesread = 0; 1912 1.1 jmcneill } 1913 1.1 jmcneill 1914 1.46 mlelstv mutex_exit(&vs->vs_lock); 1915 1.46 mlelstv 1916 1.1 jmcneill return 0; 1917 1.1 jmcneill } 1918 1.1 jmcneill 1919 1.1 jmcneill 1920 1.1 jmcneill int 1921 1.1 jmcneill videowrite(dev_t dev, struct uio *uio, int ioflag) 1922 1.1 jmcneill { 1923 1.1 jmcneill return ENXIO; 1924 1.1 jmcneill } 1925 1.1 jmcneill 1926 1.1 jmcneill 1927 1.27 jakllsch /* 1928 1.27 jakllsch * Before 64-bit time_t, timeval's tv_sec was 'long'. Thus on LP64 ports 1929 1.27 jakllsch * v4l2_buffer is the same size and layout as before. However it did change 1930 1.27 jakllsch * on LP32 ports, and we thus handle this difference here for "COMPAT_50". 1931 1.27 jakllsch */ 1932 1.27 jakllsch 1933 1.27 jakllsch #ifndef _LP64 1934 1.22 christos static void 1935 1.27 jakllsch buf50tobuf(const void *data, struct v4l2_buffer *buf) 1936 1.22 christos { 1937 1.27 jakllsch const struct v4l2_buffer50 *b50 = data; 1938 1.22 christos 1939 1.27 jakllsch buf->index = b50->index; 1940 1.27 jakllsch buf->type = b50->type; 1941 1.27 jakllsch buf->bytesused = b50->bytesused; 1942 1.27 jakllsch buf->flags = b50->flags; 1943 1.27 jakllsch buf->field = b50->field; 1944 1.27 jakllsch timeval50_to_timeval(&b50->timestamp, &buf->timestamp); 1945 1.27 jakllsch buf->timecode = b50->timecode; 1946 1.27 jakllsch buf->sequence = b50->sequence; 1947 1.27 jakllsch buf->memory = b50->memory; 1948 1.27 jakllsch buf->m.offset = b50->m.offset; 1949 1.22 christos /* XXX: Handle userptr */ 1950 1.27 jakllsch buf->length = b50->length; 1951 1.38 rjs buf->reserved2 = b50->reserved2; 1952 1.27 jakllsch buf->reserved = b50->reserved; 1953 1.22 christos } 1954 1.22 christos 1955 1.22 christos static void 1956 1.27 jakllsch buftobuf50(void *data, const struct v4l2_buffer *buf) 1957 1.22 christos { 1958 1.27 jakllsch struct v4l2_buffer50 *b50 = data; 1959 1.22 christos 1960 1.27 jakllsch b50->index = buf->index; 1961 1.27 jakllsch b50->type = buf->type; 1962 1.27 jakllsch b50->bytesused = buf->bytesused; 1963 1.27 jakllsch b50->flags = buf->flags; 1964 1.27 jakllsch b50->field = buf->field; 1965 1.27 jakllsch timeval_to_timeval50(&buf->timestamp, &b50->timestamp); 1966 1.27 jakllsch b50->timecode = buf->timecode; 1967 1.27 jakllsch b50->sequence = buf->sequence; 1968 1.27 jakllsch b50->memory = buf->memory; 1969 1.27 jakllsch b50->m.offset = buf->m.offset; 1970 1.22 christos /* XXX: Handle userptr */ 1971 1.27 jakllsch b50->length = buf->length; 1972 1.38 rjs b50->reserved2 = buf->reserved2; 1973 1.27 jakllsch b50->reserved = buf->reserved; 1974 1.22 christos } 1975 1.27 jakllsch #endif 1976 1.22 christos 1977 1.1 jmcneill int 1978 1.1 jmcneill videoioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 1979 1.1 jmcneill { 1980 1.1 jmcneill struct video_softc *sc; 1981 1.1 jmcneill const struct video_hw_if *hw; 1982 1.1 jmcneill struct v4l2_capability *cap; 1983 1.1 jmcneill struct v4l2_fmtdesc *fmtdesc; 1984 1.1 jmcneill struct v4l2_format *fmt; 1985 1.1 jmcneill struct v4l2_standard *std; 1986 1.1 jmcneill struct v4l2_input *input; 1987 1.24 jmcneill struct v4l2_audio *audio; 1988 1.24 jmcneill struct v4l2_tuner *tuner; 1989 1.24 jmcneill struct v4l2_frequency *freq; 1990 1.1 jmcneill struct v4l2_control *control; 1991 1.1 jmcneill struct v4l2_queryctrl *query; 1992 1.1 jmcneill struct v4l2_requestbuffers *reqbufs; 1993 1.27 jakllsch struct v4l2_buffer *buf; 1994 1.37 jmcneill struct v4l2_streamparm *parm; 1995 1.38 rjs struct v4l2_frmsizeenum *size; 1996 1.38 rjs struct v4l2_frmivalenum *ival; 1997 1.1 jmcneill v4l2_std_id *stdid; 1998 1.1 jmcneill enum v4l2_buf_type *typep; 1999 1.27 jakllsch int *ip; 2000 1.27 jakllsch #ifndef _LP64 2001 1.27 jakllsch struct v4l2_buffer bufspace; 2002 1.27 jakllsch int error; 2003 1.27 jakllsch #endif 2004 1.1 jmcneill 2005 1.1 jmcneill sc = device_private(device_lookup(&video_cd, VIDEOUNIT(dev))); 2006 1.1 jmcneill 2007 1.1 jmcneill if (sc->sc_dying) 2008 1.1 jmcneill return EIO; 2009 1.1 jmcneill 2010 1.1 jmcneill hw = sc->hw_if; 2011 1.1 jmcneill if (hw == NULL) 2012 1.1 jmcneill return ENXIO; 2013 1.1 jmcneill 2014 1.1 jmcneill switch (cmd) { 2015 1.1 jmcneill case VIDIOC_QUERYCAP: 2016 1.1 jmcneill cap = data; 2017 1.1 jmcneill memset(cap, 0, sizeof(*cap)); 2018 1.25 jmcneill strlcpy(cap->driver, 2019 1.25 jmcneill device_cfdriver(sc->hw_dev)->cd_name, 2020 1.1 jmcneill sizeof(cap->driver)); 2021 1.1 jmcneill strlcpy(cap->card, hw->get_devname(sc->hw_softc), 2022 1.1 jmcneill sizeof(cap->card)); 2023 1.25 jmcneill strlcpy(cap->bus_info, hw->get_businfo(sc->hw_softc), 2024 1.25 jmcneill sizeof(cap->bus_info)); 2025 1.1 jmcneill cap->version = VIDEO_DRIVER_VERSION; 2026 1.1 jmcneill cap->capabilities = 0; 2027 1.1 jmcneill if (hw->start_transfer != NULL && hw->stop_transfer != NULL) 2028 1.1 jmcneill cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | 2029 1.1 jmcneill V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; 2030 1.24 jmcneill if (hw->set_tuner != NULL && hw->get_tuner != NULL) 2031 1.24 jmcneill cap->capabilities |= V4L2_CAP_TUNER; 2032 1.24 jmcneill if (hw->set_audio != NULL && hw->get_audio != NULL && 2033 1.24 jmcneill hw->enum_audio != NULL) 2034 1.24 jmcneill cap->capabilities |= V4L2_CAP_AUDIO; 2035 1.1 jmcneill return 0; 2036 1.1 jmcneill case VIDIOC_ENUM_FMT: 2037 1.1 jmcneill /* TODO: for now, just enumerate one default format */ 2038 1.1 jmcneill fmtdesc = data; 2039 1.1 jmcneill if (fmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 2040 1.1 jmcneill return EINVAL; 2041 1.1 jmcneill return video_enum_format(sc, fmtdesc); 2042 1.1 jmcneill case VIDIOC_G_FMT: 2043 1.1 jmcneill fmt = data; 2044 1.24 jmcneill return video_get_format(sc, fmt); 2045 1.1 jmcneill case VIDIOC_S_FMT: 2046 1.1 jmcneill fmt = data; 2047 1.1 jmcneill if ((flag & FWRITE) == 0) 2048 1.1 jmcneill return EPERM; 2049 1.1 jmcneill return video_set_format(sc, fmt); 2050 1.1 jmcneill case VIDIOC_TRY_FMT: 2051 1.1 jmcneill fmt = data; 2052 1.24 jmcneill return video_try_format(sc, fmt); 2053 1.37 jmcneill case VIDIOC_G_PARM: 2054 1.37 jmcneill parm = data; 2055 1.37 jmcneill return video_get_parm(sc, parm); 2056 1.37 jmcneill case VIDIOC_S_PARM: 2057 1.37 jmcneill parm = data; 2058 1.37 jmcneill if ((flag & FWRITE) == 0) 2059 1.37 jmcneill return EPERM; 2060 1.37 jmcneill return video_set_parm(sc, parm); 2061 1.1 jmcneill case VIDIOC_ENUMSTD: 2062 1.1 jmcneill std = data; 2063 1.24 jmcneill return video_enum_standard(sc, std); 2064 1.1 jmcneill case VIDIOC_G_STD: 2065 1.1 jmcneill stdid = data; 2066 1.24 jmcneill return video_get_standard(sc, stdid); 2067 1.1 jmcneill case VIDIOC_S_STD: 2068 1.1 jmcneill stdid = data; 2069 1.24 jmcneill if ((flag & FWRITE) == 0) 2070 1.24 jmcneill return EPERM; 2071 1.24 jmcneill return video_set_standard(sc, *stdid); 2072 1.1 jmcneill case VIDIOC_ENUMINPUT: 2073 1.1 jmcneill input = data; 2074 1.24 jmcneill return video_enum_input(sc, input); 2075 1.1 jmcneill case VIDIOC_G_INPUT: 2076 1.1 jmcneill ip = data; 2077 1.24 jmcneill return video_get_input(sc, ip); 2078 1.1 jmcneill case VIDIOC_S_INPUT: 2079 1.1 jmcneill ip = data; 2080 1.24 jmcneill if ((flag & FWRITE) == 0) 2081 1.24 jmcneill return EPERM; 2082 1.24 jmcneill return video_set_input(sc, *ip); 2083 1.24 jmcneill case VIDIOC_ENUMAUDIO: 2084 1.24 jmcneill audio = data; 2085 1.24 jmcneill return video_enum_audio(sc, audio); 2086 1.24 jmcneill case VIDIOC_G_AUDIO: 2087 1.24 jmcneill audio = data; 2088 1.24 jmcneill return video_get_audio(sc, audio); 2089 1.24 jmcneill case VIDIOC_S_AUDIO: 2090 1.24 jmcneill audio = data; 2091 1.24 jmcneill if ((flag & FWRITE) == 0) 2092 1.24 jmcneill return EPERM; 2093 1.24 jmcneill return video_set_audio(sc, audio); 2094 1.24 jmcneill case VIDIOC_G_TUNER: 2095 1.24 jmcneill tuner = data; 2096 1.24 jmcneill return video_get_tuner(sc, tuner); 2097 1.24 jmcneill case VIDIOC_S_TUNER: 2098 1.24 jmcneill tuner = data; 2099 1.24 jmcneill if ((flag & FWRITE) == 0) 2100 1.24 jmcneill return EPERM; 2101 1.24 jmcneill return video_set_tuner(sc, tuner); 2102 1.24 jmcneill case VIDIOC_G_FREQUENCY: 2103 1.24 jmcneill freq = data; 2104 1.24 jmcneill return video_get_frequency(sc, freq); 2105 1.24 jmcneill case VIDIOC_S_FREQUENCY: 2106 1.24 jmcneill freq = data; 2107 1.24 jmcneill if ((flag & FWRITE) == 0) 2108 1.24 jmcneill return EPERM; 2109 1.24 jmcneill return video_set_frequency(sc, freq); 2110 1.1 jmcneill case VIDIOC_QUERYCTRL: 2111 1.1 jmcneill query = data; 2112 1.1 jmcneill return (video_query_control(sc, query)); 2113 1.1 jmcneill case VIDIOC_G_CTRL: 2114 1.1 jmcneill control = data; 2115 1.1 jmcneill return (video_get_control(sc, control)); 2116 1.1 jmcneill case VIDIOC_S_CTRL: 2117 1.1 jmcneill control = data; 2118 1.1 jmcneill if ((flag & FWRITE) == 0) 2119 1.1 jmcneill return EPERM; 2120 1.1 jmcneill return (video_set_control(sc, control)); 2121 1.1 jmcneill case VIDIOC_REQBUFS: 2122 1.1 jmcneill reqbufs = data; 2123 1.1 jmcneill return (video_request_bufs(sc, reqbufs)); 2124 1.1 jmcneill case VIDIOC_QUERYBUF: 2125 1.1 jmcneill buf = data; 2126 1.1 jmcneill return video_query_buf(sc, buf); 2127 1.27 jakllsch #ifndef _LP64 2128 1.27 jakllsch case VIDIOC_QUERYBUF50: 2129 1.27 jakllsch buf50tobuf(data, buf = &bufspace); 2130 1.22 christos if ((error = video_query_buf(sc, buf)) != 0) 2131 1.22 christos return error; 2132 1.27 jakllsch buftobuf50(data, buf); 2133 1.22 christos return 0; 2134 1.27 jakllsch #endif 2135 1.1 jmcneill case VIDIOC_QBUF: 2136 1.1 jmcneill buf = data; 2137 1.1 jmcneill return video_queue_buf(sc, buf); 2138 1.27 jakllsch #ifndef _LP64 2139 1.27 jakllsch case VIDIOC_QBUF50: 2140 1.27 jakllsch buf50tobuf(data, buf = &bufspace); 2141 1.22 christos return video_queue_buf(sc, buf); 2142 1.27 jakllsch #endif 2143 1.1 jmcneill case VIDIOC_DQBUF: 2144 1.1 jmcneill buf = data; 2145 1.1 jmcneill return video_dequeue_buf(sc, buf); 2146 1.27 jakllsch #ifndef _LP64 2147 1.27 jakllsch case VIDIOC_DQBUF50: 2148 1.27 jakllsch buf50tobuf(data, buf = &bufspace); 2149 1.22 christos if ((error = video_dequeue_buf(sc, buf)) != 0) 2150 1.22 christos return error; 2151 1.27 jakllsch buftobuf50(data, buf); 2152 1.22 christos return 0; 2153 1.27 jakllsch #endif 2154 1.1 jmcneill case VIDIOC_STREAMON: 2155 1.1 jmcneill typep = data; 2156 1.1 jmcneill return video_stream_on(sc, *typep); 2157 1.1 jmcneill case VIDIOC_STREAMOFF: 2158 1.1 jmcneill typep = data; 2159 1.1 jmcneill return video_stream_off(sc, *typep); 2160 1.38 rjs case VIDIOC_ENUM_FRAMESIZES: 2161 1.38 rjs size = data; 2162 1.38 rjs return video_enum_framesizes(sc, size); 2163 1.38 rjs case VIDIOC_ENUM_FRAMEINTERVALS: 2164 1.38 rjs ival = data; 2165 1.38 rjs return video_enum_frameival(sc, ival); 2166 1.1 jmcneill default: 2167 1.1 jmcneill DPRINTF(("videoioctl: invalid cmd %s (%lx)\n", 2168 1.1 jmcneill video_ioctl_str(cmd), cmd)); 2169 1.4 jmcneill return EINVAL; 2170 1.1 jmcneill } 2171 1.1 jmcneill } 2172 1.1 jmcneill 2173 1.1 jmcneill #ifdef VIDEO_DEBUG 2174 1.1 jmcneill static const char * 2175 1.1 jmcneill video_ioctl_str(u_long cmd) 2176 1.1 jmcneill { 2177 1.1 jmcneill const char *str; 2178 1.39 riastrad 2179 1.1 jmcneill switch (cmd) { 2180 1.1 jmcneill case VIDIOC_QUERYCAP: 2181 1.1 jmcneill str = "VIDIOC_QUERYCAP"; 2182 1.1 jmcneill break; 2183 1.1 jmcneill case VIDIOC_RESERVED: 2184 1.1 jmcneill str = "VIDIOC_RESERVED"; 2185 1.1 jmcneill break; 2186 1.1 jmcneill case VIDIOC_ENUM_FMT: 2187 1.1 jmcneill str = "VIDIOC_ENUM_FMT"; 2188 1.1 jmcneill break; 2189 1.1 jmcneill case VIDIOC_G_FMT: 2190 1.1 jmcneill str = "VIDIOC_G_FMT"; 2191 1.1 jmcneill break; 2192 1.1 jmcneill case VIDIOC_S_FMT: 2193 1.1 jmcneill str = "VIDIOC_S_FMT"; 2194 1.1 jmcneill break; 2195 1.1 jmcneill /* 6 and 7 are VIDIOC_[SG]_COMP, which are unsupported */ 2196 1.1 jmcneill case VIDIOC_REQBUFS: 2197 1.1 jmcneill str = "VIDIOC_REQBUFS"; 2198 1.1 jmcneill break; 2199 1.1 jmcneill case VIDIOC_QUERYBUF: 2200 1.1 jmcneill str = "VIDIOC_QUERYBUF"; 2201 1.1 jmcneill break; 2202 1.27 jakllsch #ifndef _LP64 2203 1.27 jakllsch case VIDIOC_QUERYBUF50: 2204 1.27 jakllsch str = "VIDIOC_QUERYBUF50"; 2205 1.22 christos break; 2206 1.27 jakllsch #endif 2207 1.1 jmcneill case VIDIOC_G_FBUF: 2208 1.1 jmcneill str = "VIDIOC_G_FBUF"; 2209 1.1 jmcneill break; 2210 1.1 jmcneill case VIDIOC_S_FBUF: 2211 1.1 jmcneill str = "VIDIOC_S_FBUF"; 2212 1.1 jmcneill break; 2213 1.1 jmcneill case VIDIOC_OVERLAY: 2214 1.1 jmcneill str = "VIDIOC_OVERLAY"; 2215 1.1 jmcneill break; 2216 1.1 jmcneill case VIDIOC_QBUF: 2217 1.1 jmcneill str = "VIDIOC_QBUF"; 2218 1.1 jmcneill break; 2219 1.27 jakllsch #ifndef _LP64 2220 1.27 jakllsch case VIDIOC_QBUF50: 2221 1.27 jakllsch str = "VIDIOC_QBUF50"; 2222 1.22 christos break; 2223 1.27 jakllsch #endif 2224 1.1 jmcneill case VIDIOC_DQBUF: 2225 1.1 jmcneill str = "VIDIOC_DQBUF"; 2226 1.1 jmcneill break; 2227 1.27 jakllsch #ifndef _LP64 2228 1.27 jakllsch case VIDIOC_DQBUF50: 2229 1.27 jakllsch str = "VIDIOC_DQBUF50"; 2230 1.22 christos break; 2231 1.27 jakllsch #endif 2232 1.1 jmcneill case VIDIOC_STREAMON: 2233 1.1 jmcneill str = "VIDIOC_STREAMON"; 2234 1.1 jmcneill break; 2235 1.1 jmcneill case VIDIOC_STREAMOFF: 2236 1.1 jmcneill str = "VIDIOC_STREAMOFF"; 2237 1.1 jmcneill break; 2238 1.1 jmcneill case VIDIOC_G_PARM: 2239 1.38 rjs str = "VIDIOC_G_PARM"; 2240 1.1 jmcneill break; 2241 1.1 jmcneill case VIDIOC_S_PARM: 2242 1.38 rjs str = "VIDIOC_S_PARM"; 2243 1.1 jmcneill break; 2244 1.1 jmcneill case VIDIOC_G_STD: 2245 1.1 jmcneill str = "VIDIOC_G_STD"; 2246 1.1 jmcneill break; 2247 1.1 jmcneill case VIDIOC_S_STD: 2248 1.1 jmcneill str = "VIDIOC_S_STD"; 2249 1.1 jmcneill break; 2250 1.1 jmcneill case VIDIOC_ENUMSTD: 2251 1.1 jmcneill str = "VIDIOC_ENUMSTD"; 2252 1.1 jmcneill break; 2253 1.1 jmcneill case VIDIOC_ENUMINPUT: 2254 1.1 jmcneill str = "VIDIOC_ENUMINPUT"; 2255 1.1 jmcneill break; 2256 1.1 jmcneill case VIDIOC_G_CTRL: 2257 1.1 jmcneill str = "VIDIOC_G_CTRL"; 2258 1.1 jmcneill break; 2259 1.1 jmcneill case VIDIOC_S_CTRL: 2260 1.1 jmcneill str = "VIDIOC_S_CTRL"; 2261 1.1 jmcneill break; 2262 1.1 jmcneill case VIDIOC_G_TUNER: 2263 1.1 jmcneill str = "VIDIOC_G_TUNER"; 2264 1.1 jmcneill break; 2265 1.1 jmcneill case VIDIOC_S_TUNER: 2266 1.1 jmcneill str = "VIDIOC_S_TUNER"; 2267 1.1 jmcneill break; 2268 1.1 jmcneill case VIDIOC_G_AUDIO: 2269 1.1 jmcneill str = "VIDIOC_G_AUDIO"; 2270 1.1 jmcneill break; 2271 1.1 jmcneill case VIDIOC_S_AUDIO: 2272 1.1 jmcneill str = "VIDIOC_S_AUDIO"; 2273 1.1 jmcneill break; 2274 1.1 jmcneill case VIDIOC_QUERYCTRL: 2275 1.1 jmcneill str = "VIDIOC_QUERYCTRL"; 2276 1.1 jmcneill break; 2277 1.1 jmcneill case VIDIOC_QUERYMENU: 2278 1.1 jmcneill str = "VIDIOC_QUERYMENU"; 2279 1.1 jmcneill break; 2280 1.1 jmcneill case VIDIOC_G_INPUT: 2281 1.1 jmcneill str = "VIDIOC_G_INPUT"; 2282 1.1 jmcneill break; 2283 1.1 jmcneill case VIDIOC_S_INPUT: 2284 1.1 jmcneill str = "VIDIOC_S_INPUT"; 2285 1.1 jmcneill break; 2286 1.1 jmcneill case VIDIOC_G_OUTPUT: 2287 1.1 jmcneill str = "VIDIOC_G_OUTPUT"; 2288 1.1 jmcneill break; 2289 1.1 jmcneill case VIDIOC_S_OUTPUT: 2290 1.1 jmcneill str = "VIDIOC_S_OUTPUT"; 2291 1.1 jmcneill break; 2292 1.1 jmcneill case VIDIOC_ENUMOUTPUT: 2293 1.1 jmcneill str = "VIDIOC_ENUMOUTPUT"; 2294 1.1 jmcneill break; 2295 1.1 jmcneill case VIDIOC_G_AUDOUT: 2296 1.1 jmcneill str = "VIDIOC_G_AUDOUT"; 2297 1.1 jmcneill break; 2298 1.1 jmcneill case VIDIOC_S_AUDOUT: 2299 1.1 jmcneill str = "VIDIOC_S_AUDOUT"; 2300 1.1 jmcneill break; 2301 1.1 jmcneill case VIDIOC_G_MODULATOR: 2302 1.1 jmcneill str = "VIDIOC_G_MODULATOR"; 2303 1.1 jmcneill break; 2304 1.1 jmcneill case VIDIOC_S_MODULATOR: 2305 1.1 jmcneill str = "VIDIOC_S_MODULATOR"; 2306 1.1 jmcneill break; 2307 1.1 jmcneill case VIDIOC_G_FREQUENCY: 2308 1.1 jmcneill str = "VIDIOC_G_FREQUENCY"; 2309 1.1 jmcneill break; 2310 1.1 jmcneill case VIDIOC_S_FREQUENCY: 2311 1.1 jmcneill str = "VIDIOC_S_FREQUENCY"; 2312 1.1 jmcneill break; 2313 1.1 jmcneill case VIDIOC_CROPCAP: 2314 1.1 jmcneill str = "VIDIOC_CROPCAP"; 2315 1.1 jmcneill break; 2316 1.1 jmcneill case VIDIOC_G_CROP: 2317 1.1 jmcneill str = "VIDIOC_G_CROP"; 2318 1.1 jmcneill break; 2319 1.1 jmcneill case VIDIOC_S_CROP: 2320 1.1 jmcneill str = "VIDIOC_S_CROP"; 2321 1.1 jmcneill break; 2322 1.1 jmcneill case VIDIOC_G_JPEGCOMP: 2323 1.1 jmcneill str = "VIDIOC_G_JPEGCOMP"; 2324 1.1 jmcneill break; 2325 1.1 jmcneill case VIDIOC_S_JPEGCOMP: 2326 1.1 jmcneill str = "VIDIOC_S_JPEGCOMP"; 2327 1.1 jmcneill break; 2328 1.1 jmcneill case VIDIOC_QUERYSTD: 2329 1.1 jmcneill str = "VIDIOC_QUERYSTD"; 2330 1.1 jmcneill break; 2331 1.1 jmcneill case VIDIOC_TRY_FMT: 2332 1.1 jmcneill str = "VIDIOC_TRY_FMT"; 2333 1.1 jmcneill break; 2334 1.1 jmcneill case VIDIOC_ENUMAUDIO: 2335 1.1 jmcneill str = "VIDIOC_ENUMAUDIO"; 2336 1.1 jmcneill break; 2337 1.1 jmcneill case VIDIOC_ENUMAUDOUT: 2338 1.1 jmcneill str = "VIDIOC_ENUMAUDOUT"; 2339 1.1 jmcneill break; 2340 1.1 jmcneill case VIDIOC_G_PRIORITY: 2341 1.1 jmcneill str = "VIDIOC_G_PRIORITY"; 2342 1.1 jmcneill break; 2343 1.1 jmcneill case VIDIOC_S_PRIORITY: 2344 1.1 jmcneill str = "VIDIOC_S_PRIORITY"; 2345 1.1 jmcneill break; 2346 1.38 rjs case VIDIOC_ENUM_FRAMESIZES: 2347 1.38 rjs str = "VIDIOC_ENUM_FRAMESIZES"; 2348 1.38 rjs break; 2349 1.38 rjs case VIDIOC_ENUM_FRAMEINTERVALS: 2350 1.38 rjs str = "VIDIOC_FRAMEINTERVALS"; 2351 1.38 rjs break; 2352 1.1 jmcneill default: 2353 1.1 jmcneill str = "unknown"; 2354 1.1 jmcneill break; 2355 1.1 jmcneill } 2356 1.1 jmcneill return str; 2357 1.1 jmcneill } 2358 1.1 jmcneill #endif 2359 1.1 jmcneill 2360 1.1 jmcneill 2361 1.1 jmcneill int 2362 1.1 jmcneill videopoll(dev_t dev, int events, struct lwp *l) 2363 1.1 jmcneill { 2364 1.1 jmcneill struct video_softc *sc; 2365 1.1 jmcneill struct video_stream *vs; 2366 1.1 jmcneill int err, revents = 0; 2367 1.1 jmcneill 2368 1.1 jmcneill sc = device_private(device_lookup(&video_cd, VIDEOUNIT(dev))); 2369 1.1 jmcneill vs = &sc->sc_stream_in; 2370 1.1 jmcneill 2371 1.1 jmcneill if (sc->sc_dying) 2372 1.1 jmcneill return (POLLHUP); 2373 1.1 jmcneill 2374 1.1 jmcneill /* userspace has chosen read() method */ 2375 1.1 jmcneill if (vs->vs_method == VIDEO_STREAM_METHOD_NONE) { 2376 1.1 jmcneill err = video_stream_setup_bufs(vs, 2377 1.1 jmcneill VIDEO_STREAM_METHOD_READ, 2378 1.1 jmcneill VIDEO_NUM_BUFS); 2379 1.1 jmcneill if (err != 0) 2380 1.1 jmcneill return POLLERR; 2381 1.1 jmcneill 2382 1.1 jmcneill err = video_stream_on(sc, vs->vs_type); 2383 1.1 jmcneill if (err != 0) 2384 1.1 jmcneill return POLLERR; 2385 1.1 jmcneill } 2386 1.1 jmcneill 2387 1.19 drochner mutex_enter(&vs->vs_lock); 2388 1.1 jmcneill if (!SIMPLEQ_EMPTY(&sc->sc_stream_in.vs_egress)) 2389 1.1 jmcneill revents |= events & (POLLIN | POLLRDNORM); 2390 1.7 jmcneill else 2391 1.7 jmcneill selrecord(l, &vs->vs_sel); 2392 1.19 drochner mutex_exit(&vs->vs_lock); 2393 1.1 jmcneill 2394 1.1 jmcneill return (revents); 2395 1.1 jmcneill } 2396 1.1 jmcneill 2397 1.1 jmcneill 2398 1.1 jmcneill paddr_t 2399 1.1 jmcneill videommap(dev_t dev, off_t off, int prot) 2400 1.1 jmcneill { 2401 1.1 jmcneill struct video_softc *sc; 2402 1.1 jmcneill struct video_stream *vs; 2403 1.1 jmcneill /* paddr_t pa; */ 2404 1.1 jmcneill 2405 1.1 jmcneill sc = device_lookup_private(&video_cd, VIDEOUNIT(dev)); 2406 1.1 jmcneill if (sc->sc_dying) 2407 1.1 jmcneill return -1; 2408 1.1 jmcneill 2409 1.1 jmcneill vs = &sc->sc_stream_in; 2410 1.39 riastrad 2411 1.1 jmcneill return scatter_buf_map(&vs->vs_data, off); 2412 1.1 jmcneill } 2413 1.1 jmcneill 2414 1.1 jmcneill 2415 1.43 andvar /* Allocates buffers and initializes some fields. The format field 2416 1.1 jmcneill * must already have been initialized. */ 2417 1.1 jmcneill void 2418 1.48 mlelstv video_stream_init(struct video_stream *vs, const char *name) 2419 1.1 jmcneill { 2420 1.1 jmcneill vs->vs_method = VIDEO_STREAM_METHOD_NONE; 2421 1.1 jmcneill vs->vs_flags = 0; 2422 1.1 jmcneill vs->vs_frameno = -1; 2423 1.1 jmcneill vs->vs_sequence = 0; 2424 1.1 jmcneill vs->vs_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2425 1.1 jmcneill vs->vs_nbufs = 0; 2426 1.1 jmcneill vs->vs_buf = NULL; 2427 1.1 jmcneill vs->vs_streaming = false; 2428 1.39 riastrad 2429 1.1 jmcneill memset(&vs->vs_format, 0, sizeof(vs->vs_format)); 2430 1.39 riastrad 2431 1.1 jmcneill SIMPLEQ_INIT(&vs->vs_ingress); 2432 1.1 jmcneill SIMPLEQ_INIT(&vs->vs_egress); 2433 1.1 jmcneill 2434 1.1 jmcneill mutex_init(&vs->vs_lock, MUTEX_DEFAULT, IPL_NONE); 2435 1.48 mlelstv cv_init(&vs->vs_sample_cv, name); 2436 1.7 jmcneill selinit(&vs->vs_sel); 2437 1.1 jmcneill 2438 1.48 mlelstv scatter_buf_init(&vs->vs_data, name); 2439 1.1 jmcneill } 2440 1.1 jmcneill 2441 1.1 jmcneill void 2442 1.1 jmcneill video_stream_fini(struct video_stream *vs) 2443 1.1 jmcneill { 2444 1.1 jmcneill /* Sample data in queues has already been freed */ 2445 1.1 jmcneill /* while (SIMPLEQ_FIRST(&vs->vs_ingress) != NULL) 2446 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_ingress, entries); 2447 1.1 jmcneill while (SIMPLEQ_FIRST(&vs->vs_egress) != NULL) 2448 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_egress, entries); */ 2449 1.39 riastrad 2450 1.1 jmcneill mutex_destroy(&vs->vs_lock); 2451 1.1 jmcneill cv_destroy(&vs->vs_sample_cv); 2452 1.7 jmcneill seldestroy(&vs->vs_sel); 2453 1.1 jmcneill 2454 1.1 jmcneill scatter_buf_destroy(&vs->vs_data); 2455 1.1 jmcneill } 2456 1.1 jmcneill 2457 1.1 jmcneill static int 2458 1.1 jmcneill video_stream_setup_bufs(struct video_stream *vs, 2459 1.1 jmcneill enum video_stream_method method, 2460 1.1 jmcneill uint8_t nbufs) 2461 1.1 jmcneill { 2462 1.1 jmcneill int i, err; 2463 1.39 riastrad 2464 1.1 jmcneill mutex_enter(&vs->vs_lock); 2465 1.1 jmcneill 2466 1.1 jmcneill /* Ensure that all allocated buffers are queued and not under 2467 1.1 jmcneill * userspace control. */ 2468 1.1 jmcneill for (i = 0; i < vs->vs_nbufs; ++i) { 2469 1.19 drochner if (!(vs->vs_buf[i]->vb_buf->flags & V4L2_BUF_FLAG_QUEUED)) { 2470 1.1 jmcneill mutex_exit(&vs->vs_lock); 2471 1.1 jmcneill return EBUSY; 2472 1.1 jmcneill } 2473 1.1 jmcneill } 2474 1.1 jmcneill 2475 1.1 jmcneill /* Allocate the buffers */ 2476 1.1 jmcneill err = video_stream_realloc_bufs(vs, nbufs); 2477 1.1 jmcneill if (err != 0) { 2478 1.1 jmcneill mutex_exit(&vs->vs_lock); 2479 1.1 jmcneill return err; 2480 1.1 jmcneill } 2481 1.1 jmcneill 2482 1.1 jmcneill /* Queue up buffers for read method. Other methods are queued 2483 1.1 jmcneill * by VIDIOC_QBUF ioctl. */ 2484 1.1 jmcneill if (method == VIDEO_STREAM_METHOD_READ) { 2485 1.1 jmcneill for (i = 0; i < nbufs; ++i) 2486 1.1 jmcneill if (!(vs->vs_buf[i]->vb_buf->flags & V4L2_BUF_FLAG_QUEUED)) 2487 1.1 jmcneill video_stream_enqueue(vs, vs->vs_buf[i]); 2488 1.1 jmcneill } 2489 1.1 jmcneill 2490 1.1 jmcneill vs->vs_method = method; 2491 1.1 jmcneill mutex_exit(&vs->vs_lock); 2492 1.39 riastrad 2493 1.1 jmcneill return 0; 2494 1.1 jmcneill } 2495 1.1 jmcneill 2496 1.1 jmcneill /* Free all buffer memory in preparation for close(). This should 2497 1.1 jmcneill * free buffers regardless of errors. Use video_stream_setup_bufs if 2498 1.1 jmcneill * you need to check for errors. Streaming should be off before 2499 1.1 jmcneill * calling this function. */ 2500 1.1 jmcneill static void 2501 1.1 jmcneill video_stream_teardown_bufs(struct video_stream *vs) 2502 1.1 jmcneill { 2503 1.1 jmcneill int err; 2504 1.1 jmcneill 2505 1.1 jmcneill mutex_enter(&vs->vs_lock); 2506 1.1 jmcneill 2507 1.2 rmind if (vs->vs_streaming) { 2508 1.1 jmcneill DPRINTF(("video_stream_teardown_bufs: " 2509 1.1 jmcneill "tearing down bufs while streaming\n")); 2510 1.2 rmind } 2511 1.1 jmcneill 2512 1.1 jmcneill /* dequeue all buffers */ 2513 1.1 jmcneill while (SIMPLEQ_FIRST(&vs->vs_ingress) != NULL) 2514 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_ingress, entries); 2515 1.1 jmcneill while (SIMPLEQ_FIRST(&vs->vs_egress) != NULL) 2516 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_egress, entries); 2517 1.39 riastrad 2518 1.1 jmcneill err = video_stream_free_bufs(vs); 2519 1.2 rmind if (err != 0) { 2520 1.1 jmcneill DPRINTF(("video_stream_teardown_bufs: " 2521 1.1 jmcneill "error releasing buffers: %d\n", 2522 1.1 jmcneill err)); 2523 1.2 rmind } 2524 1.1 jmcneill vs->vs_method = VIDEO_STREAM_METHOD_NONE; 2525 1.1 jmcneill 2526 1.1 jmcneill mutex_exit(&vs->vs_lock); 2527 1.1 jmcneill } 2528 1.1 jmcneill 2529 1.1 jmcneill static struct video_buffer * 2530 1.1 jmcneill video_buffer_alloc(void) 2531 1.1 jmcneill { 2532 1.1 jmcneill struct video_buffer *vb; 2533 1.1 jmcneill 2534 1.1 jmcneill vb = kmem_alloc(sizeof(*vb), KM_SLEEP); 2535 1.1 jmcneill vb->vb_buf = kmem_alloc(sizeof(*vb->vb_buf), KM_SLEEP); 2536 1.1 jmcneill return vb; 2537 1.1 jmcneill } 2538 1.1 jmcneill 2539 1.1 jmcneill static void 2540 1.1 jmcneill video_buffer_free(struct video_buffer *vb) 2541 1.1 jmcneill { 2542 1.1 jmcneill kmem_free(vb->vb_buf, sizeof(*vb->vb_buf)); 2543 1.1 jmcneill vb->vb_buf = NULL; 2544 1.1 jmcneill kmem_free(vb, sizeof(*vb)); 2545 1.1 jmcneill } 2546 1.1 jmcneill 2547 1.1 jmcneill /* TODO: for userptr method 2548 1.1 jmcneill struct video_buffer * 2549 1.1 jmcneill video_buf_alloc_with_ubuf(struct v4l2_buffer *buf) 2550 1.1 jmcneill { 2551 1.1 jmcneill } 2552 1.1 jmcneill 2553 1.1 jmcneill void 2554 1.1 jmcneill video_buffer_free_with_ubuf(struct video_buffer *vb) 2555 1.1 jmcneill { 2556 1.1 jmcneill } 2557 1.1 jmcneill */ 2558 1.1 jmcneill 2559 1.1 jmcneill static int 2560 1.1 jmcneill video_stream_realloc_bufs(struct video_stream *vs, uint8_t nbufs) 2561 1.1 jmcneill { 2562 1.1 jmcneill int i, err; 2563 1.1 jmcneill uint8_t minnbufs, oldnbufs; 2564 1.1 jmcneill size_t size; 2565 1.1 jmcneill off_t offset; 2566 1.1 jmcneill struct video_buffer **oldbuf; 2567 1.1 jmcneill struct v4l2_buffer *buf; 2568 1.1 jmcneill 2569 1.22 christos size = PAGE_ALIGN(vs->vs_format.sample_size) * nbufs; 2570 1.1 jmcneill err = scatter_buf_set_size(&vs->vs_data, size); 2571 1.1 jmcneill if (err != 0) 2572 1.1 jmcneill return err; 2573 1.1 jmcneill 2574 1.1 jmcneill oldnbufs = vs->vs_nbufs; 2575 1.1 jmcneill oldbuf = vs->vs_buf; 2576 1.1 jmcneill 2577 1.1 jmcneill vs->vs_nbufs = nbufs; 2578 1.1 jmcneill if (nbufs > 0) { 2579 1.1 jmcneill vs->vs_buf = 2580 1.1 jmcneill kmem_alloc(sizeof(struct video_buffer *) * nbufs, KM_SLEEP); 2581 1.1 jmcneill } else { 2582 1.1 jmcneill vs->vs_buf = NULL; 2583 1.1 jmcneill } 2584 1.1 jmcneill 2585 1.35 riastrad minnbufs = uimin(vs->vs_nbufs, oldnbufs); 2586 1.1 jmcneill /* copy any bufs that will be reused */ 2587 1.1 jmcneill for (i = 0; i < minnbufs; ++i) 2588 1.1 jmcneill vs->vs_buf[i] = oldbuf[i]; 2589 1.1 jmcneill /* allocate any necessary new bufs */ 2590 1.1 jmcneill for (; i < vs->vs_nbufs; ++i) 2591 1.1 jmcneill vs->vs_buf[i] = video_buffer_alloc(); 2592 1.1 jmcneill /* free any bufs no longer used */ 2593 1.1 jmcneill for (; i < oldnbufs; ++i) { 2594 1.1 jmcneill video_buffer_free(oldbuf[i]); 2595 1.1 jmcneill oldbuf[i] = NULL; 2596 1.1 jmcneill } 2597 1.1 jmcneill 2598 1.1 jmcneill /* Free old buffer metadata */ 2599 1.1 jmcneill if (oldbuf != NULL) 2600 1.1 jmcneill kmem_free(oldbuf, sizeof(struct video_buffer *) * oldnbufs); 2601 1.1 jmcneill 2602 1.1 jmcneill /* initialize bufs */ 2603 1.1 jmcneill offset = 0; 2604 1.1 jmcneill for (i = 0; i < vs->vs_nbufs; ++i) { 2605 1.1 jmcneill buf = vs->vs_buf[i]->vb_buf; 2606 1.1 jmcneill buf->index = i; 2607 1.1 jmcneill buf->type = vs->vs_type; 2608 1.1 jmcneill buf->bytesused = 0; 2609 1.1 jmcneill buf->flags = 0; 2610 1.1 jmcneill buf->field = 0; 2611 1.1 jmcneill buf->sequence = 0; 2612 1.1 jmcneill buf->memory = V4L2_MEMORY_MMAP; 2613 1.1 jmcneill buf->m.offset = offset; 2614 1.22 christos buf->length = PAGE_ALIGN(vs->vs_format.sample_size); 2615 1.38 rjs buf->reserved2 = 0; 2616 1.1 jmcneill buf->reserved = 0; 2617 1.1 jmcneill 2618 1.1 jmcneill offset += buf->length; 2619 1.1 jmcneill } 2620 1.1 jmcneill 2621 1.1 jmcneill return 0; 2622 1.1 jmcneill } 2623 1.1 jmcneill 2624 1.1 jmcneill /* Accepts a video_sample into the ingress queue. Caller must hold 2625 1.1 jmcneill * the stream lock. */ 2626 1.1 jmcneill void 2627 1.1 jmcneill video_stream_enqueue(struct video_stream *vs, struct video_buffer *vb) 2628 1.1 jmcneill { 2629 1.1 jmcneill if (vb->vb_buf->flags & V4L2_BUF_FLAG_QUEUED) { 2630 1.1 jmcneill DPRINTF(("video_stream_enqueue: sample already queued\n")); 2631 1.1 jmcneill return; 2632 1.1 jmcneill } 2633 1.1 jmcneill 2634 1.1 jmcneill vb->vb_buf->flags |= V4L2_BUF_FLAG_QUEUED; 2635 1.1 jmcneill vb->vb_buf->flags &= ~V4L2_BUF_FLAG_DONE; 2636 1.1 jmcneill 2637 1.1 jmcneill vb->vb_buf->bytesused = 0; 2638 1.1 jmcneill 2639 1.1 jmcneill SIMPLEQ_INSERT_TAIL(&vs->vs_ingress, vb, entries); 2640 1.1 jmcneill } 2641 1.1 jmcneill 2642 1.1 jmcneill 2643 1.1 jmcneill /* Removes the head of the egress queue for use by userspace. Caller 2644 1.1 jmcneill * must hold the stream lock. */ 2645 1.1 jmcneill struct video_buffer * 2646 1.1 jmcneill video_stream_dequeue(struct video_stream *vs) 2647 1.1 jmcneill { 2648 1.1 jmcneill struct video_buffer *vb; 2649 1.1 jmcneill 2650 1.1 jmcneill if (!SIMPLEQ_EMPTY(&vs->vs_egress)) { 2651 1.1 jmcneill vb = SIMPLEQ_FIRST(&vs->vs_egress); 2652 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_egress, entries); 2653 1.1 jmcneill vb->vb_buf->flags &= ~V4L2_BUF_FLAG_QUEUED; 2654 1.1 jmcneill vb->vb_buf->flags |= V4L2_BUF_FLAG_DONE; 2655 1.1 jmcneill return vb; 2656 1.1 jmcneill } else { 2657 1.1 jmcneill return NULL; 2658 1.1 jmcneill } 2659 1.1 jmcneill } 2660 1.1 jmcneill 2661 1.28 drochner static void 2662 1.28 drochner v4l2buf_set_timestamp(struct v4l2_buffer *buf) 2663 1.28 drochner { 2664 1.28 drochner 2665 1.28 drochner getmicrotime(&buf->timestamp); 2666 1.28 drochner } 2667 1.1 jmcneill 2668 1.1 jmcneill /* 2669 1.1 jmcneill * write payload data to the appropriate video sample, possibly moving 2670 1.1 jmcneill * the sample from ingress to egress queues 2671 1.1 jmcneill */ 2672 1.1 jmcneill void 2673 1.1 jmcneill video_stream_write(struct video_stream *vs, 2674 1.1 jmcneill const struct video_payload *payload) 2675 1.1 jmcneill { 2676 1.1 jmcneill struct video_buffer *vb; 2677 1.1 jmcneill struct v4l2_buffer *buf; 2678 1.1 jmcneill struct scatter_io sio; 2679 1.1 jmcneill 2680 1.1 jmcneill mutex_enter(&vs->vs_lock); 2681 1.1 jmcneill 2682 1.1 jmcneill /* change of frameno implies end of current frame */ 2683 1.24 jmcneill if (vs->vs_frameno >= 0 && vs->vs_frameno != payload->frameno) 2684 1.1 jmcneill video_stream_sample_done(vs); 2685 1.24 jmcneill 2686 1.24 jmcneill vs->vs_frameno = payload->frameno; 2687 1.39 riastrad 2688 1.1 jmcneill if (vs->vs_drop || SIMPLEQ_EMPTY(&vs->vs_ingress)) { 2689 1.1 jmcneill /* DPRINTF(("video_stream_write: dropping sample %d\n", 2690 1.1 jmcneill vs->vs_sequence)); */ 2691 1.1 jmcneill vs->vs_drop = true; 2692 1.15 jmcneill } else if (payload->size > 0) { 2693 1.1 jmcneill vb = SIMPLEQ_FIRST(&vs->vs_ingress); 2694 1.1 jmcneill buf = vb->vb_buf; 2695 1.28 drochner if (!buf->bytesused) 2696 1.28 drochner v4l2buf_set_timestamp(buf); 2697 1.1 jmcneill if (payload->size > buf->length - buf->bytesused) { 2698 1.1 jmcneill DPRINTF(("video_stream_write: " 2699 1.1 jmcneill "payload would overflow\n")); 2700 1.1 jmcneill } else if (scatter_io_init(&vs->vs_data, 2701 1.1 jmcneill buf->m.offset + buf->bytesused, 2702 1.1 jmcneill payload->size, 2703 1.1 jmcneill &sio)) 2704 1.1 jmcneill { 2705 1.1 jmcneill scatter_io_copyin(&sio, payload->data); 2706 1.1 jmcneill buf->bytesused += (payload->size - sio.sio_resid); 2707 1.1 jmcneill } else { 2708 1.1 jmcneill DPRINTF(("video_stream_write: failed to init scatter io " 2709 1.1 jmcneill "vb=%p buf=%p " 2710 1.21 njoly "buf->m.offset=%d buf->bytesused=%u " 2711 1.1 jmcneill "payload->size=%zu\n", 2712 1.1 jmcneill vb, buf, 2713 1.1 jmcneill buf->m.offset, buf->bytesused, payload->size)); 2714 1.1 jmcneill } 2715 1.1 jmcneill } 2716 1.1 jmcneill 2717 1.1 jmcneill /* if the payload marks it, we can do sample_done() early */ 2718 1.1 jmcneill if (payload->end_of_frame) 2719 1.1 jmcneill video_stream_sample_done(vs); 2720 1.1 jmcneill 2721 1.1 jmcneill mutex_exit(&vs->vs_lock); 2722 1.1 jmcneill } 2723 1.1 jmcneill 2724 1.1 jmcneill 2725 1.1 jmcneill /* Moves the head of the ingress queue to the tail of the egress 2726 1.1 jmcneill * queue, or resets drop status if we were dropping this sample. 2727 1.1 jmcneill * Caller should hold the stream queue lock. */ 2728 1.1 jmcneill void 2729 1.1 jmcneill video_stream_sample_done(struct video_stream *vs) 2730 1.1 jmcneill { 2731 1.1 jmcneill struct video_buffer *vb; 2732 1.1 jmcneill 2733 1.1 jmcneill if (vs->vs_drop) { 2734 1.1 jmcneill vs->vs_drop = false; 2735 1.1 jmcneill } else if (!SIMPLEQ_EMPTY(&vs->vs_ingress)) { 2736 1.1 jmcneill vb = SIMPLEQ_FIRST(&vs->vs_ingress); 2737 1.1 jmcneill vb->vb_buf->sequence = vs->vs_sequence; 2738 1.1 jmcneill SIMPLEQ_REMOVE_HEAD(&vs->vs_ingress, entries); 2739 1.1 jmcneill 2740 1.1 jmcneill SIMPLEQ_INSERT_TAIL(&vs->vs_egress, vb, entries); 2741 1.1 jmcneill cv_signal(&vs->vs_sample_cv); 2742 1.7 jmcneill selnotify(&vs->vs_sel, 0, 0); 2743 1.1 jmcneill } else { 2744 1.1 jmcneill DPRINTF(("video_stream_sample_done: no sample\n")); 2745 1.1 jmcneill } 2746 1.1 jmcneill 2747 1.1 jmcneill vs->vs_frameno ^= 1; 2748 1.1 jmcneill vs->vs_sequence++; 2749 1.1 jmcneill } 2750 1.1 jmcneill 2751 1.1 jmcneill /* Check if all buffers are queued, i.e. none are under control of 2752 1.1 jmcneill * userspace. */ 2753 1.1 jmcneill /* 2754 1.1 jmcneill static bool 2755 1.1 jmcneill video_stream_all_queued(struct video_stream *vs) 2756 1.1 jmcneill { 2757 1.1 jmcneill } 2758 1.1 jmcneill */ 2759 1.1 jmcneill 2760 1.1 jmcneill 2761 1.1 jmcneill static void 2762 1.48 mlelstv scatter_buf_init(struct scatter_buf *sb, const char *name) 2763 1.1 jmcneill { 2764 1.1 jmcneill sb->sb_pool = pool_cache_init(PAGE_SIZE, 0, 0, 0, 2765 1.48 mlelstv name, NULL, IPL_VIDEO, 2766 1.1 jmcneill NULL, NULL, NULL); 2767 1.1 jmcneill sb->sb_size = 0; 2768 1.1 jmcneill sb->sb_npages = 0; 2769 1.1 jmcneill sb->sb_page_ary = NULL; 2770 1.1 jmcneill } 2771 1.1 jmcneill 2772 1.1 jmcneill static void 2773 1.1 jmcneill scatter_buf_destroy(struct scatter_buf *sb) 2774 1.1 jmcneill { 2775 1.1 jmcneill /* Do we need to return everything to the pool first? */ 2776 1.1 jmcneill scatter_buf_set_size(sb, 0); 2777 1.1 jmcneill pool_cache_destroy(sb->sb_pool); 2778 1.1 jmcneill sb->sb_pool = 0; 2779 1.1 jmcneill sb->sb_npages = 0; 2780 1.1 jmcneill sb->sb_page_ary = NULL; 2781 1.1 jmcneill } 2782 1.1 jmcneill 2783 1.1 jmcneill /* Increase or decrease the size of the buffer */ 2784 1.1 jmcneill static int 2785 1.1 jmcneill scatter_buf_set_size(struct scatter_buf *sb, size_t sz) 2786 1.1 jmcneill { 2787 1.1 jmcneill int i; 2788 1.1 jmcneill size_t npages, minpages, oldnpages; 2789 1.1 jmcneill uint8_t **old_ary; 2790 1.1 jmcneill 2791 1.1 jmcneill npages = (sz >> PAGE_SHIFT) + ((sz & PAGE_MASK) > 0); 2792 1.39 riastrad 2793 1.1 jmcneill if (sb->sb_npages == npages) { 2794 1.1 jmcneill return 0; 2795 1.1 jmcneill } 2796 1.1 jmcneill 2797 1.1 jmcneill oldnpages = sb->sb_npages; 2798 1.1 jmcneill old_ary = sb->sb_page_ary; 2799 1.1 jmcneill 2800 1.1 jmcneill sb->sb_npages = npages; 2801 1.1 jmcneill if (npages > 0) { 2802 1.1 jmcneill sb->sb_page_ary = 2803 1.1 jmcneill kmem_alloc(sizeof(uint8_t *) * npages, KM_SLEEP); 2804 1.1 jmcneill } else { 2805 1.1 jmcneill sb->sb_page_ary = NULL; 2806 1.1 jmcneill } 2807 1.1 jmcneill 2808 1.35 riastrad minpages = uimin(npages, oldnpages); 2809 1.1 jmcneill /* copy any pages that will be reused */ 2810 1.1 jmcneill for (i = 0; i < minpages; ++i) 2811 1.1 jmcneill sb->sb_page_ary[i] = old_ary[i]; 2812 1.1 jmcneill /* allocate any new pages */ 2813 1.33 chs for (; i < npages; ++i) 2814 1.33 chs sb->sb_page_ary[i] = pool_cache_get(sb->sb_pool, PR_WAITOK); 2815 1.1 jmcneill /* return any pages no longer needed */ 2816 1.1 jmcneill for (; i < oldnpages; ++i) 2817 1.1 jmcneill pool_cache_put(sb->sb_pool, old_ary[i]); 2818 1.1 jmcneill 2819 1.1 jmcneill if (old_ary != NULL) 2820 1.1 jmcneill kmem_free(old_ary, sizeof(uint8_t *) * oldnpages); 2821 1.1 jmcneill 2822 1.1 jmcneill sb->sb_size = sb->sb_npages << PAGE_SHIFT; 2823 1.39 riastrad 2824 1.1 jmcneill return 0; 2825 1.1 jmcneill } 2826 1.1 jmcneill 2827 1.1 jmcneill 2828 1.1 jmcneill static paddr_t 2829 1.1 jmcneill scatter_buf_map(struct scatter_buf *sb, off_t off) 2830 1.1 jmcneill { 2831 1.1 jmcneill size_t pg; 2832 1.1 jmcneill paddr_t pa; 2833 1.39 riastrad 2834 1.1 jmcneill pg = off >> PAGE_SHIFT; 2835 1.1 jmcneill 2836 1.1 jmcneill if (pg >= sb->sb_npages) 2837 1.1 jmcneill return -1; 2838 1.1 jmcneill else if (!pmap_extract(pmap_kernel(), (vaddr_t)sb->sb_page_ary[pg], &pa)) 2839 1.1 jmcneill return -1; 2840 1.1 jmcneill 2841 1.1 jmcneill return atop(pa); 2842 1.1 jmcneill } 2843 1.1 jmcneill 2844 1.1 jmcneill /* Initialize data for an io operation on a scatter buffer. Returns 2845 1.1 jmcneill * true if the transfer is valid, or false if out of range. */ 2846 1.1 jmcneill static bool 2847 1.1 jmcneill scatter_io_init(struct scatter_buf *sb, 2848 1.1 jmcneill off_t off, size_t len, 2849 1.1 jmcneill struct scatter_io *sio) 2850 1.1 jmcneill { 2851 1.1 jmcneill if ((off + len) > sb->sb_size) { 2852 1.1 jmcneill DPRINTF(("video: scatter_io_init failed: off=%" PRId64 2853 1.1 jmcneill " len=%zu sb->sb_size=%zu\n", 2854 1.1 jmcneill off, len, sb->sb_size)); 2855 1.1 jmcneill return false; 2856 1.1 jmcneill } 2857 1.1 jmcneill 2858 1.1 jmcneill sio->sio_buf = sb; 2859 1.1 jmcneill sio->sio_offset = off; 2860 1.1 jmcneill sio->sio_resid = len; 2861 1.1 jmcneill 2862 1.1 jmcneill return true; 2863 1.1 jmcneill } 2864 1.1 jmcneill 2865 1.1 jmcneill /* Store the pointer and size of the next contiguous segment. Returns 2866 1.36 msaitoh * true if the segment is valid, or false if all has been transferred. 2867 1.1 jmcneill * Does not check for overflow. */ 2868 1.1 jmcneill static bool 2869 1.1 jmcneill scatter_io_next(struct scatter_io *sio, void **p, size_t *sz) 2870 1.1 jmcneill { 2871 1.1 jmcneill size_t pg, pgo; 2872 1.1 jmcneill 2873 1.1 jmcneill if (sio->sio_resid == 0) 2874 1.1 jmcneill return false; 2875 1.39 riastrad 2876 1.1 jmcneill pg = sio->sio_offset >> PAGE_SHIFT; 2877 1.1 jmcneill pgo = sio->sio_offset & PAGE_MASK; 2878 1.1 jmcneill 2879 1.35 riastrad *sz = uimin(PAGE_SIZE - pgo, sio->sio_resid); 2880 1.1 jmcneill *p = sio->sio_buf->sb_page_ary[pg] + pgo; 2881 1.1 jmcneill 2882 1.1 jmcneill sio->sio_offset += *sz; 2883 1.1 jmcneill sio->sio_resid -= *sz; 2884 1.1 jmcneill 2885 1.1 jmcneill return true; 2886 1.1 jmcneill } 2887 1.1 jmcneill 2888 1.1 jmcneill /* Semi-undo of a failed segment copy. Updates the scatter_io 2889 1.1 jmcneill * struct to the previous values prior to a failed segment copy. */ 2890 1.1 jmcneill static void 2891 1.1 jmcneill scatter_io_undo(struct scatter_io *sio, size_t sz) 2892 1.1 jmcneill { 2893 1.1 jmcneill sio->sio_offset -= sz; 2894 1.1 jmcneill sio->sio_resid += sz; 2895 1.1 jmcneill } 2896 1.1 jmcneill 2897 1.1 jmcneill /* Copy data from src into the scatter_buf as described by io. */ 2898 1.1 jmcneill static void 2899 1.1 jmcneill scatter_io_copyin(struct scatter_io *sio, const void *p) 2900 1.1 jmcneill { 2901 1.1 jmcneill void *dst; 2902 1.1 jmcneill const uint8_t *src = p; 2903 1.1 jmcneill size_t sz; 2904 1.1 jmcneill 2905 1.1 jmcneill while(scatter_io_next(sio, &dst, &sz)) { 2906 1.1 jmcneill memcpy(dst, src, sz); 2907 1.1 jmcneill src += sz; 2908 1.1 jmcneill } 2909 1.1 jmcneill } 2910 1.1 jmcneill 2911 1.1 jmcneill /* --not used; commented to avoid compiler warnings-- 2912 1.1 jmcneill static void 2913 1.1 jmcneill scatter_io_copyout(struct scatter_io *sio, void *p) 2914 1.1 jmcneill { 2915 1.1 jmcneill void *src; 2916 1.1 jmcneill uint8_t *dst = p; 2917 1.1 jmcneill size_t sz; 2918 1.1 jmcneill 2919 1.1 jmcneill while(scatter_io_next(sio, &src, &sz)) { 2920 1.1 jmcneill memcpy(dst, src, sz); 2921 1.1 jmcneill dst += sz; 2922 1.1 jmcneill } 2923 1.1 jmcneill } 2924 1.1 jmcneill */ 2925 1.1 jmcneill 2926 1.1 jmcneill /* Performat a series of uiomove calls on a scatter buf. Returns 2927 1.1 jmcneill * EFAULT if uiomove EFAULTs on the first segment. Otherwise, returns 2928 1.1 jmcneill * an incomplete transfer but with no error. */ 2929 1.1 jmcneill static int 2930 1.1 jmcneill scatter_io_uiomove(struct scatter_io *sio, struct uio *uio) 2931 1.1 jmcneill { 2932 1.1 jmcneill void *p; 2933 1.1 jmcneill size_t sz; 2934 1.1 jmcneill bool first = true; 2935 1.1 jmcneill int err; 2936 1.39 riastrad 2937 1.1 jmcneill while(scatter_io_next(sio, &p, &sz)) { 2938 1.1 jmcneill err = uiomove(p, sz, uio); 2939 1.1 jmcneill if (err == EFAULT) { 2940 1.1 jmcneill scatter_io_undo(sio, sz); 2941 1.1 jmcneill if (first) 2942 1.1 jmcneill return EFAULT; 2943 1.1 jmcneill else 2944 1.1 jmcneill return 0; 2945 1.1 jmcneill } 2946 1.1 jmcneill first = false; 2947 1.1 jmcneill } 2948 1.1 jmcneill 2949 1.1 jmcneill return 0; 2950 1.1 jmcneill } 2951 1.1 jmcneill 2952 1.1 jmcneill #endif /* NVIDEO > 0 */ 2953