1 /* $OpenBSD: video.c,v 1.46 2020/12/28 18:28:11 mglocker Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Robert Nagy <robert@openbsd.org> 5 * Copyright (c) 2008 Marcus Glocker <mglocker@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/errno.h> 23 #include <sys/ioctl.h> 24 #include <sys/fcntl.h> 25 #include <sys/poll.h> 26 #include <sys/device.h> 27 #include <sys/vnode.h> 28 #include <sys/kernel.h> 29 #include <sys/malloc.h> 30 #include <sys/conf.h> 31 #include <sys/videoio.h> 32 33 #include <dev/video_if.h> 34 35 #include <uvm/uvm_extern.h> 36 37 #ifdef VIDEO_DEBUG 38 #define DPRINTF(x) do { printf x; } while (0) 39 #else 40 #define DPRINTF(x) 41 #endif 42 43 struct video_softc { 44 struct device dev; 45 void *hw_hdl; /* hardware driver handle */ 46 struct device *sc_dev; /* hardware device struct */ 47 struct video_hw_if *hw_if; /* hardware interface */ 48 char sc_dying; /* device detached */ 49 #define VIDEO_OPEN 0x01 50 char sc_open; 51 52 int sc_fsize; 53 uint8_t *sc_fbuffer; 54 caddr_t sc_fbuffer_mmap; 55 size_t sc_fbufferlen; 56 int sc_vidmode; /* access mode */ 57 #define VIDMODE_NONE 0 58 #define VIDMODE_MMAP 1 59 #define VIDMODE_READ 2 60 int sc_frames_ready; 61 62 struct selinfo sc_rsel; /* read selector */ 63 }; 64 65 int videoprobe(struct device *, void *, void *); 66 void videoattach(struct device *, struct device *, void *); 67 int videodetach(struct device *, int); 68 int videoactivate(struct device *, int); 69 int videoprint(void *, const char *); 70 71 void video_intr(void *); 72 73 struct cfattach video_ca = { 74 sizeof(struct video_softc), videoprobe, videoattach, 75 videodetach, videoactivate 76 }; 77 78 struct cfdriver video_cd = { 79 NULL, "video", DV_DULL 80 }; 81 82 /* 83 * Global flag to control if video recording is enabled by kern.video.record. 84 */ 85 int video_record_enable = 0; 86 87 int 88 videoprobe(struct device *parent, void *match, void *aux) 89 { 90 return (1); 91 } 92 93 void 94 videoattach(struct device *parent, struct device *self, void *aux) 95 { 96 struct video_softc *sc = (void *)self; 97 struct video_attach_args *sa = aux; 98 99 printf("\n"); 100 sc->hw_if = sa->hwif; 101 sc->hw_hdl = sa->hdl; 102 sc->sc_dev = parent; 103 sc->sc_fbufferlen = 0; 104 105 if (sc->hw_if->get_bufsize) 106 sc->sc_fbufferlen = (sc->hw_if->get_bufsize)(sc->hw_hdl); 107 if (sc->sc_fbufferlen == 0) { 108 printf("video: could not request frame buffer size\n"); 109 return; 110 } 111 112 sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_DEVBUF, M_NOWAIT); 113 if (sc->sc_fbuffer == NULL) { 114 printf("video: could not allocate frame buffer\n"); 115 return; 116 } 117 } 118 119 int 120 videoopen(dev_t dev, int flags, int fmt, struct proc *p) 121 { 122 int unit; 123 struct video_softc *sc; 124 125 unit = VIDEOUNIT(dev); 126 if (unit >= video_cd.cd_ndevs || 127 (sc = video_cd.cd_devs[unit]) == NULL || 128 sc->hw_if == NULL) 129 return (ENXIO); 130 131 if (sc->sc_open & VIDEO_OPEN) 132 return (EBUSY); 133 sc->sc_open |= VIDEO_OPEN; 134 135 sc->sc_vidmode = VIDMODE_NONE; 136 sc->sc_frames_ready = 0; 137 138 if (sc->hw_if->open != NULL) 139 return (sc->hw_if->open(sc->hw_hdl, flags, &sc->sc_fsize, 140 sc->sc_fbuffer, video_intr, sc)); 141 else 142 return (0); 143 } 144 145 int 146 videoclose(dev_t dev, int flags, int fmt, struct proc *p) 147 { 148 struct video_softc *sc; 149 int r = 0; 150 151 sc = video_cd.cd_devs[VIDEOUNIT(dev)]; 152 153 if (sc->hw_if->close != NULL) 154 r = sc->hw_if->close(sc->hw_hdl); 155 156 sc->sc_open &= ~VIDEO_OPEN; 157 158 return (r); 159 } 160 161 int 162 videoread(dev_t dev, struct uio *uio, int ioflag) 163 { 164 struct video_softc *sc; 165 int unit, error; 166 size_t size; 167 168 unit = VIDEOUNIT(dev); 169 if (unit >= video_cd.cd_ndevs || 170 (sc = video_cd.cd_devs[unit]) == NULL) 171 return (ENXIO); 172 173 if (sc->sc_dying) 174 return (EIO); 175 176 if (sc->sc_vidmode == VIDMODE_MMAP) 177 return (EBUSY); 178 179 /* start the stream if not already started */ 180 if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { 181 error = sc->hw_if->start_read(sc->hw_hdl); 182 if (error) 183 return (error); 184 sc->sc_vidmode = VIDMODE_READ; 185 } 186 187 DPRINTF(("resid=%zu\n", uio->uio_resid)); 188 189 if (sc->sc_frames_ready < 1) { 190 /* block userland read until a frame is ready */ 191 error = tsleep_nsec(sc, PWAIT | PCATCH, "vid_rd", INFSLP); 192 if (sc->sc_dying) 193 error = EIO; 194 if (error) 195 return (error); 196 } 197 198 /* move no more than 1 frame to userland, as per specification */ 199 size = ulmin(uio->uio_resid, sc->sc_fsize); 200 if (!video_record_enable) 201 bzero(sc->sc_fbuffer, size); 202 error = uiomove(sc->sc_fbuffer, size, uio); 203 sc->sc_frames_ready--; 204 if (error) 205 return (error); 206 207 DPRINTF(("uiomove successfully done (%zu bytes)\n", size)); 208 209 return (0); 210 } 211 212 int 213 videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 214 { 215 struct video_softc *sc; 216 struct v4l2_buffer *vb = (struct v4l2_buffer *)data; 217 int unit, error; 218 219 unit = VIDEOUNIT(dev); 220 if (unit >= video_cd.cd_ndevs || 221 (sc = video_cd.cd_devs[unit]) == NULL || sc->hw_if == NULL) 222 return (ENXIO); 223 224 DPRINTF(("video_ioctl(%zu, '%c', %zu)\n", 225 IOCPARM_LEN(cmd), (int) IOCGROUP(cmd), cmd & 0xff)); 226 227 error = EOPNOTSUPP; 228 switch (cmd) { 229 case VIDIOC_QUERYCAP: 230 if (sc->hw_if->querycap) 231 error = (sc->hw_if->querycap)(sc->hw_hdl, 232 (struct v4l2_capability *)data); 233 break; 234 case VIDIOC_ENUM_FMT: 235 if (sc->hw_if->enum_fmt) 236 error = (sc->hw_if->enum_fmt)(sc->hw_hdl, 237 (struct v4l2_fmtdesc *)data); 238 break; 239 case VIDIOC_ENUM_FRAMESIZES: 240 if (sc->hw_if->enum_fsizes) 241 error = (sc->hw_if->enum_fsizes)(sc->hw_hdl, 242 (struct v4l2_frmsizeenum *)data); 243 break; 244 case VIDIOC_ENUM_FRAMEINTERVALS: 245 if (sc->hw_if->enum_fivals) 246 error = (sc->hw_if->enum_fivals)(sc->hw_hdl, 247 (struct v4l2_frmivalenum *)data); 248 break; 249 case VIDIOC_S_FMT: 250 if (!(flags & FWRITE)) 251 return (EACCES); 252 if (sc->hw_if->s_fmt) 253 error = (sc->hw_if->s_fmt)(sc->hw_hdl, 254 (struct v4l2_format *)data); 255 break; 256 case VIDIOC_G_FMT: 257 if (sc->hw_if->g_fmt) 258 error = (sc->hw_if->g_fmt)(sc->hw_hdl, 259 (struct v4l2_format *)data); 260 break; 261 case VIDIOC_S_PARM: 262 if (sc->hw_if->s_parm) 263 error = (sc->hw_if->s_parm)(sc->hw_hdl, 264 (struct v4l2_streamparm *)data); 265 break; 266 case VIDIOC_G_PARM: 267 if (sc->hw_if->g_parm) 268 error = (sc->hw_if->g_parm)(sc->hw_hdl, 269 (struct v4l2_streamparm *)data); 270 break; 271 case VIDIOC_ENUMINPUT: 272 if (sc->hw_if->enum_input) 273 error = (sc->hw_if->enum_input)(sc->hw_hdl, 274 (struct v4l2_input *)data); 275 break; 276 case VIDIOC_S_INPUT: 277 if (sc->hw_if->s_input) 278 error = (sc->hw_if->s_input)(sc->hw_hdl, 279 (int)*data); 280 break; 281 case VIDIOC_G_INPUT: 282 if (sc->hw_if->g_input) 283 error = (sc->hw_if->g_input)(sc->hw_hdl, 284 (int *)data); 285 break; 286 case VIDIOC_REQBUFS: 287 if (sc->hw_if->reqbufs) 288 error = (sc->hw_if->reqbufs)(sc->hw_hdl, 289 (struct v4l2_requestbuffers *)data); 290 break; 291 case VIDIOC_QUERYBUF: 292 if (sc->hw_if->querybuf) 293 error = (sc->hw_if->querybuf)(sc->hw_hdl, 294 (struct v4l2_buffer *)data); 295 break; 296 case VIDIOC_QBUF: 297 if (sc->hw_if->qbuf) 298 error = (sc->hw_if->qbuf)(sc->hw_hdl, 299 (struct v4l2_buffer *)data); 300 break; 301 case VIDIOC_DQBUF: 302 if (!sc->hw_if->dqbuf) 303 break; 304 /* should have called mmap() before now */ 305 if (sc->sc_vidmode != VIDMODE_MMAP) { 306 error = EINVAL; 307 break; 308 } 309 error = (sc->hw_if->dqbuf)(sc->hw_hdl, 310 (struct v4l2_buffer *)data); 311 if (!video_record_enable) 312 bzero(sc->sc_fbuffer_mmap + vb->m.offset, vb->length); 313 sc->sc_frames_ready--; 314 break; 315 case VIDIOC_STREAMON: 316 if (sc->hw_if->streamon) 317 error = (sc->hw_if->streamon)(sc->hw_hdl, 318 (int)*data); 319 break; 320 case VIDIOC_STREAMOFF: 321 if (sc->hw_if->streamoff) 322 error = (sc->hw_if->streamoff)(sc->hw_hdl, 323 (int)*data); 324 break; 325 case VIDIOC_TRY_FMT: 326 if (sc->hw_if->try_fmt) 327 error = (sc->hw_if->try_fmt)(sc->hw_hdl, 328 (struct v4l2_format *)data); 329 break; 330 case VIDIOC_QUERYCTRL: 331 if (sc->hw_if->queryctrl) 332 error = (sc->hw_if->queryctrl)(sc->hw_hdl, 333 (struct v4l2_queryctrl *)data); 334 break; 335 case VIDIOC_G_CTRL: 336 if (sc->hw_if->g_ctrl) 337 error = (sc->hw_if->g_ctrl)(sc->hw_hdl, 338 (struct v4l2_control *)data); 339 break; 340 case VIDIOC_S_CTRL: 341 if (sc->hw_if->s_ctrl) 342 error = (sc->hw_if->s_ctrl)(sc->hw_hdl, 343 (struct v4l2_control *)data); 344 break; 345 default: 346 error = (ENOTTY); 347 } 348 349 return (error); 350 } 351 352 int 353 videopoll(dev_t dev, int events, struct proc *p) 354 { 355 int unit = VIDEOUNIT(dev); 356 struct video_softc *sc; 357 int error, revents = 0; 358 359 if (unit >= video_cd.cd_ndevs || 360 (sc = video_cd.cd_devs[unit]) == NULL) 361 return (POLLERR); 362 363 if (sc->sc_dying) 364 return (POLLERR); 365 366 DPRINTF(("%s: events=0x%x\n", __func__, events)); 367 368 if (events & (POLLIN | POLLRDNORM)) { 369 if (sc->sc_frames_ready > 0) 370 revents |= events & (POLLIN | POLLRDNORM); 371 } 372 if (revents == 0) { 373 if (events & (POLLIN | POLLRDNORM)) { 374 /* 375 * Start the stream in read() mode if not already 376 * started. If the user wanted mmap() mode, 377 * he should have called mmap() before now. 378 */ 379 if (sc->sc_vidmode == VIDMODE_NONE && 380 sc->hw_if->start_read) { 381 error = sc->hw_if->start_read(sc->hw_hdl); 382 if (error) 383 return (POLLERR); 384 sc->sc_vidmode = VIDMODE_READ; 385 } 386 selrecord(p, &sc->sc_rsel); 387 } 388 } 389 390 DPRINTF(("%s: revents=0x%x\n", __func__, revents)); 391 392 return (revents); 393 } 394 395 paddr_t 396 videommap(dev_t dev, off_t off, int prot) 397 { 398 struct video_softc *sc; 399 int unit; 400 caddr_t p; 401 paddr_t pa; 402 403 DPRINTF(("%s: off=%lld, prot=%d\n", __func__, off, prot)); 404 405 unit = VIDEOUNIT(dev); 406 if (unit >= video_cd.cd_ndevs || 407 (sc = video_cd.cd_devs[unit]) == NULL) 408 return (-1); 409 410 if (sc->sc_dying) 411 return (-1); 412 413 if (sc->hw_if->mappage == NULL) 414 return (-1); 415 416 p = sc->hw_if->mappage(sc->hw_hdl, off, prot); 417 if (p == NULL) 418 return (-1); 419 if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) 420 panic("videommap: invalid page"); 421 sc->sc_vidmode = VIDMODE_MMAP; 422 423 /* store frame buffer base address for later blanking */ 424 if (off == 0) 425 sc->sc_fbuffer_mmap = p; 426 427 return (pa); 428 } 429 430 void 431 filt_videodetach(struct knote *kn) 432 { 433 struct video_softc *sc = kn->kn_hook; 434 int s; 435 436 s = splhigh(); 437 klist_remove_locked(&sc->sc_rsel.si_note, kn); 438 splx(s); 439 } 440 441 int 442 filt_videoread(struct knote *kn, long hint) 443 { 444 struct video_softc *sc = kn->kn_hook; 445 446 if (sc->sc_frames_ready > 0) 447 return (1); 448 449 return (0); 450 } 451 452 const struct filterops video_filtops = { 453 .f_flags = FILTEROP_ISFD, 454 .f_attach = NULL, 455 .f_detach = filt_videodetach, 456 .f_event = filt_videoread, 457 }; 458 459 int 460 videokqfilter(dev_t dev, struct knote *kn) 461 { 462 int unit = VIDEOUNIT(dev); 463 struct video_softc *sc; 464 int s; 465 466 if (unit >= video_cd.cd_ndevs || 467 (sc = video_cd.cd_devs[unit]) == NULL) 468 return (ENXIO); 469 470 if (sc->sc_dying) 471 return (ENXIO); 472 473 switch (kn->kn_filter) { 474 case EVFILT_READ: 475 kn->kn_fop = &video_filtops; 476 kn->kn_hook = sc; 477 break; 478 default: 479 return (EINVAL); 480 } 481 482 /* 483 * Start the stream in read() mode if not already started. If 484 * the user wanted mmap() mode, he should have called mmap() 485 * before now. 486 */ 487 if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { 488 if (sc->hw_if->start_read(sc->hw_hdl)) 489 return (ENXIO); 490 sc->sc_vidmode = VIDMODE_READ; 491 } 492 493 s = splhigh(); 494 klist_insert_locked(&sc->sc_rsel.si_note, kn); 495 splx(s); 496 497 return (0); 498 } 499 500 int 501 video_submatch(struct device *parent, void *match, void *aux) 502 { 503 struct cfdata *cf = match; 504 505 return (cf->cf_driver == &video_cd); 506 } 507 508 /* 509 * Called from hardware driver. This is where the MI video driver gets 510 * probed/attached to the hardware driver 511 */ 512 struct device * 513 video_attach_mi(struct video_hw_if *rhwp, void *hdlp, struct device *dev) 514 { 515 struct video_attach_args arg; 516 517 arg.hwif = rhwp; 518 arg.hdl = hdlp; 519 return (config_found_sm(dev, &arg, videoprint, video_submatch)); 520 } 521 522 void 523 video_intr(void *addr) 524 { 525 struct video_softc *sc = (struct video_softc *)addr; 526 527 DPRINTF(("video_intr sc=%p\n", sc)); 528 if (sc->sc_vidmode != VIDMODE_NONE) 529 sc->sc_frames_ready++; 530 else 531 printf("%s: interrupt but no streams!\n", __func__); 532 if (sc->sc_vidmode == VIDMODE_READ) 533 wakeup(sc); 534 selwakeup(&sc->sc_rsel); 535 } 536 537 int 538 videoprint(void *aux, const char *pnp) 539 { 540 if (pnp != NULL) 541 printf("video at %s", pnp); 542 return (UNCONF); 543 } 544 545 int 546 videodetach(struct device *self, int flags) 547 { 548 struct video_softc *sc = (struct video_softc *)self; 549 int s, maj, mn; 550 551 /* locate the major number */ 552 for (maj = 0; maj < nchrdev; maj++) 553 if (cdevsw[maj].d_open == videoopen) 554 break; 555 556 /* Nuke the vnodes for any open instances (calls close). */ 557 mn = self->dv_unit; 558 vdevgone(maj, mn, mn, VCHR); 559 560 s = splhigh(); 561 klist_invalidate(&sc->sc_rsel.si_note); 562 splx(s); 563 564 free(sc->sc_fbuffer, M_DEVBUF, sc->sc_fbufferlen); 565 566 return (0); 567 } 568 569 int 570 videoactivate(struct device *self, int act) 571 { 572 struct video_softc *sc = (struct video_softc *)self; 573 574 switch (act) { 575 case DVACT_DEACTIVATE: 576 sc->sc_dying = 1; 577 break; 578 } 579 return (0); 580 } 581