video.c 11 KB

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