1 /* $OpenBSD: video.c,v 1.40 2016/07/03 20:05:44 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 size_t sc_fbufferlen; 55 int sc_vidmode; /* access mode */ 56 #define VIDMODE_NONE 0 57 #define VIDMODE_MMAP 1 58 #define VIDMODE_READ 2 59 int sc_frames_ready; 60 61 struct selinfo sc_rsel; /* read selector */ 62 }; 63 64 int videoprobe(struct device *, void *, void *); 65 void videoattach(struct device *, struct device *, void *); 66 int videodetach(struct device *, int); 67 int videoactivate(struct device *, int); 68 int videoprint(void *, const char *); 69 70 void video_intr(void *); 71 72 struct cfattach video_ca = { 73 sizeof(struct video_softc), videoprobe, videoattach, 74 videodetach, videoactivate 75 }; 76 77 struct cfdriver video_cd = { 78 NULL, "video", DV_DULL 79 }; 80 81 int 82 videoprobe(struct device *parent, void *match, void *aux) 83 { 84 return (1); 85 } 86 87 void 88 videoattach(struct device *parent, struct device *self, void *aux) 89 { 90 struct video_softc *sc = (void *)self; 91 struct video_attach_args *sa = aux; 92 93 printf("\n"); 94 sc->hw_if = sa->hwif; 95 sc->hw_hdl = sa->hdl; 96 sc->sc_dev = parent; 97 sc->sc_fbufferlen = 0; 98 99 if (sc->hw_if->get_bufsize) 100 sc->sc_fbufferlen = (sc->hw_if->get_bufsize)(sc->hw_hdl); 101 if (sc->sc_fbufferlen == 0) { 102 printf("video: could not request frame buffer size\n"); 103 return; 104 } 105 106 sc->sc_fbuffer = malloc(sc->sc_fbufferlen, M_DEVBUF, M_NOWAIT); 107 if (sc->sc_fbuffer == NULL) { 108 printf("video: could not allocate frame buffer\n"); 109 return; 110 } 111 } 112 113 int 114 videoopen(dev_t dev, int flags, int fmt, struct proc *p) 115 { 116 int unit; 117 struct video_softc *sc; 118 119 unit = VIDEOUNIT(dev); 120 if (unit >= video_cd.cd_ndevs || 121 (sc = video_cd.cd_devs[unit]) == NULL || 122 sc->hw_if == NULL) 123 return (ENXIO); 124 125 if (sc->sc_open & VIDEO_OPEN) 126 return (EBUSY); 127 sc->sc_open |= VIDEO_OPEN; 128 129 sc->sc_vidmode = VIDMODE_NONE; 130 sc->sc_frames_ready = 0; 131 132 if (sc->hw_if->open != NULL) 133 return (sc->hw_if->open(sc->hw_hdl, flags, &sc->sc_fsize, 134 sc->sc_fbuffer, video_intr, sc)); 135 else 136 return (0); 137 } 138 139 int 140 videoclose(dev_t dev, int flags, int fmt, struct proc *p) 141 { 142 struct video_softc *sc; 143 int r = 0; 144 145 sc = video_cd.cd_devs[VIDEOUNIT(dev)]; 146 147 if (sc->hw_if->close != NULL) 148 r = sc->hw_if->close(sc->hw_hdl); 149 150 sc->sc_open &= ~VIDEO_OPEN; 151 152 return (r); 153 } 154 155 int 156 videoread(dev_t dev, struct uio *uio, int ioflag) 157 { 158 struct video_softc *sc; 159 int unit, error; 160 size_t size; 161 162 unit = VIDEOUNIT(dev); 163 if (unit >= video_cd.cd_ndevs || 164 (sc = video_cd.cd_devs[unit]) == NULL) 165 return (ENXIO); 166 167 if (sc->sc_dying) 168 return (EIO); 169 170 if (sc->sc_vidmode == VIDMODE_MMAP) 171 return (EBUSY); 172 173 /* start the stream if not already started */ 174 if (sc->sc_vidmode == VIDMODE_NONE && sc->hw_if->start_read) { 175 error = sc->hw_if->start_read(sc->hw_hdl); 176 if (error) 177 return (error); 178 sc->sc_vidmode = VIDMODE_READ; 179 } 180 181 DPRINTF(("resid=%d\n", uio->uio_resid)); 182 183 if (sc->sc_frames_ready < 1) { 184 /* block userland read until a frame is ready */ 185 error = tsleep(sc, PWAIT | PCATCH, "vid_rd", 0); 186 if (sc->sc_dying) 187 error = EIO; 188 if (error) 189 return (error); 190 } 191 192 /* move no more than 1 frame to userland, as per specification */ 193 size = ulmin(uio->uio_resid, sc->sc_fsize); 194 error = uiomove(sc->sc_fbuffer, size, uio); 195 sc->sc_frames_ready--; 196 if (error) 197 return (error); 198 199 DPRINTF(("uiomove successfully done (%zu bytes)\n", size)); 200 201 return (0); 202 } 203 204 int 205 videoioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 206 { 207 struct video_softc *sc; 208 int unit, error; 209 210 unit = VIDEOUNIT(dev); 211 if (unit >= video_cd.cd_ndevs || 212 (sc = video_cd.cd_devs[unit]) == NULL || sc->hw_if == NULL) 213 return (ENXIO); 214 215 DPRINTF(("video_ioctl(%d, '%c', %d)\n", 216 IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff)); 217 218 error = EOPNOTSUPP; 219 switch (cmd) { 220 case VIDIOC_QUERYCAP: 221 if (sc->hw_if->querycap) 222 error = (sc->hw_if->querycap)(sc->hw_hdl, 223 (struct v4l2_capability *)data); 224 break; 225 case VIDIOC_ENUM_FMT: 226 if (sc->hw_if->enum_fmt) 227 error = (sc->hw_if->enum_fmt)(sc->hw_hdl, 228 (struct v4l2_fmtdesc *)data); 229 break; 230 case VIDIOC_ENUM_FRAMESIZES: 231 if (sc->hw_if->enum_fsizes) 232 error = (sc->hw_if->enum_fsizes)(sc->hw_hdl, 233 (struct v4l2_frmsizeenum *)data); 234 break; 235 case VIDIOC_ENUM_FRAMEINTERVALS: 236 if (sc->hw_if->enum_fivals) 237 error = (sc->hw_if->enum_fivals)(sc->hw_hdl, 238 (struct v4l2_frmivalenum *)data); 239 break; 240 case VIDIOC_S_FMT: 241 if (!(flags & FWRITE)) 242 return (EACCES); 243 if (sc->hw_if->s_fmt) 244 error = (sc->hw_if->s_fmt)(sc->hw_hdl, 245 (struct v4l2_format *)data); 246 break; 247 case VIDIOC_G_FMT: 248 if (sc->hw_if->g_fmt) 249 error = (sc->hw_if->g_fmt)(sc->hw_hdl, 250 (struct v4l2_format *)data); 251 break; 252 case VIDIOC_S_PARM: 253 if (sc->hw_if->s_parm) 254 error = (sc->hw_if->s_parm)(sc->hw_hdl, 255 (struct v4l2_streamparm *)data); 256 break; 257 case VIDIOC_G_PARM: 258 if (sc->hw_if->g_parm) 259 error = (sc->hw_if->g_parm)(sc->hw_hdl, 260 (struct v4l2_streamparm *)data); 261 break; 262 case VIDIOC_ENUMINPUT: 263 if (sc->hw_if->enum_input) 264 error = (sc->hw_if->enum_input)(sc->hw_hdl, 265 (struct v4l2_input *)data); 266 break; 267 case VIDIOC_S_INPUT: 268 if (sc->hw_if->s_input) 269 error = (sc->hw_if->s_input)(sc->hw_hdl, 270 (int)*data); 271 break; 272 case VIDIOC_G_INPUT: 273 if (sc->hw_if->g_input) 274 error = (sc->hw_if->g_input)(sc->hw_hdl, 275 (int *)data); 276 break; 277 case VIDIOC_REQBUFS: 278 if (sc->hw_if->reqbufs) 279 error = (sc->hw_if->reqbufs)(sc->hw_hdl, 280 (struct v4l2_requestbuffers *)data); 281 break; 282 case VIDIOC_QUERYBUF: 283 if (sc->hw_if->querybuf) 284 error = (sc->hw_if->querybuf)(sc->hw_hdl, 285 (struct v4l2_buffer *)data); 286 break; 287 case VIDIOC_QBUF: 288 if (sc->hw_if->qbuf) 289 error = (sc->hw_if->qbuf)(sc->hw_hdl, 290 (struct v4l2_buffer *)data); 291 break; 292 case VIDIOC_DQBUF: 293 if (!sc->hw_if->dqbuf) 294 break; 295 /* should have called mmap() before now */ 296 if (sc->sc_vidmode != VIDMODE_MMAP) { 297 error = EINVAL; 298 break; 299 } 300 error = (sc->hw_if->dqbuf)(sc->hw_hdl, 301 (struct v4l2_buffer *)data); 302 sc->sc_frames_ready--; 303 break; 304 case VIDIOC_STREAMON: 305 if (sc->hw_if->streamon) 306 error = (sc->hw_if->streamon)(sc->hw_hdl, 307 (int)*data); 308 break; 309 case VIDIOC_STREAMOFF: 310 if (sc->hw_if->streamoff) 311 error = (sc->hw_if->streamoff)(sc->hw_hdl, 312 (int)*data); 313 break; 314 case VIDIOC_TRY_FMT: 315 if (sc->hw_if->try_fmt) 316 error = (sc->hw_if->try_fmt)(sc->hw_hdl, 317 (struct v4l2_format *)data); 318 break; 319 case VIDIOC_QUERYCTRL: 320 if (sc->hw_if->queryctrl) 321 error = (sc->hw_if->queryctrl)(sc->hw_hdl, 322 (struct v4l2_queryctrl *)data); 323 break; 324 case VIDIOC_G_CTRL: 325 if (sc->hw_if->g_ctrl) 326 error = (sc->hw_if->g_ctrl)(sc->hw_hdl, 327 (struct v4l2_control *)data); 328 break; 329 case VIDIOC_S_CTRL: 330 if (sc->hw_if->s_ctrl) 331 error = (sc->hw_if->s_ctrl)(sc->hw_hdl, 332 (struct v4l2_control *)data); 333 break; 334 default: 335 error = (ENOTTY); 336 } 337 338 return (error); 339 } 340 341 int 342 videopoll(dev_t dev, int events, struct proc *p) 343 { 344 int unit = VIDEOUNIT(dev); 345 struct video_softc *sc; 346 int error, revents = 0; 347 348 if (unit >= video_cd.cd_ndevs || 349 (sc = video_cd.cd_devs[unit]) == NULL) 350 return (POLLERR); 351 352 if (sc->sc_dying) 353 return (POLLERR); 354 355 DPRINTF(("%s: events=0x%x\n", __func__, events)); 356 357 if (events & (POLLIN | POLLRDNORM)) { 358 if (sc->sc_frames_ready > 0) 359 revents |= events & (POLLIN | POLLRDNORM); 360 } 361 if (revents == 0) { 362 if (events & (POLLIN | POLLRDNORM)) { 363 /* 364 * Start the stream in read() mode if not already 365 * started. If the user wanted mmap() mode, 366 * he should have called mmap() before now. 367 */ 368 if (sc->sc_vidmode == VIDMODE_NONE && 369 sc->hw_if->start_read) { 370 error = sc->hw_if->start_read(sc->hw_hdl); 371 if (error) 372 return (POLLERR); 373 sc->sc_vidmode = VIDMODE_READ; 374 } 375 selrecord(p, &sc->sc_rsel); 376 } 377 } 378 379 DPRINTF(("%s: revents=0x%x\n", __func__, revents)); 380 381 return (revents); 382 } 383 384 paddr_t 385 videommap(dev_t dev, off_t off, int prot) 386 { 387 struct video_softc *sc; 388 int unit; 389 caddr_t p; 390 paddr_t pa; 391 392 DPRINTF(("%s: off=%d, prot=%d\n", __func__, off, prot)); 393 394 unit = VIDEOUNIT(dev); 395 if (unit >= video_cd.cd_ndevs || 396 (sc = video_cd.cd_devs[unit]) == NULL) 397 return (-1); 398 399 if (sc->sc_dying) 400 return (-1); 401 402 if (sc->hw_if->mappage == NULL) 403 return (-1); 404 405 p = sc->hw_if->mappage(sc->hw_hdl, off, prot); 406 if (p == NULL) 407 return (-1); 408 if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) 409 panic("videommap: invalid page"); 410 sc->sc_vidmode = VIDMODE_MMAP; 411 412 return (pa); 413 } 414 415 int 416 video_submatch(struct device *parent, void *match, void *aux) 417 { 418 struct cfdata *cf = match; 419 420 return (cf->cf_driver == &video_cd); 421 } 422 423 /* 424 * Called from hardware driver. This is where the MI video driver gets 425 * probed/attached to the hardware driver 426 */ 427 struct device * 428 video_attach_mi(struct video_hw_if *rhwp, void *hdlp, struct device *dev) 429 { 430 struct video_attach_args arg; 431 432 arg.hwif = rhwp; 433 arg.hdl = hdlp; 434 return (config_found_sm(dev, &arg, videoprint, video_submatch)); 435 } 436 437 void 438 video_intr(void *addr) 439 { 440 struct video_softc *sc = (struct video_softc *)addr; 441 442 DPRINTF(("video_intr sc=%p\n", sc)); 443 if (sc->sc_vidmode != VIDMODE_NONE) 444 sc->sc_frames_ready++; 445 else 446 printf("%s: interrupt but no streams!\n", __func__); 447 if (sc->sc_vidmode == VIDMODE_READ) 448 wakeup(sc); 449 selwakeup(&sc->sc_rsel); 450 } 451 452 int 453 videoprint(void *aux, const char *pnp) 454 { 455 if (pnp != NULL) 456 printf("video at %s", pnp); 457 return (UNCONF); 458 } 459 460 int 461 videodetach(struct device *self, int flags) 462 { 463 struct video_softc *sc = (struct video_softc *)self; 464 int maj, mn; 465 466 if (sc->sc_fbuffer != NULL) 467 free(sc->sc_fbuffer, M_DEVBUF, sc->sc_fbufferlen); 468 469 /* locate the major number */ 470 for (maj = 0; maj < nchrdev; maj++) 471 if (cdevsw[maj].d_open == videoopen) 472 break; 473 474 /* Nuke the vnodes for any open instances (calls close). */ 475 mn = self->dv_unit; 476 vdevgone(maj, mn, mn, VCHR); 477 478 return (0); 479 } 480 481 int 482 videoactivate(struct device *self, int act) 483 { 484 struct video_softc *sc = (struct video_softc *)self; 485 486 switch (act) { 487 case DVACT_DEACTIVATE: 488 sc->sc_dying = 1; 489 break; 490 } 491 return (0); 492 } 493