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