1 /* $OpenBSD: video.c,v 1.54 2021/02/17 17:21:58 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/proc.h> 32 #include <sys/videoio.h> 33 34 #include <dev/video_if.h> 35 36 #include <uvm/uvm_extern.h> 37 38 #ifdef VIDEO_DEBUG 39 int video_debug = 1; 40 #define DPRINTF(l, x...) do { if ((l) <= video_debug) printf(x); } while (0) 41 #else 42 #define DPRINTF(l, x...) 43 #endif 44 45 struct video_softc { 46 struct device dev; 47 void *hw_hdl; /* hardware driver handle */ 48 struct device *sc_dev; /* hardware device struct */ 49 struct video_hw_if *hw_if; /* hardware interface */ 50 char sc_dying; /* device detached */ 51 struct process *sc_owner; /* owner process */ 52 uint8_t sc_open; /* device opened */ 53 54 int sc_fsize; 55 uint8_t *sc_fbuffer; 56 caddr_t sc_fbuffer_mmap; 57 size_t sc_fbufferlen; 58 int sc_vidmode; /* access mode */ 59 #define VIDMODE_NONE 0 60 #define VIDMODE_MMAP 1 61 #define VIDMODE_READ 2 62 int sc_frames_ready; 63 64 struct selinfo sc_rsel; /* read selector */ 65 }; 66 67 int videoprobe(struct device *, void *, void *); 68 void videoattach(struct device *, struct device *, void *); 69 int videodetach(struct device *, int); 70 int videoactivate(struct device *, int); 71 int videoprint(void *, const char *); 72 73 void video_intr(void *); 74 int video_stop(struct video_softc *); 75 int video_claim(struct video_softc *, struct process *); 76 77 struct cfattach video_ca = { 78 sizeof(struct video_softc), videoprobe, videoattach, 79 videodetach, videoactivate 80 }; 81 82 struct cfdriver video_cd = { 83 NULL, "video", DV_DULL 84 }; 85 86 /* 87 * Global flag to control if video recording is enabled by kern.video.record. 88 */ 89 int video_record_enable = 0; 90 91 int 92 videoprobe(struct device *parent, void *match, void *aux) 93 { 94 return (1); 95 } 96 97 void 98 videoattach(struct device *parent, struct device *self, void *aux) 99 { 100 struct video_softc *sc = (void *)self; 101 struct video_attach_args *sa = aux; 102 103 printf("\n"); 104 sc->hw_if = sa->hwif; 105 sc->hw_hdl = sa->hdl; 106 sc->sc_dev = parent; 107 sc->sc_fbufferlen = 0; 108 sc->sc_owner = NULL; 109 110 if (sc->hw_if->get_bufsize) 111 sc->sc_fbufferlen = (sc->hw_if->get_bufsize)(sc->hw_hdl); 112 if (sc->sc_fbufferlen == 0) { 113 printf("video: could not request frame buffer size\n"); 114 return; 115 } 116 117 sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_DEVBUF, M_NOWAIT); 118 if (sc->sc_fbuffer == NULL) { 119 printf("video: could not allocate frame buffer\n"); 120 return; 121 } 122 } 123 124 int 125 videoopen(dev_t dev, int flags, int fmt, struct proc *p) 126 { 127 int unit = VIDEOUNIT(dev); 128 struct video_softc *sc; 129 int error = 0; 130 131 KERNEL_ASSERT_LOCKED(); 132 133 if (unit >= video_cd.cd_ndevs || 134 (sc = video_cd.cd_devs[unit]) == NULL || 135 sc->hw_if == NULL) 136 return (ENXIO); 137 138 if (sc->sc_open) { 139 DPRINTF(1, "%s: device already open\n", __func__); 140 return (0); 141 } 142 143 sc->sc_vidmode = VIDMODE_NONE; 144 sc->sc_frames_ready = 0; 145 146 if (sc->hw_if->open != NULL) { 147 error = sc->hw_if->open(sc->hw_hdl, flags, &sc->sc_fsize, 148 sc->sc_fbuffer, video_intr, sc); 149 } 150 if (error == 0) { 151 sc->sc_open = 1; 152 DPRINTF(1, "%s: set device to open\n", __func__); 153 } 154 155 return (error); 156 } 157 158 int 159 videoclose(dev_t dev, int flags, int fmt, struct proc *p) 160 { 161 struct video_softc *sc; 162 int error = 0; 163 164 KERNEL_ASSERT_LOCKED(); 165 166 DPRINTF(1, "%s: last close\n", __func__); 167 168 sc = video_cd.cd_devs[VIDEOUNIT(dev)]; 169 170 error = video_stop(sc); 171 sc->sc_open = 0; 172 173 return (error); 174 } 175 176 int 177 videoread(dev_t dev, struct uio *uio, int ioflag) 178 { 179 int unit = VIDEOUNIT(dev); 180 struct video_softc *sc; 181 int error; 182 size_t size; 183 184 KERNEL_ASSERT_LOCKED(); 185 186 if (unit >= video_cd.cd_ndevs || 187 (sc = video_cd.cd_devs[unit]) == NULL) 188 return (ENXIO); 189 190 if (sc->sc_dying) 191 return (EIO); 192 193 if (sc->sc_vidmode == VIDMODE_MMAP) 194 return (EBUSY); 195 196 if ((error = video_claim(sc, curproc->p_p))) 197 return (error); 198 199 /* start the stream if not already started */ 200 if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { 201 error = sc->hw_if->start_read(sc->hw_hdl); 202 if (error) 203 return (error); 204 sc->sc_vidmode = VIDMODE_READ; 205 } 206 207 DPRINTF(1, "resid=%zu\n", uio->uio_resid); 208 209 if (sc->sc_frames_ready < 1) { 210 /* block userland read until a frame is ready */ 211 error = tsleep_nsec(sc, PWAIT | PCATCH, "vid_rd", INFSLP); 212 if (sc->sc_dying) 213 error = EIO; 214 if (error) 215 return (error); 216 } 217 218 /* move no more than 1 frame to userland, as per specification */ 219 size = ulmin(uio->uio_resid, sc->sc_fsize); 220 if (!video_record_enable) 221 bzero(sc->sc_fbuffer, size); 222 error = uiomove(sc->sc_fbuffer, size, uio); 223 sc->sc_frames_ready--; 224 if (error) 225 return (error); 226 227 DPRINTF(1, "uiomove successfully done (%zu bytes)\n", size); 228 229 return (0); 230 } 231 232 int 233 videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 234 { 235 int unit = VIDEOUNIT(dev); 236 struct video_softc *sc; 237 struct v4l2_buffer *vb = (struct v4l2_buffer *)data; 238 int error; 239 240 KERNEL_ASSERT_LOCKED(); 241 242 if (unit >= video_cd.cd_ndevs || 243 (sc = video_cd.cd_devs[unit]) == NULL || sc->hw_if == NULL) 244 return (ENXIO); 245 246 DPRINTF(3, "video_ioctl(%zu, '%c', %zu)\n", 247 IOCPARM_LEN(cmd), (int) IOCGROUP(cmd), cmd & 0xff); 248 249 error = EOPNOTSUPP; 250 switch (cmd) { 251 case VIDIOC_G_CTRL: 252 if (sc->hw_if->g_ctrl) 253 error = (sc->hw_if->g_ctrl)(sc->hw_hdl, 254 (struct v4l2_control *)data); 255 break; 256 case VIDIOC_S_CTRL: 257 if (sc->hw_if->s_ctrl) 258 error = (sc->hw_if->s_ctrl)(sc->hw_hdl, 259 (struct v4l2_control *)data); 260 break; 261 default: 262 error = (ENOTTY); 263 } 264 if (error != ENOTTY) 265 return (error); 266 267 if ((error = video_claim(sc, p->p_p))) 268 return (error); 269 270 /* 271 * The following IOCTLs can only be called by the device owner. 272 * For further shared IOCTLs please move it up. 273 */ 274 error = EOPNOTSUPP; 275 switch (cmd) { 276 case VIDIOC_QUERYCAP: 277 if (sc->hw_if->querycap) 278 error = (sc->hw_if->querycap)(sc->hw_hdl, 279 (struct v4l2_capability *)data); 280 break; 281 case VIDIOC_ENUM_FMT: 282 if (sc->hw_if->enum_fmt) 283 error = (sc->hw_if->enum_fmt)(sc->hw_hdl, 284 (struct v4l2_fmtdesc *)data); 285 break; 286 case VIDIOC_ENUM_FRAMESIZES: 287 if (sc->hw_if->enum_fsizes) 288 error = (sc->hw_if->enum_fsizes)(sc->hw_hdl, 289 (struct v4l2_frmsizeenum *)data); 290 break; 291 case VIDIOC_ENUM_FRAMEINTERVALS: 292 if (sc->hw_if->enum_fivals) 293 error = (sc->hw_if->enum_fivals)(sc->hw_hdl, 294 (struct v4l2_frmivalenum *)data); 295 break; 296 case VIDIOC_S_FMT: 297 if (!(flags & FWRITE)) 298 return (EACCES); 299 if (sc->hw_if->s_fmt) 300 error = (sc->hw_if->s_fmt)(sc->hw_hdl, 301 (struct v4l2_format *)data); 302 break; 303 case VIDIOC_G_FMT: 304 if (sc->hw_if->g_fmt) 305 error = (sc->hw_if->g_fmt)(sc->hw_hdl, 306 (struct v4l2_format *)data); 307 break; 308 case VIDIOC_S_PARM: 309 if (sc->hw_if->s_parm) 310 error = (sc->hw_if->s_parm)(sc->hw_hdl, 311 (struct v4l2_streamparm *)data); 312 break; 313 case VIDIOC_G_PARM: 314 if (sc->hw_if->g_parm) 315 error = (sc->hw_if->g_parm)(sc->hw_hdl, 316 (struct v4l2_streamparm *)data); 317 break; 318 case VIDIOC_ENUMINPUT: 319 if (sc->hw_if->enum_input) 320 error = (sc->hw_if->enum_input)(sc->hw_hdl, 321 (struct v4l2_input *)data); 322 break; 323 case VIDIOC_S_INPUT: 324 if (sc->hw_if->s_input) 325 error = (sc->hw_if->s_input)(sc->hw_hdl, 326 (int)*data); 327 break; 328 case VIDIOC_G_INPUT: 329 if (sc->hw_if->g_input) 330 error = (sc->hw_if->g_input)(sc->hw_hdl, 331 (int *)data); 332 break; 333 case VIDIOC_REQBUFS: 334 if (sc->hw_if->reqbufs) 335 error = (sc->hw_if->reqbufs)(sc->hw_hdl, 336 (struct v4l2_requestbuffers *)data); 337 break; 338 case VIDIOC_QUERYBUF: 339 if (sc->hw_if->querybuf) 340 error = (sc->hw_if->querybuf)(sc->hw_hdl, 341 (struct v4l2_buffer *)data); 342 break; 343 case VIDIOC_QBUF: 344 if (sc->hw_if->qbuf) 345 error = (sc->hw_if->qbuf)(sc->hw_hdl, 346 (struct v4l2_buffer *)data); 347 break; 348 case VIDIOC_DQBUF: 349 if (!sc->hw_if->dqbuf) 350 break; 351 /* should have called mmap() before now */ 352 if (sc->sc_vidmode != VIDMODE_MMAP) { 353 error = EINVAL; 354 break; 355 } 356 error = (sc->hw_if->dqbuf)(sc->hw_hdl, 357 (struct v4l2_buffer *)data); 358 if (!video_record_enable) 359 bzero(sc->sc_fbuffer_mmap + vb->m.offset, vb->length); 360 sc->sc_frames_ready--; 361 break; 362 case VIDIOC_STREAMON: 363 if (sc->hw_if->streamon) 364 error = (sc->hw_if->streamon)(sc->hw_hdl, 365 (int)*data); 366 break; 367 case VIDIOC_STREAMOFF: 368 if (sc->hw_if->streamoff) 369 error = (sc->hw_if->streamoff)(sc->hw_hdl, 370 (int)*data); 371 if (!error) { 372 /* Release device ownership and streaming buffers. */ 373 error = video_stop(sc); 374 } 375 break; 376 case VIDIOC_TRY_FMT: 377 if (sc->hw_if->try_fmt) 378 error = (sc->hw_if->try_fmt)(sc->hw_hdl, 379 (struct v4l2_format *)data); 380 break; 381 case VIDIOC_QUERYCTRL: 382 if (sc->hw_if->queryctrl) 383 error = (sc->hw_if->queryctrl)(sc->hw_hdl, 384 (struct v4l2_queryctrl *)data); 385 break; 386 default: 387 error = (ENOTTY); 388 } 389 390 return (error); 391 } 392 393 int 394 videopoll(dev_t dev, int events, struct proc *p) 395 { 396 int unit = VIDEOUNIT(dev); 397 struct video_softc *sc; 398 int error, revents = 0; 399 400 KERNEL_ASSERT_LOCKED(); 401 402 if (unit >= video_cd.cd_ndevs || 403 (sc = video_cd.cd_devs[unit]) == NULL) 404 return (POLLERR); 405 406 if (sc->sc_dying) 407 return (POLLERR); 408 409 if ((error = video_claim(sc, p->p_p))) 410 return (error); 411 412 DPRINTF(1, "%s: events=0x%x\n", __func__, events); 413 414 if (events & (POLLIN | POLLRDNORM)) { 415 if (sc->sc_frames_ready > 0) 416 revents |= events & (POLLIN | POLLRDNORM); 417 } 418 if (revents == 0) { 419 if (events & (POLLIN | POLLRDNORM)) { 420 /* 421 * Start the stream in read() mode if not already 422 * started. If the user wanted mmap() mode, 423 * he should have called mmap() before now. 424 */ 425 if (sc->sc_vidmode == VIDMODE_NONE && 426 sc->hw_if->start_read) { 427 error = sc->hw_if->start_read(sc->hw_hdl); 428 if (error) 429 return (POLLERR); 430 sc->sc_vidmode = VIDMODE_READ; 431 } 432 selrecord(p, &sc->sc_rsel); 433 } 434 } 435 436 DPRINTF(1, "%s: revents=0x%x\n", __func__, revents); 437 438 return (revents); 439 } 440 441 paddr_t 442 videommap(dev_t dev, off_t off, int prot) 443 { 444 int unit = VIDEOUNIT(dev); 445 struct video_softc *sc; 446 caddr_t p; 447 paddr_t pa; 448 449 KERNEL_ASSERT_LOCKED(); 450 451 DPRINTF(2, "%s: off=%lld, prot=%d\n", __func__, off, prot); 452 453 if (unit >= video_cd.cd_ndevs || 454 (sc = video_cd.cd_devs[unit]) == NULL) 455 return (-1); 456 457 if (sc->sc_dying) 458 return (-1); 459 460 if (sc->hw_if->mappage == NULL) 461 return (-1); 462 463 p = sc->hw_if->mappage(sc->hw_hdl, off, prot); 464 if (p == NULL) 465 return (-1); 466 if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) 467 panic("videommap: invalid page"); 468 sc->sc_vidmode = VIDMODE_MMAP; 469 470 /* store frame buffer base address for later blanking */ 471 if (off == 0) 472 sc->sc_fbuffer_mmap = p; 473 474 return (pa); 475 } 476 477 void 478 filt_videodetach(struct knote *kn) 479 { 480 struct video_softc *sc = kn->kn_hook; 481 int s; 482 483 s = splhigh(); 484 klist_remove_locked(&sc->sc_rsel.si_note, kn); 485 splx(s); 486 } 487 488 int 489 filt_videoread(struct knote *kn, long hint) 490 { 491 struct video_softc *sc = kn->kn_hook; 492 493 if (sc->sc_frames_ready > 0) 494 return (1); 495 496 return (0); 497 } 498 499 const struct filterops video_filtops = { 500 .f_flags = FILTEROP_ISFD, 501 .f_attach = NULL, 502 .f_detach = filt_videodetach, 503 .f_event = filt_videoread, 504 }; 505 506 int 507 videokqfilter(dev_t dev, struct knote *kn) 508 { 509 int unit = VIDEOUNIT(dev); 510 struct video_softc *sc; 511 int s, error; 512 513 KERNEL_ASSERT_LOCKED(); 514 515 if (unit >= video_cd.cd_ndevs || 516 (sc = video_cd.cd_devs[unit]) == NULL) 517 return (ENXIO); 518 519 if (sc->sc_dying) 520 return (ENXIO); 521 522 switch (kn->kn_filter) { 523 case EVFILT_READ: 524 kn->kn_fop = &video_filtops; 525 kn->kn_hook = sc; 526 break; 527 default: 528 return (EINVAL); 529 } 530 531 if ((error = video_claim(sc, curproc->p_p))) 532 return (error); 533 534 /* 535 * Start the stream in read() mode if not already started. If 536 * the user wanted mmap() mode, he should have called mmap() 537 * before now. 538 */ 539 if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { 540 if (sc->hw_if->start_read(sc->hw_hdl)) 541 return (ENXIO); 542 sc->sc_vidmode = VIDMODE_READ; 543 } 544 545 s = splhigh(); 546 klist_insert_locked(&sc->sc_rsel.si_note, kn); 547 splx(s); 548 549 return (0); 550 } 551 552 int 553 video_submatch(struct device *parent, void *match, void *aux) 554 { 555 struct cfdata *cf = match; 556 557 return (cf->cf_driver == &video_cd); 558 } 559 560 /* 561 * Called from hardware driver. This is where the MI video driver gets 562 * probed/attached to the hardware driver 563 */ 564 struct device * 565 video_attach_mi(struct video_hw_if *rhwp, void *hdlp, struct device *dev) 566 { 567 struct video_attach_args arg; 568 569 arg.hwif = rhwp; 570 arg.hdl = hdlp; 571 return (config_found_sm(dev, &arg, videoprint, video_submatch)); 572 } 573 574 void 575 video_intr(void *addr) 576 { 577 struct video_softc *sc = (struct video_softc *)addr; 578 579 DPRINTF(3, "video_intr sc=%p\n", sc); 580 if (sc->sc_vidmode != VIDMODE_NONE) 581 sc->sc_frames_ready++; 582 else 583 printf("%s: interrupt but no streams!\n", __func__); 584 if (sc->sc_vidmode == VIDMODE_READ) 585 wakeup(sc); 586 selwakeup(&sc->sc_rsel); 587 } 588 589 int 590 video_stop(struct video_softc *sc) 591 { 592 int error = 0; 593 594 DPRINTF(1, "%s: stream close\n", __func__); 595 596 if (sc->hw_if->close != NULL) 597 error = sc->hw_if->close(sc->hw_hdl); 598 599 sc->sc_vidmode = VIDMODE_NONE; 600 sc->sc_frames_ready = 0; 601 sc->sc_owner = NULL; 602 603 return (error); 604 } 605 606 int 607 video_claim(struct video_softc *sc, struct process *pr) 608 { 609 if (sc->sc_owner != NULL && sc->sc_owner != pr) { 610 DPRINTF(1, "%s: already owned=%p\n", __func__, sc->sc_owner); 611 return (EBUSY); 612 } 613 614 if (sc->sc_owner == NULL) { 615 sc->sc_owner = pr; 616 DPRINTF(1, "%s: new owner=%p\n", __func__, sc->sc_owner); 617 } 618 619 return (0); 620 } 621 622 int 623 videoprint(void *aux, const char *pnp) 624 { 625 if (pnp != NULL) 626 printf("video at %s", pnp); 627 return (UNCONF); 628 } 629 630 int 631 videodetach(struct device *self, int flags) 632 { 633 struct video_softc *sc = (struct video_softc *)self; 634 int s, maj, mn; 635 636 /* locate the major number */ 637 for (maj = 0; maj < nchrdev; maj++) 638 if (cdevsw[maj].d_open == videoopen) 639 break; 640 641 /* Nuke the vnodes for any open instances (calls close). */ 642 mn = self->dv_unit; 643 vdevgone(maj, mn, mn, VCHR); 644 645 s = splhigh(); 646 klist_invalidate(&sc->sc_rsel.si_note); 647 splx(s); 648 649 free(sc->sc_fbuffer, M_DEVBUF, sc->sc_fbufferlen); 650 651 return (0); 652 } 653 654 int 655 videoactivate(struct device *self, int act) 656 { 657 struct video_softc *sc = (struct video_softc *)self; 658 659 switch (act) { 660 case DVACT_DEACTIVATE: 661 sc->sc_dying = 1; 662 break; 663 } 664 return (0); 665 } 666