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