xref: /freebsd/sys/dev/video/video.c (revision f5dc2263ab1be8a35a7e27e82103f9ccd41ae584)
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 	wakeup(&vd->done);
307 	mtx_unlock(&vd->mtx);
308 }
309 
310 void
311 video_buf_error(struct video_buf *vb)
312 {
313 	struct video_device *vd = vb->vd;
314 
315 	mtx_lock(&vd->mtx);
316 	if (vb->state != VB_ACTIVE) {
317 		mtx_unlock(&vd->mtx);
318 		return;
319 	}
320 	vb->bytesused = 0;
321 	vb->flags = V4L2_BUF_FLAG_ERROR;
322 	getmicrouptime(&vb->timestamp);
323 	vb->state = VB_ERROR;
324 	STAILQ_INSERT_TAIL(&vd->done, vb, entry);
325 	selwakeup(&vd->sel);
326 	wakeup(&vd->done);
327 	mtx_unlock(&vd->mtx);
328 }
329 
330 static int
331 video_querycap(struct video_device *vd, struct v4l2_capability *cap)
332 {
333 	struct video_caps vc;
334 	int error;
335 
336 	memset(&vc, 0, sizeof(vc));
337 	error = VIDEO_QUERYCAP(vd->dev, &vc);
338 	if (error != 0)
339 		return (error);
340 
341 	memset(cap, 0, sizeof(*cap));
342 	strlcpy((char *)cap->driver, vc.driver, sizeof(cap->driver));
343 	strlcpy((char *)cap->card, vc.card, sizeof(cap->card));
344 	strlcpy((char *)cap->bus_info, vc.bus_info, sizeof(cap->bus_info));
345 	cap->version = vc.version;
346 	cap->device_caps = vc.capabilities;
347 	cap->capabilities = vc.capabilities | V4L2_CAP_DEVICE_CAPS;
348 	return (0);
349 }
350 
351 static int
352 video_enum_fmt(struct video_device *vd, struct v4l2_fmtdesc *fd)
353 {
354 	struct video_format vf;
355 	int error;
356 
357 	if (fd->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
358 		return (EINVAL);
359 
360 	memset(&vf, 0, sizeof(vf));
361 	error = VIDEO_ENUM_FORMAT(vd->dev, fd->index, &vf);
362 	if (error != 0)
363 		return (error);
364 
365 	fd->pixelformat = vf.pixelformat;
366 	fd->flags = vf.flags;
367 	strlcpy((char *)fd->description, vf.description,
368 	    sizeof(fd->description));
369 	return (0);
370 }
371 
372 static int
373 video_g_fmt(struct video_device *vd, struct v4l2_format *f)
374 {
375 	struct video_format vf;
376 	int error;
377 
378 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
379 		return (EINVAL);
380 
381 	memset(&vf, 0, sizeof(vf));
382 	error = VIDEO_GET_FORMAT(vd->dev, &vf);
383 	if (error != 0)
384 		return (error);
385 
386 	memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
387 	f->fmt.pix.width = vf.width;
388 	f->fmt.pix.height = vf.height;
389 	f->fmt.pix.pixelformat = vf.pixelformat;
390 	f->fmt.pix.field = vf.field;
391 	f->fmt.pix.bytesperline = vf.bytesperline;
392 	f->fmt.pix.sizeimage = vf.sizeimage;
393 	f->fmt.pix.colorspace = vf.colorspace;
394 	f->fmt.pix.xfer_func = vf.xfer_func;
395 	f->fmt.pix.ycbcr_enc = vf.ycbcr_enc;
396 	f->fmt.pix.flags = vf.flags;
397 	return (0);
398 }
399 
400 static int
401 video_s_fmt(struct video_device *vd, struct video_file *vf,
402     struct v4l2_format *f)
403 {
404 	struct video_format fmt;
405 	int error;
406 
407 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
408 		return (EINVAL);
409 
410 	sx_xlock(&vd->cfg_sx);
411 	error = video_claim_owner(vd, vf);
412 	if (error != 0) {
413 		sx_xunlock(&vd->cfg_sx);
414 		return (error);
415 	}
416 	if (vd->streaming) {
417 		sx_xunlock(&vd->cfg_sx);
418 		return (EBUSY);
419 	}
420 
421 	memset(&fmt, 0, sizeof(fmt));
422 	fmt.width = f->fmt.pix.width;
423 	fmt.height = f->fmt.pix.height;
424 	fmt.pixelformat = f->fmt.pix.pixelformat;
425 	fmt.field = f->fmt.pix.field;
426 
427 	error = VIDEO_SET_FORMAT(vd->dev, &fmt);
428 	if (error == 0) {
429 		VIDEO_GET_FORMAT(vd->dev, &vd->format);
430 
431 		f->fmt.pix.width = vd->format.width;
432 		f->fmt.pix.height = vd->format.height;
433 		f->fmt.pix.pixelformat = vd->format.pixelformat;
434 		f->fmt.pix.field = vd->format.field;
435 		f->fmt.pix.bytesperline = vd->format.bytesperline;
436 		f->fmt.pix.sizeimage = vd->format.sizeimage;
437 		f->fmt.pix.colorspace = vd->format.colorspace;
438 	}
439 	sx_xunlock(&vd->cfg_sx);
440 	return (error);
441 }
442 
443 static int
444 video_try_fmt(struct video_device *vd, struct v4l2_format *f)
445 {
446 	struct video_format fmt;
447 	int error;
448 
449 	if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
450 		return (EINVAL);
451 	memset(&fmt, 0, sizeof(fmt));
452 	fmt.width = f->fmt.pix.width;
453 	fmt.height = f->fmt.pix.height;
454 	fmt.pixelformat = f->fmt.pix.pixelformat;
455 	fmt.field = f->fmt.pix.field;
456 
457 	error = VIDEO_TRY_FORMAT(vd->dev, &fmt);
458 	if (error == 0) {
459 		f->fmt.pix.width = fmt.width;
460 		f->fmt.pix.height = fmt.height;
461 		f->fmt.pix.pixelformat = fmt.pixelformat;
462 		f->fmt.pix.field = fmt.field;
463 		f->fmt.pix.bytesperline = fmt.bytesperline;
464 		f->fmt.pix.sizeimage = fmt.sizeimage;
465 		f->fmt.pix.colorspace = fmt.colorspace;
466 	}
467 	return (error);
468 }
469 
470 static int
471 video_reqbufs(struct video_device *vd, struct video_file *vf,
472     struct v4l2_requestbuffers *rb)
473 {
474 	struct video_buf_pool *pool;
475 	int error;
476 
477 	if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
478 		return (EINVAL);
479 	if (rb->memory != V4L2_MEMORY_MMAP)
480 		return (EINVAL);
481 
482 	sx_xlock(&vd->cfg_sx);
483 	error = video_claim_owner(vd, vf);
484 	if (error != 0) {
485 		sx_xunlock(&vd->cfg_sx);
486 		return (error);
487 	}
488 	if (vd->streaming) {
489 		sx_xunlock(&vd->cfg_sx);
490 		return (EBUSY);
491 	}
492 
493 	video_pool_detach(vd);
494 
495 	if (rb->count == 0) {
496 		vd->mode = VMODE_NONE;
497 		sx_xunlock(&vd->cfg_sx);
498 		rb->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP;
499 		return (0);
500 	}
501 
502 	if (rb->count > VIDEO_MAX_BUFFERS)
503 		rb->count = VIDEO_MAX_BUFFERS;
504 	if (rb->count < 2)
505 		rb->count = 2;
506 
507 	if (vd->format.sizeimage == 0) {
508 		error = VIDEO_GET_FORMAT(vd->dev, &vd->format);
509 		if (error != 0 || vd->format.sizeimage == 0) {
510 			sx_xunlock(&vd->cfg_sx);
511 			return (error != 0 ? error : EINVAL);
512 		}
513 	}
514 
515 	pool = video_pool_alloc(rb->count, vd->format.sizeimage);
516 	if (pool == NULL) {
517 		sx_xunlock(&vd->cfg_sx);
518 		return (ENOMEM);
519 	}
520 	mtx_lock(&vd->mtx);
521 	vd->pool = pool;
522 	mtx_unlock(&vd->mtx);
523 
524 	vd->mode = VMODE_MMAP;
525 	rb->capabilities = V4L2_BUF_CAP_SUPPORTS_MMAP;
526 	sx_xunlock(&vd->cfg_sx);
527 	return (0);
528 }
529 
530 static int
531 video_querybuf(struct video_device *vd, struct video_file *vf,
532     struct v4l2_buffer *b)
533 {
534 	struct video_buf *vb;
535 
536 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
537 		return (EINVAL);
538 
539 	mtx_lock(&vd->mtx);
540 	if (vd->owner != vf) {
541 		mtx_unlock(&vd->mtx);
542 		return (EPERM);
543 	}
544 	if (vd->pool == NULL || b->index >= vd->pool->nbufs) {
545 		mtx_unlock(&vd->mtx);
546 		return (EINVAL);
547 	}
548 
549 	vb = &vd->pool->bufs[b->index];
550 	b->memory = V4L2_MEMORY_MMAP;
551 	b->length = vb->length;
552 	b->m.offset = vb->index * vd->pool->buf_size;
553 	b->bytesused = vb->bytesused;
554 	b->field = V4L2_FIELD_NONE;
555 	b->timestamp = vb->timestamp;
556 	b->sequence = vb->sequence;
557 	b->flags = 0;
558 
559 	switch (vb->state) {
560 	case VB_QUEUED:
561 	case VB_ACTIVE:
562 		b->flags |= V4L2_BUF_FLAG_QUEUED;
563 		break;
564 	case VB_DONE:
565 		b->flags |= V4L2_BUF_FLAG_DONE;
566 		break;
567 	case VB_ERROR:
568 		b->flags |= V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR;
569 		break;
570 	default:
571 		break;
572 	}
573 	b->flags |= V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
574 	mtx_unlock(&vd->mtx);
575 	return (0);
576 }
577 
578 static int
579 video_qbuf(struct video_device *vd, struct video_file *vf,
580     struct v4l2_buffer *b)
581 {
582 	struct video_buf *vb;
583 
584 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
585 		return (EINVAL);
586 	if (b->memory != V4L2_MEMORY_MMAP)
587 		return (EINVAL);
588 
589 	mtx_lock(&vd->mtx);
590 	if (vd->owner != vf) {
591 		mtx_unlock(&vd->mtx);
592 		return (EPERM);
593 	}
594 	if (vd->pool == NULL || vd->mode != VMODE_MMAP ||
595 	    b->index >= vd->pool->nbufs) {
596 		mtx_unlock(&vd->mtx);
597 		return (EINVAL);
598 	}
599 
600 	vb = &vd->pool->bufs[b->index];
601 	if (vb->state != VB_IDLE) {
602 		mtx_unlock(&vd->mtx);
603 		return (EINVAL);
604 	}
605 
606 	vb->state = VB_QUEUED;
607 	vb->bytesused = 0;
608 	vb->vd = vd;
609 	STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
610 	mtx_unlock(&vd->mtx);
611 
612 	b->flags = V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_MAPPED;
613 	return (0);
614 }
615 
616 static int
617 video_dqbuf(struct video_device *vd, struct video_file *vf,
618     struct v4l2_buffer *b, int flags)
619 {
620 	struct video_buf *vb;
621 	int error;
622 
623 	if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
624 		return (EINVAL);
625 	if (b->memory != V4L2_MEMORY_MMAP)
626 		return (EINVAL);
627 
628 	mtx_lock(&vd->mtx);
629 	if (vd->owner != vf) {
630 		mtx_unlock(&vd->mtx);
631 		return (EPERM);
632 	}
633 	while (STAILQ_EMPTY(&vd->done)) {
634 		if (!vd->streaming || vd->stopping) {
635 			mtx_unlock(&vd->mtx);
636 			return (EINVAL);
637 		}
638 		if (flags & O_NONBLOCK) {
639 			mtx_unlock(&vd->mtx);
640 			return (EAGAIN);
641 		}
642 		error = msleep(&vd->done, &vd->mtx, PCATCH, "vdqbuf", 0);
643 		if (error != 0) {
644 			mtx_unlock(&vd->mtx);
645 			return (error);
646 		}
647 	}
648 
649 	vb = STAILQ_FIRST(&vd->done);
650 	STAILQ_REMOVE_HEAD(&vd->done, entry);
651 
652 	b->index = vb->index;
653 	b->bytesused = vb->bytesused;
654 	b->field = V4L2_FIELD_NONE;
655 	b->timestamp = vb->timestamp;
656 	b->sequence = vb->sequence;
657 	b->memory = V4L2_MEMORY_MMAP;
658 	b->m.offset = vb->index * vd->pool->buf_size;
659 	b->length = vb->length;
660 	b->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE |
661 	    V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
662 	if (vb->flags & V4L2_BUF_FLAG_ERROR)
663 		b->flags |= V4L2_BUF_FLAG_ERROR;
664 
665 	vb->state = VB_IDLE;
666 	mtx_unlock(&vd->mtx);
667 
668 	return (0);
669 }
670 
671 static int
672 video_streamon(struct video_device *vd, struct video_file *vf, int *type)
673 {
674 	int error;
675 
676 	if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
677 		return (EINVAL);
678 
679 	sx_xlock(&vd->cfg_sx);
680 	error = video_claim_owner(vd, vf);
681 	if (error != 0) {
682 		sx_xunlock(&vd->cfg_sx);
683 		return (error);
684 	}
685 	if (vd->streaming) {
686 		sx_xunlock(&vd->cfg_sx);
687 		return (0);
688 	}
689 	if (vd->pool == NULL || vd->mode != VMODE_MMAP) {
690 		sx_xunlock(&vd->cfg_sx);
691 		return (EINVAL);
692 	}
693 
694 	error = VIDEO_START_STREAM(vd->dev);
695 	if (error != 0) {
696 		sx_xunlock(&vd->cfg_sx);
697 		return (error);
698 	}
699 
700 	mtx_lock(&vd->mtx);
701 	vd->streaming = true;
702 	mtx_unlock(&vd->mtx);
703 
704 	sx_xunlock(&vd->cfg_sx);
705 	return (0);
706 }
707 
708 static int
709 video_streamoff(struct video_device *vd, struct video_file *vf, int *type)
710 {
711 	struct video_buf *vb;
712 	u_int i;
713 
714 	if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
715 		return (EINVAL);
716 
717 	sx_xlock(&vd->cfg_sx);
718 	if (vd->owner != vf) {
719 		sx_xunlock(&vd->cfg_sx);
720 		return (EBUSY);
721 	}
722 	if (!vd->streaming) {
723 		sx_xunlock(&vd->cfg_sx);
724 		return (0);
725 	}
726 
727 	mtx_lock(&vd->mtx);
728 	vd->stopping = true;
729 	wakeup(&vd->done);
730 	mtx_unlock(&vd->mtx);
731 
732 	VIDEO_STOP_STREAM(vd->dev);
733 
734 	mtx_lock(&vd->mtx);
735 	vd->streaming = false;
736 	vd->stopping = false;
737 	STAILQ_INIT(&vd->queued);
738 	STAILQ_INIT(&vd->done);
739 	for (i = 0; i < vd->pool->nbufs; i++) {
740 		vb = &vd->pool->bufs[i];
741 		vb->state = VB_IDLE;
742 		vb->bytesused = 0;
743 		vb->vd = NULL;
744 	}
745 	vf->read_buf = NULL;
746 	vf->read_offset = 0;
747 	mtx_unlock(&vd->mtx);
748 
749 	sx_xunlock(&vd->cfg_sx);
750 	return (0);
751 }
752 
753 static int
754 video_g_parm(struct video_device *vd, struct v4l2_streamparm *sp)
755 {
756 	struct video_fract fract;
757 	int error;
758 
759 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
760 		return (EINVAL);
761 	memset(&fract, 0, sizeof(fract));
762 	error = VIDEO_GET_PARM(vd->dev, &fract);
763 	if (error != 0)
764 		return (error);
765 
766 	memset(&sp->parm.capture, 0, sizeof(sp->parm.capture));
767 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
768 	sp->parm.capture.timeperframe.numerator = fract.numerator;
769 	sp->parm.capture.timeperframe.denominator = fract.denominator;
770 	return (0);
771 }
772 
773 static int
774 video_s_parm(struct video_device *vd, struct v4l2_streamparm *sp)
775 {
776 	struct video_fract fract;
777 	int error;
778 
779 	if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
780 		return (EINVAL);
781 	fract.numerator = sp->parm.capture.timeperframe.numerator;
782 	fract.denominator = sp->parm.capture.timeperframe.denominator;
783 
784 	error = VIDEO_SET_PARM(vd->dev, &fract);
785 	if (error != 0)
786 		return (error);
787 
788 	sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
789 	sp->parm.capture.timeperframe.numerator = fract.numerator;
790 	sp->parm.capture.timeperframe.denominator = fract.denominator;
791 	return (0);
792 }
793 
794 static int
795 video_queryctrl(struct video_device *vd, struct v4l2_queryctrl *qc)
796 {
797 	struct video_control_desc desc;
798 	int error;
799 
800 	memset(&desc, 0, sizeof(desc));
801 	desc.id = qc->id;
802 	error = VIDEO_QUERY_CONTROL(vd->dev, &desc);
803 	if (error != 0)
804 		return (error);
805 
806 	qc->id = desc.id;
807 	qc->type = desc.type;
808 	strlcpy((char *)qc->name, desc.name, sizeof(qc->name));
809 	qc->minimum = desc.minimum;
810 	qc->maximum = desc.maximum;
811 	qc->step = desc.step;
812 	qc->default_value = desc.default_value;
813 	qc->flags = desc.flags;
814 	return (0);
815 }
816 
817 static int
818 video_g_ctrl(struct video_device *vd, struct v4l2_control *c)
819 {
820 	struct video_control vc;
821 	int error;
822 
823 	vc.id = c->id;
824 	vc.value = 0;
825 	error = VIDEO_GET_CONTROL(vd->dev, &vc);
826 	if (error == 0)
827 		c->value = vc.value;
828 	return (error);
829 }
830 
831 static int
832 video_s_ctrl(struct video_device *vd, struct v4l2_control *c)
833 {
834 	struct video_control vc;
835 
836 	vc.id = c->id;
837 	vc.value = c->value;
838 	return (VIDEO_SET_CONTROL(vd->dev, &vc));
839 }
840 
841 static int
842 video_enum_framesizes(struct video_device *vd, struct v4l2_frmsizeenum *fs)
843 {
844 	struct video_frmsizeenum vfs;
845 	int error;
846 
847 	memset(&vfs, 0, sizeof(vfs));
848 	vfs.index = fs->index;
849 	vfs.pixelformat = fs->pixel_format;
850 	error = VIDEO_ENUM_FRAMESIZES(vd->dev, &vfs);
851 	if (error != 0)
852 		return (error);
853 
854 	fs->type = vfs.type;
855 	if (vfs.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
856 		fs->discrete.width = vfs.discrete.width;
857 		fs->discrete.height = vfs.discrete.height;
858 	} else {
859 		fs->stepwise.min_width = vfs.stepwise.min_width;
860 		fs->stepwise.max_width = vfs.stepwise.max_width;
861 		fs->stepwise.step_width = vfs.stepwise.step_width;
862 		fs->stepwise.min_height = vfs.stepwise.min_height;
863 		fs->stepwise.max_height = vfs.stepwise.max_height;
864 		fs->stepwise.step_height = vfs.stepwise.step_height;
865 	}
866 	return (0);
867 }
868 
869 static int
870 video_enum_frameintervals(struct video_device *vd,
871     struct v4l2_frmivalenum *fi)
872 {
873 	struct video_frmivalenum vfi;
874 	int error;
875 
876 	memset(&vfi, 0, sizeof(vfi));
877 	vfi.index = fi->index;
878 	vfi.pixelformat = fi->pixel_format;
879 	vfi.width = fi->width;
880 	vfi.height = fi->height;
881 	error = VIDEO_ENUM_FRAMEINTERVALS(vd->dev, &vfi);
882 	if (error != 0)
883 		return (error);
884 
885 	fi->type = vfi.type;
886 	if (vfi.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
887 		fi->discrete.numerator = vfi.discrete.numerator;
888 		fi->discrete.denominator = vfi.discrete.denominator;
889 	} else {
890 		fi->stepwise.min.numerator = vfi.stepwise.min.numerator;
891 		fi->stepwise.min.denominator = vfi.stepwise.min.denominator;
892 		fi->stepwise.max.numerator = vfi.stepwise.max.numerator;
893 		fi->stepwise.max.denominator = vfi.stepwise.max.denominator;
894 		fi->stepwise.step.numerator = vfi.stepwise.step.numerator;
895 		fi->stepwise.step.denominator = vfi.stepwise.step.denominator;
896 	}
897 	return (0);
898 }
899 
900 static int
901 video_enum_input(struct video_device *vd, struct v4l2_input *inp)
902 {
903 	struct video_input vi;
904 	int error;
905 
906 	memset(&vi, 0, sizeof(vi));
907 	error = VIDEO_ENUM_INPUT(vd->dev, inp->index, &vi);
908 	if (error != 0)
909 		return (error);
910 
911 	strlcpy((char *)inp->name, vi.name, sizeof(inp->name));
912 	inp->type = vi.type;
913 	return (0);
914 }
915 
916 static int
917 video_g_input(struct video_device *vd, int *index)
918 {
919 	uint32_t idx;
920 	int error;
921 
922 	error = VIDEO_GET_INPUT(vd->dev, &idx);
923 	if (error == 0)
924 		*index = idx;
925 	return (error);
926 }
927 
928 static int
929 video_s_input(struct video_device *vd, int *index)
930 {
931 
932 	return (VIDEO_SET_INPUT(vd->dev, *index));
933 }
934 
935 static int
936 video_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
937     struct thread *td)
938 {
939 	struct video_device *vd = dev->si_drv1;
940 	struct video_file *vf;
941 	int error;
942 
943 	if (vd == NULL || vd->dying)
944 		return (ENXIO);
945 
946 	error = devfs_get_cdevpriv((void **)&vf);
947 	if (error != 0)
948 		return (error);
949 
950 	switch (cmd) {
951 	case VIDIOC_QUERYCAP:
952 		return (video_querycap(vd, (struct v4l2_capability *)data));
953 	case VIDIOC_ENUM_FMT:
954 		return (video_enum_fmt(vd, (struct v4l2_fmtdesc *)data));
955 	case VIDIOC_G_FMT:
956 		return (video_g_fmt(vd, (struct v4l2_format *)data));
957 	case VIDIOC_S_FMT:
958 		return (video_s_fmt(vd, vf, (struct v4l2_format *)data));
959 	case VIDIOC_TRY_FMT:
960 		return (video_try_fmt(vd, (struct v4l2_format *)data));
961 	case VIDIOC_REQBUFS:
962 		return (video_reqbufs(vd, vf,
963 		    (struct v4l2_requestbuffers *)data));
964 	case VIDIOC_QUERYBUF:
965 		return (video_querybuf(vd, vf, (struct v4l2_buffer *)data));
966 	case VIDIOC_QBUF:
967 		return (video_qbuf(vd, vf, (struct v4l2_buffer *)data));
968 	case VIDIOC_DQBUF:
969 		return (video_dqbuf(vd, vf, (struct v4l2_buffer *)data,
970 		    fflag));
971 	case VIDIOC_STREAMON:
972 		return (video_streamon(vd, vf, (int *)data));
973 	case VIDIOC_STREAMOFF:
974 		return (video_streamoff(vd, vf, (int *)data));
975 	case VIDIOC_G_PARM:
976 		return (video_g_parm(vd, (struct v4l2_streamparm *)data));
977 	case VIDIOC_S_PARM:
978 		return (video_s_parm(vd, (struct v4l2_streamparm *)data));
979 	case VIDIOC_QUERYCTRL:
980 		return (video_queryctrl(vd, (struct v4l2_queryctrl *)data));
981 	case VIDIOC_G_CTRL:
982 		return (video_g_ctrl(vd, (struct v4l2_control *)data));
983 	case VIDIOC_S_CTRL:
984 		return (video_s_ctrl(vd, (struct v4l2_control *)data));
985 	case VIDIOC_ENUMINPUT:
986 		return (video_enum_input(vd, (struct v4l2_input *)data));
987 	case VIDIOC_G_INPUT:
988 		return (video_g_input(vd, (int *)data));
989 	case VIDIOC_S_INPUT:
990 		return (video_s_input(vd, (int *)data));
991 	case VIDIOC_ENUM_FRAMESIZES:
992 		return (video_enum_framesizes(vd,
993 		    (struct v4l2_frmsizeenum *)data));
994 	case VIDIOC_ENUM_FRAMEINTERVALS:
995 		return (video_enum_frameintervals(vd,
996 		    (struct v4l2_frmivalenum *)data));
997 	default:
998 		return (ENOTTY);
999 	}
1000 }
1001 
1002 static int
1003 video_read(struct cdev *dev, struct uio *uio, int ioflag)
1004 {
1005 	struct video_device *vd = dev->si_drv1;
1006 	struct video_buf_pool *pool;
1007 	struct video_file *vf;
1008 	struct video_buf *vb;
1009 	uint8_t *src;
1010 	size_t bytesused, chunk, offset;
1011 	int error;
1012 
1013 	if (vd == NULL || vd->dying)
1014 		return (ENXIO);
1015 
1016 	error = devfs_get_cdevpriv((void **)&vf);
1017 	if (error != 0)
1018 		return (error);
1019 
1020 	mtx_lock(&vd->mtx);
1021 	while (vf->reading) {
1022 		error = msleep(&vf->reading, &vd->mtx, PCATCH, "vrdser", 0);
1023 		if (error != 0) {
1024 			mtx_unlock(&vd->mtx);
1025 			return (error);
1026 		}
1027 	}
1028 	vf->reading = true;
1029 	mtx_unlock(&vd->mtx);
1030 
1031 	sx_xlock(&vd->cfg_sx);
1032 	error = video_claim_owner(vd, vf);
1033 	if (error != 0) {
1034 		sx_xunlock(&vd->cfg_sx);
1035 		goto out;
1036 	}
1037 
1038 	if (!vd->streaming) {
1039 		if (vd->mode == VMODE_MMAP) {
1040 			sx_xunlock(&vd->cfg_sx);
1041 			error = EBUSY;
1042 			goto out;
1043 		}
1044 
1045 		if (vd->format.sizeimage == 0) {
1046 			error = VIDEO_GET_FORMAT(vd->dev, &vd->format);
1047 			if (error != 0 || vd->format.sizeimage == 0) {
1048 				sx_xunlock(&vd->cfg_sx);
1049 				if (error == 0)
1050 					error = EIO;
1051 				goto out;
1052 			}
1053 		}
1054 
1055 		if (vd->pool == NULL) {
1056 			pool = video_pool_alloc(VIDEO_READ_BUFFERS,
1057 			    vd->format.sizeimage);
1058 			if (pool == NULL) {
1059 				sx_xunlock(&vd->cfg_sx);
1060 				error = ENOMEM;
1061 				goto out;
1062 			}
1063 			mtx_lock(&vd->mtx);
1064 			vd->pool = pool;
1065 			mtx_unlock(&vd->mtx);
1066 		}
1067 		vd->mode = VMODE_READ;
1068 
1069 		mtx_lock(&vd->mtx);
1070 		for (u_int i = 0; i < vd->pool->nbufs; i++) {
1071 			vb = &vd->pool->bufs[i];
1072 			vb->state = VB_QUEUED;
1073 			vb->vd = vd;
1074 			STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
1075 		}
1076 		mtx_unlock(&vd->mtx);
1077 
1078 		error = VIDEO_START_STREAM(vd->dev);
1079 		if (error != 0) {
1080 			video_pool_detach(vd);
1081 			vd->mode = VMODE_NONE;
1082 			sx_xunlock(&vd->cfg_sx);
1083 			goto out;
1084 		}
1085 
1086 		mtx_lock(&vd->mtx);
1087 		vd->streaming = true;
1088 		mtx_unlock(&vd->mtx);
1089 	}
1090 	sx_xunlock(&vd->cfg_sx);
1091 
1092 	mtx_lock(&vd->mtx);
1093 	while (vf->read_buf == NULL) {
1094 		if (!STAILQ_EMPTY(&vd->done)) {
1095 			vf->read_buf = STAILQ_FIRST(&vd->done);
1096 			STAILQ_REMOVE_HEAD(&vd->done, entry);
1097 			vf->read_offset = 0;
1098 			break;
1099 		}
1100 		if (!vd->streaming || vd->stopping) {
1101 			mtx_unlock(&vd->mtx);
1102 			error = EIO;
1103 			goto out;
1104 		}
1105 		if (ioflag & O_NONBLOCK) {
1106 			mtx_unlock(&vd->mtx);
1107 			error = EAGAIN;
1108 			goto out;
1109 		}
1110 		error = msleep(&vd->done, &vd->mtx, PCATCH, "vread", 0);
1111 		if (error != 0) {
1112 			mtx_unlock(&vd->mtx);
1113 			goto out;
1114 		}
1115 	}
1116 
1117 	vb = vf->read_buf;
1118 	bytesused = vb->bytesused;
1119 	offset = vf->read_offset;
1120 	chunk = 0;
1121 	if (uio->uio_resid > 0 && offset < bytesused) {
1122 		chunk = MIN((size_t)uio->uio_resid, bytesused - offset);
1123 		src = (uint8_t *)vb->buf + offset;
1124 		vd->readers++;
1125 		mtx_unlock(&vd->mtx);
1126 
1127 		error = uiomove(src, chunk, uio);
1128 
1129 		mtx_lock(&vd->mtx);
1130 		if (--vd->readers == 0)
1131 			wakeup(&vd->readers);
1132 		if (error != 0) {
1133 			mtx_unlock(&vd->mtx);
1134 			goto out;
1135 		}
1136 	}
1137 
1138 	if (vf->read_buf == vb) {
1139 		vf->read_offset = offset + chunk;
1140 		if (vf->read_offset >= bytesused) {
1141 			vf->read_buf = NULL;
1142 			vf->read_offset = 0;
1143 			vb->state = VB_QUEUED;
1144 			vb->bytesused = 0;
1145 			STAILQ_INSERT_TAIL(&vd->queued, vb, entry);
1146 		}
1147 	}
1148 	mtx_unlock(&vd->mtx);
1149 
1150 	error = 0;
1151 out:
1152 	mtx_lock(&vd->mtx);
1153 	vf->reading = false;
1154 	wakeup(&vf->reading);
1155 	mtx_unlock(&vd->mtx);
1156 	return (error);
1157 }
1158 
1159 static int
1160 video_poll(struct cdev *dev, int events, struct thread *td)
1161 {
1162 	struct video_device *vd = dev->si_drv1;
1163 	int revents = 0;
1164 
1165 	if (vd == NULL || vd->dying)
1166 		return (POLLHUP);
1167 
1168 	mtx_lock(&vd->mtx);
1169 	if (events & (POLLIN | POLLRDNORM)) {
1170 		if (!STAILQ_EMPTY(&vd->done))
1171 			revents |= events & (POLLIN | POLLRDNORM);
1172 		else
1173 			selrecord(td, &vd->sel);
1174 	}
1175 	mtx_unlock(&vd->mtx);
1176 	return (revents);
1177 }
1178 
1179 static void video_kqfilter_detach(struct knote *kn);
1180 static int video_kqfilter_event(struct knote *kn, long hint);
1181 
1182 static const struct filterops video_read_filterops = {
1183 	.f_isfd =	1,
1184 	.f_detach =	video_kqfilter_detach,
1185 	.f_event =	video_kqfilter_event,
1186 };
1187 
1188 static void
1189 video_kqfilter_detach(struct knote *kn)
1190 {
1191 	struct video_device *vd = kn->kn_hook;
1192 
1193 	knlist_remove(&vd->sel.si_note, kn, 0);
1194 }
1195 
1196 static int
1197 video_kqfilter_event(struct knote *kn, long hint)
1198 {
1199 	struct video_device *vd = kn->kn_hook;
1200 
1201 	if (!STAILQ_EMPTY(&vd->done)) {
1202 		kn->kn_data = 1;
1203 		return (1);
1204 	}
1205 	return (0);
1206 }
1207 
1208 static int
1209 video_kqfilter(struct cdev *dev, struct knote *kn)
1210 {
1211 	struct video_device *vd = dev->si_drv1;
1212 
1213 	if (vd == NULL || vd->dying)
1214 		return (ENXIO);
1215 
1216 	switch (kn->kn_filter) {
1217 	case EVFILT_READ:
1218 		kn->kn_fop = &video_read_filterops;
1219 		kn->kn_hook = vd;
1220 		knlist_add(&vd->sel.si_note, kn, 0);
1221 		return (0);
1222 	default:
1223 		return (EINVAL);
1224 	}
1225 }
1226 
1227 static int
1228 video_mmap_single(struct cdev *dev, vm_ooffset_t *offset, vm_size_t size,
1229     vm_object_t *objp, int nprot)
1230 {
1231 	struct video_device *vd = dev->si_drv1;
1232 	struct video_file *vf;
1233 	int error;
1234 
1235 	if (vd == NULL || vd->dying)
1236 		return (ENXIO);
1237 
1238 	error = devfs_get_cdevpriv((void **)&vf);
1239 	if (error != 0)
1240 		return (error);
1241 
1242 	sx_slock(&vd->cfg_sx);
1243 	if (vd->owner != vf || vd->pool == NULL || vd->mode != VMODE_MMAP) {
1244 		sx_sunlock(&vd->cfg_sx);
1245 		return (EINVAL);
1246 	}
1247 
1248 	if (*offset >= vd->pool->map_size ||
1249 	    size > vd->pool->map_size - *offset) {
1250 		sx_sunlock(&vd->cfg_sx);
1251 		return (EINVAL);
1252 	}
1253 
1254 	/*
1255 	 * Hand out a reference to the object backing the whole pool; the
1256 	 * offset selects which buffer within it gets mapped.  The VM system
1257 	 * tracks the mapping lifetime through the object reference count,
1258 	 * so no per-mapping bookkeeping is needed here.
1259 	 */
1260 	vm_object_reference(vd->pool->obj);
1261 	*objp = vd->pool->obj;
1262 	sx_sunlock(&vd->cfg_sx);
1263 
1264 	return (0);
1265 }
1266 
1267 int
1268 video_register(device_t dev, struct video_device **vdp)
1269 {
1270 	struct make_dev_args args;
1271 	struct video_device *vd;
1272 	int taken[VIDEO_UNIT_RETRIES];
1273 	int collisions, error, unit;
1274 
1275 	vd = malloc(sizeof(*vd), M_VIDEO, M_WAITOK | M_ZERO);
1276 	vd->dev = dev;
1277 
1278 	sx_init(&vd->cfg_sx, "video_cfg");
1279 	mtx_init(&vd->mtx, "video_mtx", NULL, MTX_DEF);
1280 	STAILQ_INIT(&vd->queued);
1281 	STAILQ_INIT(&vd->done);
1282 	knlist_init_mtx(&vd->sel.si_note, &vd->mtx);
1283 
1284 	error = EEXIST;
1285 	for (collisions = 0; collisions < VIDEO_UNIT_RETRIES; collisions++) {
1286 		taken[collisions] = unit = alloc_unr(video_unrhdr);
1287 
1288 		make_dev_args_init(&args);
1289 		args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
1290 		args.mda_devsw = &video_cdevsw;
1291 		args.mda_uid = UID_ROOT;
1292 		args.mda_gid = GID_VIDEO;
1293 		args.mda_mode = 0660;
1294 		args.mda_unit = unit;
1295 		args.mda_si_drv1 = vd;
1296 
1297 		error = make_dev_s(&args, &vd->cdev, "video%d", unit);
1298 		if (error != EEXIST)
1299 			break;
1300 	}
1301 
1302 	while (collisions > 0)
1303 		free_unr(video_unrhdr, taken[--collisions]);
1304 
1305 	if (error != 0) {
1306 		free_unr(video_unrhdr, unit);
1307 		device_printf(dev, "failed to create a /dev/video node: %d\n",
1308 		    error);
1309 		knlist_destroy(&vd->sel.si_note);
1310 		mtx_destroy(&vd->mtx);
1311 		sx_destroy(&vd->cfg_sx);
1312 		free(vd, M_VIDEO);
1313 		return (error);
1314 	}
1315 	vd->unit = unit;
1316 
1317 	*vdp = vd;
1318 	device_printf(dev, "registered as /dev/video%d\n", unit);
1319 	return (0);
1320 }
1321 
1322 void
1323 video_unregister(struct video_device *vd)
1324 {
1325 
1326 	sx_xlock(&vd->cfg_sx);
1327 	vd->dying = true;
1328 
1329 	if (vd->streaming) {
1330 		mtx_lock(&vd->mtx);
1331 		vd->stopping = true;
1332 		wakeup(&vd->done);
1333 		mtx_unlock(&vd->mtx);
1334 
1335 		VIDEO_STOP_STREAM(vd->dev);
1336 
1337 		mtx_lock(&vd->mtx);
1338 		vd->streaming = false;
1339 		vd->stopping = false;
1340 		STAILQ_INIT(&vd->queued);
1341 		STAILQ_INIT(&vd->done);
1342 		mtx_unlock(&vd->mtx);
1343 	}
1344 
1345 	sx_xunlock(&vd->cfg_sx);
1346 
1347 	destroy_dev(vd->cdev);
1348 	free_unr(video_unrhdr, vd->unit);
1349 
1350 	video_pool_detach(vd);
1351 
1352 	knlist_destroy(&vd->sel.si_note);
1353 	mtx_destroy(&vd->mtx);
1354 	sx_destroy(&vd->cfg_sx);
1355 
1356 	free(vd, M_VIDEO);
1357 }
1358 
1359 static int
1360 video_modevent(module_t mod, int type, void *data)
1361 {
1362 
1363 	switch (type) {
1364 	case MOD_LOAD:
1365 		video_unrhdr = new_unrhdr(0, INT_MAX, NULL);
1366 		return (0);
1367 	case MOD_UNLOAD:
1368 		delete_unrhdr(video_unrhdr);
1369 		return (0);
1370 	default:
1371 		return (EOPNOTSUPP);
1372 	}
1373 }
1374 
1375 static moduledata_t video_mod = {
1376 	"video",
1377 	video_modevent,
1378 	NULL,
1379 };
1380 
1381 DECLARE_MODULE(video, video_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1382 MODULE_VERSION(video, 1);
1383