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