xref: /freebsd/sys/dev/video/video.c (revision d3e5082ce4dcb154cbf50cba05d8f1dbbd55a5fc)
1 /*
2  * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
3  * Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
4  * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org>
5  *
6  * SPDX-License-Identifier: BSD-2-Clause AND ISC
7  *
8  * The cdev, kqfilter and buffer-pool handling are derived from uvideo(4).
9  */
10 
11 #include <sys/param.h>
12 #include <sys/systm.h>
13 #include <sys/bus.h>
14 #include <sys/conf.h>
15 #include <sys/fcntl.h>
16 #include <sys/kernel.h>
17 #include <sys/lock.h>
18 #include <sys/rwlock.h>
19 #include <sys/malloc.h>
20 #include <sys/module.h>
21 #include <sys/mutex.h>
22 #include <sys/poll.h>
23 #include <sys/proc.h>
24 #include <sys/selinfo.h>
25 #include <sys/sx.h>
26 #include <sys/uio.h>
27 #include <sys/videoio.h>
28 
29 #include <vm/vm.h>
30 #include <vm/vm_extern.h>
31 #include <vm/vm_kern.h>
32 #include <vm/vm_object.h>
33 #include <vm/vm_page.h>
34 #include <vm/vm_pager.h>
35 #include <vm/vm_param.h>
36 #include <vm/pmap.h>
37 #include <vm/vm_map.h>
38 #include <vm/uma.h>
39 
40 #include <dev/video/video_internal.h>
41 
42 #include "video_if.h"
43 
44 MALLOC_DEFINE(M_VIDEO, "video", "video(4) framework");
45 
46 #define	VIDEO_UNIT_RETRIES	32
47 
48 static struct unrhdr *video_unrhdr;
49 
50 static d_open_t		video_open;
51 static d_close_t	video_close;
52 static d_read_t		video_read;
53 static d_ioctl_t	video_ioctl;
54 static d_poll_t		video_poll;
55 static d_kqfilter_t	video_kqfilter;
56 static d_mmap_single_t	video_mmap_single;
57 
58 static struct cdevsw video_cdevsw = {
59 	.d_version =	D_VERSION,
60 	.d_open =	video_open,
61 	.d_close =	video_close,
62 	.d_read =	video_read,
63 	.d_ioctl =	video_ioctl,
64 	.d_poll =	video_poll,
65 	.d_kqfilter =	video_kqfilter,
66 	.d_mmap_single = video_mmap_single,
67 	.d_name =	"video",
68 };
69 
70 static struct video_buf_pool *
71 video_pool_alloc(u_int nbufs, size_t buf_size)
72 {
73 	struct video_buf_pool *pool;
74 	struct video_buf *vb;
75 	size_t map_size;
76 	vm_object_t obj;
77 	vm_offset_t kva;
78 	u_int i;
79 	int error;
80 
81 	buf_size = round_page(buf_size);
82 	if (buf_size == 0 || nbufs == 0 || nbufs > VIDEO_MAX_BUFFERS)
83 		return (NULL);
84 	if (SIZE_MAX / nbufs < buf_size)
85 		return (NULL);
86 	map_size = (size_t)nbufs * buf_size;
87 
88 	/*
89 	 * Use phys_pager_allocate() rather than a bare vm_object_allocate():
90 	 * the latter leaves un_pager.phys.ops NULL, which faults when the VM
91 	 * system calls phys_pager_getpages() from vm_map_wire() or from a
92 	 * userspace fault on the mapping.
93 	 */
94 	obj = phys_pager_allocate(NULL, &default_phys_pg_ops, NULL, map_size,
95 	    VM_PROT_ALL, 0, curthread->td_ucred);
96 	if (obj == NULL)
97 		return (NULL);
98 
99 	kva = vm_map_min(kernel_map);
100 	error = vm_map_find(kernel_map, obj, 0, &kva, map_size, 0,
101 	    VMFS_OPTIMAL_SPACE, VM_PROT_READ | VM_PROT_WRITE,
102 	    VM_PROT_READ | VM_PROT_WRITE, 0);
103 	if (error != KERN_SUCCESS) {
104 		vm_object_deallocate(obj);
105 		return (NULL);
106 	}
107 	error = vm_map_wire(kernel_map, kva, kva + map_size,
108 	    VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
109 	if (error != KERN_SUCCESS) {
110 		vm_map_remove(kernel_map, kva, kva + map_size);
111 		return (NULL);
112 	}
113 
114 	pool = malloc(sizeof(*pool), M_VIDEO, M_WAITOK | M_ZERO);
115 	pool->obj = obj;
116 	pool->kva = kva;
117 	pool->nbufs = nbufs;
118 	pool->buf_size = buf_size;
119 	pool->map_size = map_size;
120 
121 	for (i = 0; i < nbufs; i++) {
122 		vb = &pool->bufs[i];
123 		vb->pool = pool;
124 		vb->index = i;
125 		vb->state = VB_IDLE;
126 		vb->length = buf_size;
127 		vb->buf = (uint8_t *)kva + (size_t)i * buf_size;
128 	}
129 	return (pool);
130 }
131 
132 static void
133 video_pool_free(struct video_buf_pool *pool)
134 {
135 
136 	/*
137 	 * Removing the kernel mapping drops the map's reference on the
138 	 * object.  Any surviving userspace mapping holds its own reference,
139 	 * so the frames stay alive until the last one goes away.
140 	 */
141 	vm_map_remove(kernel_map, pool->kva, pool->kva + pool->map_size);
142 	free(pool, M_VIDEO);
143 }
144 
145 static void
146 video_pool_detach(struct video_device *vd)
147 {
148 	struct video_buf_pool *pool;
149 
150 	mtx_lock(&vd->mtx);
151 	if (vd->owner != NULL) {
152 		vd->owner->read_buf = NULL;
153 		vd->owner->read_offset = 0;
154 	}
155 	while (vd->readers > 0)
156 		msleep(&vd->readers, &vd->mtx, 0, "vdrain", 0);
157 	pool = vd->pool;
158 	vd->pool = NULL;
159 	STAILQ_INIT(&vd->queued);
160 	STAILQ_INIT(&vd->done);
161 	mtx_unlock(&vd->mtx);
162 
163 	if (pool != NULL)
164 		video_pool_free(pool);
165 }
166 
167 static void
168 video_file_dtor(void *arg)
169 {
170 	struct video_file *vf = arg;
171 	struct video_device *vd = vf->vd;
172 
173 	sx_xlock(&vd->cfg_sx);
174 
175 	if (vf->is_owner) {
176 		if (vd->streaming) {
177 			mtx_lock(&vd->mtx);
178 			vd->stopping = true;
179 			mtx_unlock(&vd->mtx);
180 
181 			VIDEO_STOP_STREAM(vd->dev);
182 
183 			mtx_lock(&vd->mtx);
184 			vd->streaming = false;
185 			vd->stopping = false;
186 			STAILQ_INIT(&vd->queued);
187 			STAILQ_INIT(&vd->done);
188 			mtx_unlock(&vd->mtx);
189 		}
190 
191 		video_pool_detach(vd);
192 
193 		mtx_lock(&vd->mtx);
194 		vd->owner = NULL;
195 		mtx_unlock(&vd->mtx);
196 		vd->mode = VMODE_NONE;
197 
198 		VIDEO_CLOSE(vd->dev);
199 	}
200 
201 	sx_xunlock(&vd->cfg_sx);
202 
203 	free(vf, M_VIDEO);
204 }
205 
206 static int
207 video_open(struct cdev *dev, int flags, int fmt, struct thread *td)
208 {
209 	struct video_device *vd = dev->si_drv1;
210 	struct video_file *vf;
211 
212 	if (vd == NULL || vd->dying)
213 		return (ENXIO);
214 
215 	vf = malloc(sizeof(*vf), M_VIDEO, M_WAITOK | M_ZERO);
216 	vf->vd = vd;
217 
218 	return (devfs_set_cdevpriv(vf, video_file_dtor));
219 }
220 
221 static int
222 video_close(struct cdev *dev, int flags, int fmt, struct thread *td)
223 {
224 
225 	return (0);
226 }
227 
228 static int
229 video_claim_owner(struct video_device *vd, struct video_file *vf)
230 {
231 	int error;
232 
233 	sx_assert(&vd->cfg_sx, SA_XLOCKED);
234 
235 	if (vd->dying)
236 		return (ENXIO);
237 	if (vd->owner == vf)
238 		return (0);
239 	if (vd->owner != NULL)
240 		return (EBUSY);
241 
242 	error = VIDEO_OPEN(vd->dev);
243 	if (error != 0)
244 		return (error);
245 
246 	mtx_lock(&vd->mtx);
247 	vd->owner = vf;
248 	mtx_unlock(&vd->mtx);
249 	vf->is_owner = true;
250 	return (0);
251 }
252 
253 struct video_buf *
254 video_buf_acquire(struct video_device *vd)
255 {
256 	struct video_buf *vb;
257 
258 	mtx_lock(&vd->mtx);
259 	vb = STAILQ_FIRST(&vd->queued);
260 	if (vb != NULL) {
261 		STAILQ_REMOVE_HEAD(&vd->queued, entry);
262 		vb->state = VB_ACTIVE;
263 		vb->bytesused = 0;
264 	}
265 	mtx_unlock(&vd->mtx);
266 	return (vb);
267 }
268 
269 int
270 video_buf_write(struct video_buf *vb, size_t offset, const void *src,
271     size_t len)
272 {
273 
274 	if (offset > vb->length || len > vb->length - offset)
275 		return (ENOSPC);
276 
277 	memcpy((uint8_t *)vb->buf + offset, src, len);
278 	return (0);
279 }
280 
281 void
282 video_buf_done(struct video_buf *vb, size_t bytesused, uint32_t sequence)
283 {
284 	struct video_device *vd;
285 	bool overrun;
286 
287 	overrun = bytesused > vb->length;
288 	if (overrun)
289 		bytesused = 0;
290 
291 	vd = vb->vd;
292 	mtx_lock(&vd->mtx);
293 	if (vb->state != VB_ACTIVE) {
294 		mtx_unlock(&vd->mtx);
295 		return;
296 	}
297 	vb->bytesused = bytesused;
298 	vb->sequence = sequence;
299 	getmicrouptime(&vb->timestamp);
300 	vb->flags = V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
301 	if (overrun)
302 		vb->flags |= V4L2_BUF_FLAG_ERROR;
303 	vb->state = VB_DONE;
304 	STAILQ_INSERT_TAIL(&vd->done, vb, entry);
305 	selwakeup(&vd->sel);
306 	KNOTE_LOCKED(&vd->sel.si_note, 0);
307 	wakeup(&vd->done);
308 	mtx_unlock(&vd->mtx);
309 }
310 
311 void
312 video_buf_error(struct video_buf *vb)
313 {
314 	struct video_device *vd = vb->vd;
315 
316 	mtx_lock(&vd->mtx);
317 	if (vb->state != VB_ACTIVE) {
318 		mtx_unlock(&vd->mtx);
319 		return;
320 	}
321 	vb->bytesused = 0;
322 	vb->flags = V4L2_BUF_FLAG_ERROR;
323 	getmicrouptime(&vb->timestamp);
324 	vb->state = VB_ERROR;
325 	STAILQ_INSERT_TAIL(&vd->done, vb, entry);
326 	selwakeup(&vd->sel);
327 	KNOTE_LOCKED(&vd->sel.si_note, 0);
328 	wakeup(&vd->done);
329 	mtx_unlock(&vd->mtx);
330 }
331 
332 static int
333 video_querycap(struct video_device *vd, struct v4l2_capability *cap)
334 {
335 	struct video_caps vc;
336 	int error;
337 
338 	memset(&vc, 0, sizeof(vc));
339 	error = VIDEO_QUERYCAP(vd->dev, &vc);
340 	if (error != 0)
341 		return (error);
342 
343 	memset(cap, 0, sizeof(*cap));
344 	strlcpy((char *)cap->driver, vc.driver, sizeof(cap->driver));
345 	strlcpy((char *)cap->card, vc.card, sizeof(cap->card));
346 	strlcpy((char *)cap->bus_info, vc.bus_info, sizeof(cap->bus_info));
347 	cap->version = vc.version;
348 	cap->device_caps = vc.capabilities | V4L2_CAP_EXT_PIX_FORMAT;
349 	cap->capabilities = vc.capabilities | V4L2_CAP_DEVICE_CAPS |
350 	    V4L2_CAP_EXT_PIX_FORMAT;
351 	return (0);
352 }
353 
354 static int
355 video_enum_fmt(struct video_device *vd, struct v4l2_fmtdesc *fd)
356 {
357 	struct video_format vf;
358 	int error;
359 
360 	if (fd->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
361 		return (EINVAL);
362 
363 	memset(&vf, 0, sizeof(vf));
364 	error = VIDEO_ENUM_FORMAT(vd->dev, fd->index, &vf);
365 	if (error != 0)
366 		return (error);
367 
368 	fd->pixelformat = vf.pixelformat;
369 	fd->flags = vf.flags;
370 	strlcpy((char *)fd->description, vf.description,
371 	    sizeof(fd->description));
372 	return (0);
373 }
374 
375 static int
376 video_g_fmt(struct video_device *vd, struct v4l2_format *f)
377 {
378 	struct video_format vf;
379 	int error;
380 
381 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
382 		return (EINVAL);
383 
384 	memset(&vf, 0, sizeof(vf));
385 	error = VIDEO_GET_FORMAT(vd->dev, &vf);
386 	if (error != 0)
387 		return (error);
388 
389 	memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
390 	f->fmt.pix.width = vf.width;
391 	f->fmt.pix.height = vf.height;
392 	f->fmt.pix.pixelformat = vf.pixelformat;
393 	f->fmt.pix.field = vf.field;
394 	f->fmt.pix.bytesperline = vf.bytesperline;
395 	f->fmt.pix.sizeimage = vf.sizeimage;
396 	f->fmt.pix.colorspace = vf.colorspace;
397 	f->fmt.pix.xfer_func = vf.xfer_func;
398 	f->fmt.pix.ycbcr_enc = vf.ycbcr_enc;
399 	f->fmt.pix.flags = vf.flags;
400 	return (0);
401 }
402 
403 static int
404 video_s_fmt(struct video_device *vd, struct video_file *vf,
405     struct v4l2_format *f)
406 {
407 	struct video_format fmt;
408 	int error;
409 
410 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
411 		return (EINVAL);
412 
413 	sx_xlock(&vd->cfg_sx);
414 	error = video_claim_owner(vd, vf);
415 	if (error != 0) {
416 		sx_xunlock(&vd->cfg_sx);
417 		return (error);
418 	}
419 	if (vd->streaming) {
420 		sx_xunlock(&vd->cfg_sx);
421 		return (EBUSY);
422 	}
423 
424 	memset(&fmt, 0, sizeof(fmt));
425 	fmt.width = f->fmt.pix.width;
426 	fmt.height = f->fmt.pix.height;
427 	fmt.pixelformat = f->fmt.pix.pixelformat;
428 	fmt.field = f->fmt.pix.field;
429 
430 	error = VIDEO_SET_FORMAT(vd->dev, &fmt);
431 	if (error == 0) {
432 		VIDEO_GET_FORMAT(vd->dev, &vd->format);
433 
434 		f->fmt.pix.width = vd->format.width;
435 		f->fmt.pix.height = vd->format.height;
436 		f->fmt.pix.pixelformat = vd->format.pixelformat;
437 		f->fmt.pix.field = vd->format.field;
438 		f->fmt.pix.bytesperline = vd->format.bytesperline;
439 		f->fmt.pix.sizeimage = vd->format.sizeimage;
440 		f->fmt.pix.colorspace = vd->format.colorspace;
441 	}
442 	sx_xunlock(&vd->cfg_sx);
443 	return (error);
444 }
445 
446 static int
447 video_try_fmt(struct video_device *vd, struct v4l2_format *f)
448 {
449 	struct video_format fmt;
450 	int error;
451 
452 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
453 		return (EINVAL);
454 	memset(&fmt, 0, sizeof(fmt));
455 	fmt.width = f->fmt.pix.width;
456 	fmt.height = f->fmt.pix.height;
457 	fmt.pixelformat = f->fmt.pix.pixelformat;
458 	fmt.field = f->fmt.pix.field;
459 
460 	error = VIDEO_TRY_FORMAT(vd->dev, &fmt);
461 	if (error == 0) {
462 		f->fmt.pix.width = fmt.width;
463 		f->fmt.pix.height = fmt.height;
464 		f->fmt.pix.pixelformat = fmt.pixelformat;
465 		f->fmt.pix.field = fmt.field;
466 		f->fmt.pix.bytesperline = fmt.bytesperline;
467 		f->fmt.pix.sizeimage = fmt.sizeimage;
468 		f->fmt.pix.colorspace = fmt.colorspace;
469 	}
470 	return (error);
471 }
472 
473 static int
474 video_reqbufs(struct video_device *vd, struct video_file *vf,
475     struct v4l2_requestbuffers *rb)
476 {
477 	struct video_buf_pool *pool;
478 	int error;
479 
480 	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
481 		return (EINVAL);
482 	if (rb->memory != V4L2_MEMORY_MMAP)
483 		return (EINVAL);
484 
485 	sx_xlock(&vd->cfg_sx);
486 	error = video_claim_owner(vd, vf);
487 	if (error != 0) {
488 		sx_xunlock(&vd->cfg_sx);
489 		return (error);
490 	}
491 	if (vd->streaming) {
492 		sx_xunlock(&vd->cfg_sx);
493 		return (EBUSY);
494 	}
495 
496 	video_pool_detach(vd);
497 
498 	if (rb->count == 0) {
499 		vd->mode = VMODE_NONE;
500 		sx_xunlock(&vd->cfg_sx);
501 		rb->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP;
502 		return (0);
503 	}
504 
505 	if (rb->count > VIDEO_MAX_BUFFERS)
506 		rb->count = VIDEO_MAX_BUFFERS;
507 	if (rb->count < 2)
508 		rb->count = 2;
509 
510 	if (vd->format.sizeimage == 0) {
511 		error = VIDEO_GET_FORMAT(vd->dev, &vd->format);
512 		if (error != 0 || vd->format.sizeimage == 0) {
513 			sx_xunlock(&vd->cfg_sx);
514 			return (error != 0 ? error : EINVAL);
515 		}
516 	}
517 
518 	pool = video_pool_alloc(rb->count, vd->format.sizeimage);
519 	if (pool == NULL) {
520 		sx_xunlock(&vd->cfg_sx);
521 		return (ENOMEM);
522 	}
523 	mtx_lock(&vd->mtx);
524 	vd->pool = pool;
525 	mtx_unlock(&vd->mtx);
526 
527 	vd->mode = VMODE_MMAP;
528 	rb->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP;
529 	sx_xunlock(&vd->cfg_sx);
530 	return (0);
531 }
532 
533 static int
534 video_querybuf(struct video_device *vd, struct video_file *vf,
535     struct v4l2_buffer *b)
536 {
537 	struct video_buf *vb;
538 
539 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
540 		return (EINVAL);
541 
542 	mtx_lock(&vd->mtx);
543 	if (vd->owner != vf) {
544 		mtx_unlock(&vd->mtx);
545 		return (EPERM);
546 	}
547 	if (vd->pool == NULL || b->index >= vd->pool->nbufs) {
548 		mtx_unlock(&vd->mtx);
549 		return (EINVAL);
550 	}
551 
552 	vb = &vd->pool->bufs[b->index];
553 	b->memory = V4L2_MEMORY_MMAP;
554 	b->length = vb->length;
555 	b->m.offset = vb->index * vd->pool->buf_size;
556 	b->bytesused = vb->bytesused;
557 	b->field = V4L2_FIELD_NONE;
558 	b->timestamp = vb->timestamp;
559 	b->sequence = vb->sequence;
560 	b->flags = 0;
561 
562 	switch (vb->state) {
563 	case VB_QUEUED:
564 	case VB_ACTIVE:
565 		b->flags |= V4L2_BUF_FLAG_QUEUED;
566 		break;
567 	case VB_DONE:
568 		b->flags |= V4L2_BUF_FLAG_DONE;
569 		break;
570 	case VB_ERROR:
571 		b->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR;
572 		break;
573 	default:
574 		break;
575 	}
576 	b->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
577 	mtx_unlock(&vd->mtx);
578 	return (0);
579 }
580 
581 static int
582 video_qbuf(struct video_device *vd, struct video_file *vf,
583     struct v4l2_buffer *b)
584 {
585 	struct video_buf *vb;
586 
587 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
588 		return (EINVAL);
589 	if (b->memory != V4L2_MEMORY_MMAP)
590 		return (EINVAL);
591 
592 	mtx_lock(&vd->mtx);
593 	if (vd->owner != vf) {
594 		mtx_unlock(&vd->mtx);
595 		return (EPERM);
596 	}
597 	if (vd->pool == NULL || vd->mode != VMODE_MMAP ||
598 	    b->index >= vd->pool->nbufs) {
599 		mtx_unlock(&vd->mtx);
600 		return (EINVAL);
601 	}
602 
603 	vb = &vd->pool->bufs[b->index];
604 	if (vb->state != VB_IDLE) {
605 		mtx_unlock(&vd->mtx);
606 		return (EINVAL);
607 	}
608 
609 	vb->state = VB_QUEUED;
610 	vb->bytesused = 0;
611 	vb->vd = vd;
612 	STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
613 	mtx_unlock(&vd->mtx);
614 
615 	b->flags = V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED;
616 	return (0);
617 }
618 
619 static int
620 video_dqbuf(struct video_device *vd, struct video_file *vf,
621     struct v4l2_buffer *b, int flags)
622 {
623 	struct video_buf *vb;
624 	int error;
625 
626 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
627 		return (EINVAL);
628 	if (b->memory != V4L2_MEMORY_MMAP)
629 		return (EINVAL);
630 
631 	mtx_lock(&vd->mtx);
632 	if (vd->owner != vf) {
633 		mtx_unlock(&vd->mtx);
634 		return (EPERM);
635 	}
636 	while (STAILQ_EMPTY(&vd->done)) {
637 		if (!vd->streaming || vd->stopping) {
638 			mtx_unlock(&vd->mtx);
639 			return (EINVAL);
640 		}
641 		if (flags & O_NONBLOCK) {
642 			mtx_unlock(&vd->mtx);
643 			return (EAGAIN);
644 		}
645 		error = msleep(&vd->done, &vd->mtx, PCATCH, "vdqbuf", 0);
646 		if (error != 0) {
647 			mtx_unlock(&vd->mtx);
648 			return (error);
649 		}
650 	}
651 
652 	vb = STAILQ_FIRST(&vd->done);
653 	STAILQ_REMOVE_HEAD(&vd->done, entry);
654 
655 	b->index = vb->index;
656 	b->bytesused = vb->bytesused;
657 	b->field = V4L2_FIELD_NONE;
658 	b->timestamp = vb->timestamp;
659 	b->sequence = vb->sequence;
660 	b->memory = V4L2_MEMORY_MMAP;
661 	b->m.offset = vb->index * vd->pool->buf_size;
662 	b->length = vb->length;
663 	b->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE |
664 	    V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
665 	if (vb->flags & V4L2_BUF_FLAG_ERROR)
666 		b->flags |= V4L2_BUF_FLAG_ERROR;
667 
668 	vb->state = VB_IDLE;
669 	mtx_unlock(&vd->mtx);
670 
671 	return (0);
672 }
673 
674 static int
675 video_streamon(struct video_device *vd, struct video_file *vf, int *type)
676 {
677 	int error;
678 
679 	if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
680 		return (EINVAL);
681 
682 	sx_xlock(&vd->cfg_sx);
683 	error = video_claim_owner(vd, vf);
684 	if (error != 0) {
685 		sx_xunlock(&vd->cfg_sx);
686 		return (error);
687 	}
688 	if (vd->streaming) {
689 		sx_xunlock(&vd->cfg_sx);
690 		return (0);
691 	}
692 	if (vd->pool == NULL || vd->mode != VMODE_MMAP) {
693 		sx_xunlock(&vd->cfg_sx);
694 		return (EINVAL);
695 	}
696 
697 	error = VIDEO_START_STREAM(vd->dev);
698 	if (error != 0) {
699 		sx_xunlock(&vd->cfg_sx);
700 		return (error);
701 	}
702 
703 	mtx_lock(&vd->mtx);
704 	vd->streaming = true;
705 	mtx_unlock(&vd->mtx);
706 
707 	sx_xunlock(&vd->cfg_sx);
708 	return (0);
709 }
710 
711 static int
712 video_streamoff(struct video_device *vd, struct video_file *vf, int *type)
713 {
714 	struct video_buf *vb;
715 	u_int i;
716 
717 	if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
718 		return (EINVAL);
719 
720 	sx_xlock(&vd->cfg_sx);
721 	if (vd->owner != vf) {
722 		sx_xunlock(&vd->cfg_sx);
723 		return (EBUSY);
724 	}
725 	if (!vd->streaming) {
726 		sx_xunlock(&vd->cfg_sx);
727 		return (0);
728 	}
729 
730 	mtx_lock(&vd->mtx);
731 	vd->stopping = true;
732 	wakeup(&vd->done);
733 	mtx_unlock(&vd->mtx);
734 
735 	VIDEO_STOP_STREAM(vd->dev);
736 
737 	mtx_lock(&vd->mtx);
738 	vd->streaming = false;
739 	vd->stopping = false;
740 	STAILQ_INIT(&vd->queued);
741 	STAILQ_INIT(&vd->done);
742 	for (i = 0; i < vd->pool->nbufs; i++) {
743 		vb = &vd->pool->bufs[i];
744 		vb->state = VB_IDLE;
745 		vb->bytesused = 0;
746 		vb->vd = NULL;
747 	}
748 	vf->read_buf = NULL;
749 	vf->read_offset = 0;
750 	mtx_unlock(&vd->mtx);
751 
752 	sx_xunlock(&vd->cfg_sx);
753 	return (0);
754 }
755 
756 static int
757 video_g_parm(struct video_device *vd, struct v4l2_streamparm *sp)
758 {
759 	struct video_fract fract;
760 	int error;
761 
762 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
763 		return (EINVAL);
764 	memset(&fract, 0, sizeof(fract));
765 	error = VIDEO_GET_PARM(vd->dev, &fract);
766 	if (error != 0)
767 		return (error);
768 
769 	memset(&sp->parm.capture, 0, sizeof(sp->parm.capture));
770 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
771 	sp->parm.capture.timeperframe.numerator = fract.numerator;
772 	sp->parm.capture.timeperframe.denominator = fract.denominator;
773 	return (0);
774 }
775 
776 static int
777 video_s_parm(struct video_device *vd, struct v4l2_streamparm *sp)
778 {
779 	struct video_fract fract;
780 	int error;
781 
782 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
783 		return (EINVAL);
784 	fract.numerator = sp->parm.capture.timeperframe.numerator;
785 	fract.denominator = sp->parm.capture.timeperframe.denominator;
786 
787 	error = VIDEO_SET_PARM(vd->dev, &fract);
788 	if (error != 0)
789 		return (error);
790 
791 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
792 	sp->parm.capture.timeperframe.numerator = fract.numerator;
793 	sp->parm.capture.timeperframe.denominator = fract.denominator;
794 	return (0);
795 }
796 
797 static int
798 video_queryctrl(struct video_device *vd, struct v4l2_queryctrl *qc)
799 {
800 	struct video_control_desc desc;
801 	int error;
802 
803 	memset(&desc, 0, sizeof(desc));
804 	desc.id = qc->id;
805 	error = VIDEO_QUERY_CONTROL(vd->dev, &desc);
806 	if (error != 0)
807 		return (error);
808 
809 	qc->id = desc.id;
810 	qc->type = desc.type;
811 	strlcpy((char *)qc->name, desc.name, sizeof(qc->name));
812 	qc->minimum = desc.minimum;
813 	qc->maximum = desc.maximum;
814 	qc->step = desc.step;
815 	qc->default_value = desc.default_value;
816 	qc->flags = desc.flags;
817 	return (0);
818 }
819 
820 static int
821 video_g_ctrl(struct video_device *vd, struct v4l2_control *c)
822 {
823 	struct video_control vc;
824 	int error;
825 
826 	vc.id = c->id;
827 	vc.value = 0;
828 	error = VIDEO_GET_CONTROL(vd->dev, &vc);
829 	if (error == 0)
830 		c->value = vc.value;
831 	return (error);
832 }
833 
834 static int
835 video_s_ctrl(struct video_device *vd, struct v4l2_control *c)
836 {
837 	struct video_control vc;
838 
839 	vc.id = c->id;
840 	vc.value = c->value;
841 	return (VIDEO_SET_CONTROL(vd->dev, &vc));
842 }
843 
844 static int
845 video_enum_framesizes(struct video_device *vd, struct v4l2_frmsizeenum *fs)
846 {
847 	struct video_frmsizeenum vfs;
848 	int error;
849 
850 	memset(&vfs, 0, sizeof(vfs));
851 	vfs.index = fs->index;
852 	vfs.pixelformat = fs->pixel_format;
853 	error = VIDEO_ENUM_FRAMESIZES(vd->dev, &vfs);
854 	if (error != 0)
855 		return (error);
856 
857 	fs->type = vfs.type;
858 	if (vfs.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
859 		fs->discrete.width = vfs.discrete.width;
860 		fs->discrete.height = vfs.discrete.height;
861 	} else {
862 		fs->stepwise.min_width = vfs.stepwise.min_width;
863 		fs->stepwise.max_width = vfs.stepwise.max_width;
864 		fs->stepwise.step_width = vfs.stepwise.step_width;
865 		fs->stepwise.min_height = vfs.stepwise.min_height;
866 		fs->stepwise.max_height = vfs.stepwise.max_height;
867 		fs->stepwise.step_height = vfs.stepwise.step_height;
868 	}
869 	return (0);
870 }
871 
872 static int
873 video_enum_frameintervals(struct video_device *vd,
874     struct v4l2_frmivalenum *fi)
875 {
876 	struct video_frmivalenum vfi;
877 	int error;
878 
879 	memset(&vfi, 0, sizeof(vfi));
880 	vfi.index = fi->index;
881 	vfi.pixelformat = fi->pixel_format;
882 	vfi.width = fi->width;
883 	vfi.height = fi->height;
884 	error = VIDEO_ENUM_FRAMEINTERVALS(vd->dev, &vfi);
885 	if (error != 0)
886 		return (error);
887 
888 	fi->type = vfi.type;
889 	if (vfi.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
890 		fi->discrete.numerator = vfi.discrete.numerator;
891 		fi->discrete.denominator = vfi.discrete.denominator;
892 	} else {
893 		fi->stepwise.min.numerator = vfi.stepwise.min.numerator;
894 		fi->stepwise.min.denominator = vfi.stepwise.min.denominator;
895 		fi->stepwise.max.numerator = vfi.stepwise.max.numerator;
896 		fi->stepwise.max.denominator = vfi.stepwise.max.denominator;
897 		fi->stepwise.step.numerator = vfi.stepwise.step.numerator;
898 		fi->stepwise.step.denominator = vfi.stepwise.step.denominator;
899 	}
900 	return (0);
901 }
902 
903 static int
904 video_enum_input(struct video_device *vd, struct v4l2_input *inp)
905 {
906 	struct video_input vi;
907 	int error;
908 
909 	memset(&vi, 0, sizeof(vi));
910 	error = VIDEO_ENUM_INPUT(vd->dev, inp->index, &vi);
911 	if (error != 0)
912 		return (error);
913 
914 	strlcpy((char *)inp->name, vi.name, sizeof(inp->name));
915 	inp->type = vi.type;
916 	return (0);
917 }
918 
919 static int
920 video_g_input(struct video_device *vd, int *index)
921 {
922 	uint32_t idx;
923 	int error;
924 
925 	error = VIDEO_GET_INPUT(vd->dev, &idx);
926 	if (error == 0)
927 		*index = idx;
928 	return (error);
929 }
930 
931 static int
932 video_s_input(struct video_device *vd, int *index)
933 {
934 
935 	return (VIDEO_SET_INPUT(vd->dev, *index));
936 }
937 
938 static int
939 video_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
940     struct thread *td)
941 {
942 	struct video_device *vd = dev->si_drv1;
943 	struct video_file *vf;
944 	int error;
945 
946 	if (vd == NULL || vd->dying)
947 		return (ENXIO);
948 
949 	error = devfs_get_cdevpriv((void **)&vf);
950 	if (error != 0)
951 		return (error);
952 
953 	switch (cmd) {
954 	case VIDIOC_QUERYCAP:
955 		return (video_querycap(vd, (struct v4l2_capability *)data));
956 	case VIDIOC_ENUM_FMT:
957 		return (video_enum_fmt(vd, (struct v4l2_fmtdesc *)data));
958 	case VIDIOC_G_FMT:
959 		return (video_g_fmt(vd, (struct v4l2_format *)data));
960 	case VIDIOC_S_FMT:
961 		return (video_s_fmt(vd, vf, (struct v4l2_format *)data));
962 	case VIDIOC_TRY_FMT:
963 		return (video_try_fmt(vd, (struct v4l2_format *)data));
964 	case VIDIOC_REQBUFS:
965 		return (video_reqbufs(vd, vf,
966 		    (struct v4l2_requestbuffers *)data));
967 	case VIDIOC_QUERYBUF:
968 		return (video_querybuf(vd, vf, (struct v4l2_buffer *)data));
969 	case VIDIOC_QBUF:
970 		return (video_qbuf(vd, vf, (struct v4l2_buffer *)data));
971 	case VIDIOC_DQBUF:
972 		return (video_dqbuf(vd, vf, (struct v4l2_buffer *)data,
973 		    fflag));
974 	case VIDIOC_STREAMON:
975 		return (video_streamon(vd, vf, (int *)data));
976 	case VIDIOC_STREAMOFF:
977 		return (video_streamoff(vd, vf, (int *)data));
978 	case VIDIOC_G_PARM:
979 		return (video_g_parm(vd, (struct v4l2_streamparm *)data));
980 	case VIDIOC_S_PARM:
981 		return (video_s_parm(vd, (struct v4l2_streamparm *)data));
982 	case VIDIOC_QUERYCTRL:
983 		return (video_queryctrl(vd, (struct v4l2_queryctrl *)data));
984 	case VIDIOC_G_CTRL:
985 		return (video_g_ctrl(vd, (struct v4l2_control *)data));
986 	case VIDIOC_S_CTRL:
987 		return (video_s_ctrl(vd, (struct v4l2_control *)data));
988 	case VIDIOC_ENUMINPUT:
989 		return (video_enum_input(vd, (struct v4l2_input *)data));
990 	case VIDIOC_G_INPUT:
991 		return (video_g_input(vd, (int *)data));
992 	case VIDIOC_S_INPUT:
993 		return (video_s_input(vd, (int *)data));
994 	case VIDIOC_ENUM_FRAMESIZES:
995 		return (video_enum_framesizes(vd,
996 		    (struct v4l2_frmsizeenum *)data));
997 	case VIDIOC_ENUM_FRAMEINTERVALS:
998 		return (video_enum_frameintervals(vd,
999 		    (struct v4l2_frmivalenum *)data));
1000 	default:
1001 		return (ENOTTY);
1002 	}
1003 }
1004 
1005 static int
1006 video_read(struct cdev *dev, struct uio *uio, int ioflag)
1007 {
1008 	struct video_device *vd = dev->si_drv1;
1009 	struct video_buf_pool *pool;
1010 	struct video_file *vf;
1011 	struct video_buf *vb;
1012 	uint8_t *src;
1013 	size_t bytesused, chunk, offset;
1014 	int error;
1015 
1016 	if (vd == NULL || vd->dying)
1017 		return (ENXIO);
1018 
1019 	error = devfs_get_cdevpriv((void **)&vf);
1020 	if (error != 0)
1021 		return (error);
1022 
1023 	mtx_lock(&vd->mtx);
1024 	while (vf->reading) {
1025 		error = msleep(&vf->reading, &vd->mtx, PCATCH, "vrdser", 0);
1026 		if (error != 0) {
1027 			mtx_unlock(&vd->mtx);
1028 			return (error);
1029 		}
1030 	}
1031 	vf->reading = true;
1032 	mtx_unlock(&vd->mtx);
1033 
1034 	sx_xlock(&vd->cfg_sx);
1035 	error = video_claim_owner(vd, vf);
1036 	if (error != 0) {
1037 		sx_xunlock(&vd->cfg_sx);
1038 		goto out;
1039 	}
1040 
1041 	if (!vd->streaming) {
1042 		if (vd->mode == VMODE_MMAP) {
1043 			sx_xunlock(&vd->cfg_sx);
1044 			error = EBUSY;
1045 			goto out;
1046 		}
1047 
1048 		if (vd->format.sizeimage == 0) {
1049 			error = VIDEO_GET_FORMAT(vd->dev, &vd->format);
1050 			if (error != 0 || vd->format.sizeimage == 0) {
1051 				sx_xunlock(&vd->cfg_sx);
1052 				if (error == 0)
1053 					error = EIO;
1054 				goto out;
1055 			}
1056 		}
1057 
1058 		if (vd->pool == NULL) {
1059 			pool = video_pool_alloc(VIDEO_READ_BUFFERS,
1060 			    vd->format.sizeimage);
1061 			if (pool == NULL) {
1062 				sx_xunlock(&vd->cfg_sx);
1063 				error = ENOMEM;
1064 				goto out;
1065 			}
1066 			mtx_lock(&vd->mtx);
1067 			vd->pool = pool;
1068 			mtx_unlock(&vd->mtx);
1069 		}
1070 		vd->mode = VMODE_READ;
1071 
1072 		mtx_lock(&vd->mtx);
1073 		for (u_int i = 0; i < vd->pool->nbufs; i++) {
1074 			vb = &vd->pool->bufs[i];
1075 			vb->state = VB_QUEUED;
1076 			vb->vd = vd;
1077 			STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
1078 		}
1079 		mtx_unlock(&vd->mtx);
1080 
1081 		error = VIDEO_START_STREAM(vd->dev);
1082 		if (error != 0) {
1083 			video_pool_detach(vd);
1084 			vd->mode = VMODE_NONE;
1085 			sx_xunlock(&vd->cfg_sx);
1086 			goto out;
1087 		}
1088 
1089 		mtx_lock(&vd->mtx);
1090 		vd->streaming = true;
1091 		mtx_unlock(&vd->mtx);
1092 	}
1093 	sx_xunlock(&vd->cfg_sx);
1094 
1095 	mtx_lock(&vd->mtx);
1096 	while (vf->read_buf == NULL) {
1097 		if (!STAILQ_EMPTY(&vd->done)) {
1098 			vf->read_buf = STAILQ_FIRST(&vd->done);
1099 			STAILQ_REMOVE_HEAD(&vd->done, entry);
1100 			vf->read_offset = 0;
1101 			break;
1102 		}
1103 		if (!vd->streaming || vd->stopping) {
1104 			mtx_unlock(&vd->mtx);
1105 			error = EIO;
1106 			goto out;
1107 		}
1108 		if (ioflag & O_NONBLOCK) {
1109 			mtx_unlock(&vd->mtx);
1110 			error = EAGAIN;
1111 			goto out;
1112 		}
1113 		error = msleep(&vd->done, &vd->mtx, PCATCH, "vread", 0);
1114 		if (error != 0) {
1115 			mtx_unlock(&vd->mtx);
1116 			goto out;
1117 		}
1118 	}
1119 
1120 	vb = vf->read_buf;
1121 	bytesused = vb->bytesused;
1122 	offset = vf->read_offset;
1123 	chunk = 0;
1124 	if (uio->uio_resid > 0 && offset < bytesused) {
1125 		chunk = MIN((size_t)uio->uio_resid, bytesused - offset);
1126 		src = (uint8_t *)vb->buf + offset;
1127 		vd->readers++;
1128 		mtx_unlock(&vd->mtx);
1129 
1130 		error = uiomove(src, chunk, uio);
1131 
1132 		mtx_lock(&vd->mtx);
1133 		if (--vd->readers == 0)
1134 			wakeup(&vd->readers);
1135 		if (error != 0) {
1136 			mtx_unlock(&vd->mtx);
1137 			goto out;
1138 		}
1139 	}
1140 
1141 	if (vf->read_buf == vb) {
1142 		vf->read_offset = offset + chunk;
1143 		if (vf->read_offset >= bytesused) {
1144 			vf->read_buf = NULL;
1145 			vf->read_offset = 0;
1146 			vb->state = VB_QUEUED;
1147 			vb->bytesused = 0;
1148 			STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
1149 		}
1150 	}
1151 	mtx_unlock(&vd->mtx);
1152 
1153 	error = 0;
1154 out:
1155 	mtx_lock(&vd->mtx);
1156 	vf->reading = false;
1157 	wakeup(&vf->reading);
1158 	mtx_unlock(&vd->mtx);
1159 	return (error);
1160 }
1161 
1162 static int
1163 video_poll(struct cdev *dev, int events, struct thread *td)
1164 {
1165 	struct video_device *vd = dev->si_drv1;
1166 	int revents = 0;
1167 
1168 	if (vd == NULL || vd->dying)
1169 		return (POLLHUP);
1170 
1171 	mtx_lock(&vd->mtx);
1172 	if (events & (POLLIN | POLLRDNORM)) {
1173 		if (!STAILQ_EMPTY(&vd->done))
1174 			revents |= events & (POLLIN | POLLRDNORM);
1175 		else
1176 			selrecord(td, &vd->sel);
1177 	}
1178 	mtx_unlock(&vd->mtx);
1179 	return (revents);
1180 }
1181 
1182 static void video_kqfilter_detach(struct knote *kn);
1183 static int video_kqfilter_event(struct knote *kn, long hint);
1184 
1185 static const struct filterops video_read_filterops = {
1186 	.f_isfd =	1,
1187 	.f_detach =	video_kqfilter_detach,
1188 	.f_event =	video_kqfilter_event,
1189 };
1190 
1191 static void
1192 video_kqfilter_detach(struct knote *kn)
1193 {
1194 	struct video_device *vd = kn->kn_hook;
1195 
1196 	knlist_remove(&vd->sel.si_note, kn, 0);
1197 }
1198 
1199 static int
1200 video_kqfilter_event(struct knote *kn, long hint)
1201 {
1202 	struct video_device *vd = kn->kn_hook;
1203 
1204 	if (!STAILQ_EMPTY(&vd->done)) {
1205 		kn->kn_data = 1;
1206 		return (1);
1207 	}
1208 	return (0);
1209 }
1210 
1211 static int
1212 video_kqfilter(struct cdev *dev, struct knote *kn)
1213 {
1214 	struct video_device *vd = dev->si_drv1;
1215 
1216 	if (vd == NULL || vd->dying)
1217 		return (ENXIO);
1218 
1219 	switch (kn->kn_filter) {
1220 	case EVFILT_READ:
1221 		kn->kn_fop = &video_read_filterops;
1222 		kn->kn_hook = vd;
1223 		knlist_add(&vd->sel.si_note, kn, 0);
1224 		return (0);
1225 	default:
1226 		return (EINVAL);
1227 	}
1228 }
1229 
1230 static int
1231 video_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
1232     vm_object_t *objp, int nprot)
1233 {
1234 	struct video_device *vd = dev->si_drv1;
1235 	struct video_file *vf;
1236 	int error;
1237 
1238 	if (vd == NULL || vd->dying)
1239 		return (ENXIO);
1240 
1241 	error = devfs_get_cdevpriv((void **)&vf);
1242 	if (error != 0)
1243 		return (error);
1244 
1245 	sx_slock(&vd->cfg_sx);
1246 	if (vd->owner != vf || vd->pool == NULL || vd->mode != VMODE_MMAP) {
1247 		sx_sunlock(&vd->cfg_sx);
1248 		return (EINVAL);
1249 	}
1250 
1251 	if (*offset >= vd->pool->map_size ||
1252 	    size > vd->pool->map_size - *offset) {
1253 		sx_sunlock(&vd->cfg_sx);
1254 		return (EINVAL);
1255 	}
1256 
1257 	/*
1258 	 * Hand out a reference to the object backing the whole pool; the
1259 	 * offset selects which buffer within it gets mapped.  The VM system
1260 	 * tracks the mapping lifetime through the object reference count,
1261 	 * so no per-mapping bookkeeping is needed here.
1262 	 */
1263 	vm_object_reference(vd->pool->obj);
1264 	*objp = vd->pool->obj;
1265 	sx_sunlock(&vd->cfg_sx);
1266 
1267 	return (0);
1268 }
1269 
1270 int
1271 video_register(device_t dev, struct video_device **vdp)
1272 {
1273 	struct make_dev_args args;
1274 	struct video_device *vd;
1275 	int taken[VIDEO_UNIT_RETRIES];
1276 	int collisions, error, unit;
1277 
1278 	vd = malloc(sizeof(*vd), M_VIDEO, M_WAITOK | M_ZERO);
1279 	vd->dev = dev;
1280 
1281 	sx_init(&vd->cfg_sx, "video_cfg");
1282 	mtx_init(&vd->mtx, "video_mtx", NULL, MTX_DEF);
1283 	STAILQ_INIT(&vd->queued);
1284 	STAILQ_INIT(&vd->done);
1285 	knlist_init_mtx(&vd->sel.si_note, &vd->mtx);
1286 
1287 	error = EEXIST;
1288 	for (collisions = 0; collisions < VIDEO_UNIT_RETRIES; collisions++) {
1289 		taken[collisions] = unit = alloc_unr(video_unrhdr);
1290 
1291 		make_dev_args_init(&args);
1292 		args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
1293 		args.mda_devsw = &video_cdevsw;
1294 		args.mda_uid = UID_ROOT;
1295 		args.mda_gid = GID_VIDEO;
1296 		args.mda_mode = 0660;
1297 		args.mda_unit = unit;
1298 		args.mda_si_drv1 = vd;
1299 
1300 		error = make_dev_s(&args, &vd->cdev, "video%d", unit);
1301 		if (error != EEXIST)
1302 			break;
1303 	}
1304 
1305 	while (collisions > 0)
1306 		free_unr(video_unrhdr, taken[--collisions]);
1307 
1308 	if (error != 0) {
1309 		free_unr(video_unrhdr, unit);
1310 		device_printf(dev, "failed to create a /dev/video node: %d\n",
1311 		    error);
1312 		knlist_destroy(&vd->sel.si_note);
1313 		mtx_destroy(&vd->mtx);
1314 		sx_destroy(&vd->cfg_sx);
1315 		free(vd, M_VIDEO);
1316 		return (error);
1317 	}
1318 	vd->unit = unit;
1319 
1320 	*vdp = vd;
1321 	device_printf(dev, "registered as /dev/video%d\n", unit);
1322 	return (0);
1323 }
1324 
1325 void
1326 video_unregister(struct video_device *vd)
1327 {
1328 
1329 	sx_xlock(&vd->cfg_sx);
1330 	vd->dying = true;
1331 
1332 	if (vd->streaming) {
1333 		mtx_lock(&vd->mtx);
1334 		vd->stopping = true;
1335 		wakeup(&vd->done);
1336 		mtx_unlock(&vd->mtx);
1337 
1338 		VIDEO_STOP_STREAM(vd->dev);
1339 
1340 		mtx_lock(&vd->mtx);
1341 		vd->streaming = false;
1342 		vd->stopping = false;
1343 		STAILQ_INIT(&vd->queued);
1344 		STAILQ_INIT(&vd->done);
1345 		mtx_unlock(&vd->mtx);
1346 	}
1347 
1348 	sx_xunlock(&vd->cfg_sx);
1349 
1350 	destroy_dev(vd->cdev);
1351 	free_unr(video_unrhdr, vd->unit);
1352 
1353 	video_pool_detach(vd);
1354 
1355 	knlist_destroy(&vd->sel.si_note);
1356 	mtx_destroy(&vd->mtx);
1357 	sx_destroy(&vd->cfg_sx);
1358 
1359 	free(vd, M_VIDEO);
1360 }
1361 
1362 static int
1363 video_modevent(module_t mod, int type, void *data)
1364 {
1365 
1366 	switch (type) {
1367 	case MOD_LOAD:
1368 		video_unrhdr = new_unrhdr(0, INT_MAX, NULL);
1369 		return (0);
1370 	case MOD_UNLOAD:
1371 		delete_unrhdr(video_unrhdr);
1372 		return (0);
1373 	default:
1374 		return (EOPNOTSUPP);
1375 	}
1376 }
1377 
1378 static moduledata_t video_mod = {
1379 	"video",
1380 	video_modevent,
1381 	NULL,
1382 };
1383 
1384 DECLARE_MODULE(video, video_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1385 MODULE_VERSION(video, 1);
1386