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