1 /**************************************************************************
3 xserver-xorg-video-emulfb
5 Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
7 Contact: Boram Park <boram1288.park@samsung.com>
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 **************************************************************************/
35 #include <sys/types.h>
39 #include <X11/extensions/Xv.h>
40 #include <X11/extensions/Xvproto.h>
42 #include "fbdev_util.h"
43 #include "fbdev_video_v4l2.h"
47 #include "fbdev_util.h"
48 #include "fbdev_video.h"
49 #include "fbdev_video_fourcc.h"
50 #include "fbdev_pixman.h"
54 typedef struct _DeviceInfo
56 char *video; /* video */
60 typedef struct _FormatInfo
65 FBDevV4l2Memory memory;
99 FBDevV4l2FimcBuffer fimcbuf;
100 FBDevV4l2SrcBuffer *src_buf;
101 FBDevV4l2DstBuffer *dst_buf;
102 FBDevV4l2Memory memory;
109 void *aligned_buffer;
121 static FormatInfo format_infos [] =
123 { FOURCC_RGB565, TYPE_RGB, V4L2_PIX_FMT_RGB565, V4L2_MEMORY_MMAP },
124 { FOURCC_RGB32, TYPE_RGB, V4L2_PIX_FMT_RGB32, V4L2_MEMORY_MMAP },
125 { FOURCC_I420, TYPE_YUV420, V4L2_PIX_FMT_YUV420, V4L2_MEMORY_MMAP },
126 { FOURCC_YUY2, TYPE_YUV422, V4L2_PIX_FMT_YUYV, V4L2_MEMORY_MMAP },
127 { FOURCC_YV12, TYPE_YUV420, V4L2_PIX_FMT_YVU420, V4L2_MEMORY_MMAP },
131 static XF86ImageRec Images[] =
140 static DeviceInfo device_infos[] =
142 { "/dev/video1", FALSE },
143 { "/dev/video2", FALSE },
146 #define NUM_IMAGES (sizeof(Images) / sizeof(XF86ImageRec))
147 #define DEVICE_NUMS (sizeof (device_infos) / sizeof (DeviceInfo))
150 _fbdevVideoV4l2SetDst (int fd, int offset_x, int offset_y, xRectangle *rect)
152 struct v4l2_format format = {0,};
155 return_val_if_fail (fd >= 0, FALSE);
157 DRVLOG ("[SetDst] offset(%d,%d) win(%d,%d %dx%d) \n", offset_x, offset_y,
158 rect->x, rect->y, rect->width, rect->height);
160 caps = V4L2_CAP_VIDEO_OVERLAY;
161 if (!fbdev_v4l2_querycap (fd, caps))
166 format.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
167 if (!fbdev_v4l2_g_fmt (fd, &format))
170 format.fmt.win.w.left = rect->x + offset_x;
171 format.fmt.win.w.top = rect->y + offset_y;
172 format.fmt.win.w.width = rect->width;
173 format.fmt.win.w.height = rect->height;
174 if (!fbdev_v4l2_s_fmt (fd, &format))
181 _fbdevVideoV4l2SetBuffer (int fd,
182 FBDevV4l2BufType type,
183 FBDevV4l2Memory memory,
185 FBDevV4l2DstBuffer **mem_buf)
187 struct v4l2_requestbuffers req = {0,};
189 return_val_if_fail (fd >= 0, FALSE);
191 DRVLOG ("[SetBuffer] num_buf(%d) mem_buf(%p) memory(%d)\n",
192 num_buf, mem_buf, memory);
198 if (!fbdev_v4l2_reqbuf (fd, &req))
201 if (memory == V4L2_MEMORY_MMAP)
203 FBDevV4l2DstBuffer *out_buf;
206 return_val_if_fail (mem_buf != NULL, FALSE);
208 out_buf = calloc (req.count, sizeof (FBDevV4l2DstBuffer));
209 return_val_if_fail (out_buf != NULL, FALSE);
211 for (i = 0; i < num_buf; i++)
213 struct v4l2_buffer buffer = {0,};
218 buffer.memory = V4L2_MEMORY_MMAP;
219 if (!fbdev_v4l2_querybuf (fd, &buffer))
225 out_buf[i].index = buffer.index;
226 out_buf[i].size = buffer.length;
227 out_buf[i].buf = mmap (NULL, buffer.length,
228 PROT_READ | PROT_WRITE , \
229 MAP_SHARED , fd, buffer.m.offset & ~(PAGE_SIZE - 1));
230 out_buf[i].buf += buffer.m.offset & (PAGE_SIZE - 1);
232 if (out_buf[i].buf == MAP_FAILED)
234 xf86DrvMsg (0, X_ERROR, "[SetBuffer] mmap failed. index(%d)\n", i);
247 _fbdevVideoV4l2ClearBuffer (int fd,
248 FBDevV4l2BufType type,
249 FBDevV4l2Memory memory,
251 FBDevV4l2DstBuffer *mem_buf)
253 struct v4l2_requestbuffers req = {0,};
255 return_val_if_fail (fd >= 0, FALSE);
257 DRVLOG ("[ClearBuffer] memory(%d) num_buf(%d) mem_buf(%p)\n",
258 num_buf, mem_buf, memory);
260 if (memory == V4L2_MEMORY_MMAP && mem_buf)
264 for (i = 0; i < num_buf; i++)
266 if (munmap (mem_buf[i].buf, mem_buf[i].size) == -1)
267 xf86DrvMsg (0, X_WARNING, "[ClearBuffer] Failed to unmap v4l2 buffer at index %d\n", i);
276 if (!fbdev_v4l2_reqbuf (fd, &req))
283 _fbdevVideoV4l2StreamOn (int fd)
285 return_val_if_fail (fd >= 0, FALSE);
287 DRVLOG ("[StreamOn] \n");
289 if (!fbdev_v4l2_start_overlay (fd))
297 _fbdevVideoV4l2StreamOff (int fd)
299 return_val_if_fail (fd >= 0, FALSE);
301 DRVLOG ("[StreamOff] \n");
303 if (!fbdev_v4l2_stop_overlay (fd))
310 _open_device (char *device)
314 return_val_if_fail (device != NULL, -1);
316 fd = open (device, O_RDWR);
319 xf86DrvMsg (0, X_ERROR, "Cannot open '%s'. fd(%d)\n", device, fd);
323 DRVLOG ("'%s' opened. fd(%d) \n", device, fd);
329 _close_device (int fd)
333 return_if_fail (fd >= 0);
338 xf86DrvMsg (0, X_ERROR, "Cannot close fd(%d)\n", fd);
342 DRVLOG ("fd(%d) closed. \n", fd);
346 _fbdevVideoV4l2EnsureStreamOff (FBDevDispHandle *hdisp)
348 if (!hdisp->status.streamon)
351 if (!_fbdevVideoV4l2StreamOff (hdisp->video_fd))
354 hdisp->status.streamon = FALSE;
360 _fbdevVideoV4l2OpenDevice (FBDevDispHandle *hdisp, int index)
362 if (device_infos[index].bOpened)
364 DRVLOG ("[OpenDevice, %p] Already opened : %s\n", hdisp, device_infos[index].video);
368 hdisp->video_fd = _open_device (device_infos[index].video);
369 if (hdisp->video_fd < 0)
372 device_infos[index].bOpened = TRUE;
377 /* This function never failed.
378 * If failed, it means kernel has some problems.
379 * Then a device should be rebooted.
382 _fbdevVideoV4l2CloseDevice (FBDevDispHandle *hdisp)
384 if (!_fbdevVideoV4l2EnsureStreamOff (hdisp)) // We will consider this as a LCD Off case.
385 xf86DrvMsg (0, X_WARNING, "[CloseDevice, %p] Warning : Cannot stream off!! \n", hdisp);
387 if (hdisp->video_fd >= 0)
388 if (!_fbdevVideoV4l2ClearBuffer (hdisp->video_fd,
389 V4L2_BUF_TYPE_VIDEO_OVERLAY,
393 xf86DrvMsg (0, X_WARNING, "[CloseDevice, %p] Warning : Cannot clear buffer!! \n", hdisp);
395 hdisp->dst_buf = NULL;
397 if (hdisp->video_fd >= 0)
399 _close_device (hdisp->video_fd);
400 hdisp->video_fd = -1;
403 if (hdisp->aligned_buffer)
405 free (hdisp->aligned_buffer);
406 hdisp->aligned_buffer = NULL;
407 hdisp->aligned_width = 0;
410 device_infos[hdisp->index].bOpened = FALSE;
414 fbdevVideoV4l2GetHandleNums (void)
420 fbdevVideoV4l2HandleOpened (int index)
422 return_val_if_fail (index < DEVICE_NUMS, FALSE);
424 return device_infos[index].bOpened;
428 fbdevVideoV4l2OpenHandle (ScreenPtr pScreen, int index, int requestbuffer)
430 FBDevDispHandle *handle;
432 return_val_if_fail (pScreen != NULL, NULL);
433 return_val_if_fail (index < DEVICE_NUMS, NULL);
435 handle = (FBDevDispHandle*)calloc (sizeof (FBDevDispHandle), 1);
437 return_val_if_fail (handle != NULL, NULL);
439 handle->pScreen = pScreen;
440 handle->index = index;
441 handle->status.hw_rotate = -1;
442 handle->status.id = 0;
443 handle->status.cur_idx = -1;
444 handle->status.init = 0;
445 handle->memory = V4L2_MEMORY_MMAP;
446 handle->video_fd = -1;
448 if (!_fbdevVideoV4l2OpenDevice (handle, index))
454 DRVLOG ("[OpenHandle, %p] Handle(%d) opened. \n", handle, index);
460 fbdevVideoV4l2CloseHandle (void *handle)
462 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
464 return_if_fail (handle != NULL);
466 _fbdevVideoV4l2CloseDevice ((FBDevDispHandle*)handle);
468 if (hdisp->status.backup)
470 free (hdisp->status.backup);
471 hdisp->status.backup = NULL;
474 DRVLOG ("[CloseHandle, %p] Handle(%d) closed. \n", hdisp, hdisp->index);
480 fbdevVideoV4l2StreamOn (void *handle)
482 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
485 return_val_if_fail (hdisp != NULL, FALSE);
487 hdisp->re_setting = TRUE;
489 if (!_fbdevVideoV4l2OpenDevice (hdisp, hdisp->index))
492 fbdevVideoV4l2SetFormat (handle,
497 hdisp->status.scn_rotate,
498 hdisp->status.hw_rotate,
504 phy_addrs[0] = hdisp->fimcbuf.base[0];
505 phy_addrs[1] = hdisp->fimcbuf.base[1];
506 phy_addrs[2] = hdisp->fimcbuf.base[2];
508 if (hdisp->status.backup)
512 size = fbdevVideoQueryImageAttributes (NULL, FOURCC_RGB32,
513 (unsigned short*)&hdisp->status.dst.width,
514 (unsigned short*)&hdisp->status.dst.height,
517 memcpy (hdisp->dst_buf[0].buf, hdisp->status.backup, size);
519 free (hdisp->status.backup);
520 hdisp->status.backup = NULL;
523 hdisp->re_setting = FALSE;
525 DRVLOG ("%s \n", __FUNCTION__);
531 fbdevVideoV4l2StreamOff (void *handle)
533 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
535 return_if_fail (hdisp != NULL);
537 if (hdisp->memory == V4L2_MEMORY_MMAP)
541 if (hdisp->status.backup)
543 free (hdisp->status.backup);
544 hdisp->status.backup = NULL;
547 size = fbdevVideoQueryImageAttributes (NULL, FOURCC_RGB32,
548 (unsigned short*)&hdisp->status.dst.width,
549 (unsigned short*)&hdisp->status.dst.height,
553 hdisp->status.backup = malloc (size);
555 if (hdisp->status.backup &&
557 hdisp->dst_buf[hdisp->status.queued_index].buf)
559 memcpy (hdisp->status.backup,
560 hdisp->dst_buf[hdisp->status.queued_index].buf,
565 _fbdevVideoV4l2CloseDevice (hdisp);
567 DRVLOG ("%s \n", __FUNCTION__);
571 fbdevVideoV4l2VideoOffset (void *handle, int x, int y)
573 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
575 return_if_fail (handle != NULL);
577 DRVLOG ("[VideoOffset, %p] to %d,%d\n", hdisp, x, y);
579 if (hdisp->offset_x == x && hdisp->offset_y == y)
582 if (!_fbdevVideoV4l2SetDst (hdisp->video_fd, x, y, &hdisp->status.dst))
584 xf86DrvMsg (0, X_ERROR, "[VideoOffset, %p] _fbdevVideoV4l2SetDst is failed. \n", hdisp);
592 /* img->x, img->y : not used. */
594 fbdevVideoV4l2SetFormat (void *handle,
595 xRectangle *img, xRectangle *crop, xRectangle *dst,
604 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
605 Bool src_changed = FALSE;
606 Bool dst_changed = FALSE;
607 Bool buf_changed = FALSE;
609 return_val_if_fail (handle != NULL, FALSE);
610 return_val_if_fail (img != NULL, FALSE);
611 return_val_if_fail (crop != NULL, FALSE);
612 return_val_if_fail (dst != NULL, FALSE);
614 DRVLOG ("[SetFormat, %p] try to set : img(%d,%d %dx%d) crop(%d,%d %dx%d) dst(%d,%d %dx%d) id(%x), rot(%d), flip(%d,%d) req(%d)\n", hdisp,
615 img->x, img->y, img->width, img->height,
616 crop->x, crop->y, crop->width, crop->height,
617 dst->x, dst->y, dst->width, dst->height,
618 id, hw_rotate, hflip, vflip, requestbuffer);
620 if (memcmp (&hdisp->status.img, img, sizeof (xRectangle)) ||
621 memcmp (&hdisp->status.crop, crop, sizeof (xRectangle)) ||
622 hdisp->status.id != id)
625 if (memcmp (&hdisp->status.dst, dst, sizeof (xRectangle)) ||
626 hdisp->status.hw_rotate != hw_rotate ||
627 hdisp->status.hflip != hflip ||
628 hdisp->status.vflip != vflip)
631 if (hdisp->status.init && (src_changed || dst_changed || buf_changed))
633 _fbdevVideoV4l2CloseDevice (hdisp);
634 _fbdevVideoV4l2OpenDevice (hdisp, hdisp->index);
636 DRVLOG ("[SetFormat, %p] changed : img(%d) dst(%d) buf(%d) \n", hdisp,
637 src_changed, dst_changed, buf_changed);
639 /* After close device, below all steps should be done. */
640 src_changed = dst_changed = buf_changed = TRUE;
641 hdisp->status.init = 0;
644 if (hdisp->re_setting)
645 src_changed = dst_changed = buf_changed = TRUE;
647 if (src_changed || dst_changed || buf_changed)
649 fbdevVideoV4l2GetFormatInfo (id, NULL, &hdisp->pixfmt, &hdisp->memory);
651 DRVLOG ("[SetFormat, %p] id(%c%c%c%c) => pixfmt(%d) memory(%d) \n", hdisp,
652 id & 0xFF, (id & 0xFF00) >> 8, (id & 0xFF0000) >> 16, (id & 0xFF000000) >> 24,
653 hdisp->pixfmt, hdisp->memory);
655 hdisp->status.img = *img;
656 hdisp->status.crop = *crop;
657 hdisp->status.id = id;
658 hdisp->status.sync = sync;
659 hdisp->status.init = 1;
661 hdisp->status.cur_idx = 0;
662 hdisp->status.hw_rotate = hw_rotate;
663 hdisp->status.scn_rotate = scn_rotate;
664 hdisp->status.hflip = hflip;
665 hdisp->status.vflip = vflip;
666 hdisp->status.dst = *dst;
668 if (!_fbdevVideoV4l2SetDst (hdisp->video_fd, hdisp->offset_x, hdisp->offset_y, dst))
670 xf86DrvMsg (0, X_ERROR, "[SetFormat, %p] _fbdevVideoV4l2SetDst is failed. \n", hdisp);
674 if (!_fbdevVideoV4l2SetBuffer (hdisp->video_fd,
675 V4L2_BUF_TYPE_VIDEO_OVERLAY,
680 xf86DrvMsg (0, X_ERROR, "[SetFormat, %p] _fbdevVideoV4l2SetBuffer is failed. \n", hdisp);
684 hdisp->status.cur_idx = 0;
687 if (!hdisp->status.streamon)
689 _fbdevVideoV4l2StreamOn (hdisp->video_fd);
690 hdisp->status.streamon = TRUE;
697 fbdevVideoV4l2SupportImages (int *count)
706 fbdevVideoV4l2Draw (void *handle, uchar *buf, uint *phy_addrs)
708 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
709 pixman_format_code_t src_format, dst_format;
710 xRectangle img = hdisp->status.img;
711 xRectangle src = hdisp->status.crop;
712 xRectangle pxm = hdisp->status.dst;
713 xRectangle dst = hdisp->status.dst;
715 pxm.x = pxm.y = dst.x = dst.y = 0;
717 switch (hdisp->pixfmt)
719 case V4L2_PIX_FMT_YUV420:
720 case V4L2_PIX_FMT_YVU420:
721 src_format = PIXMAN_yv12;
723 case V4L2_PIX_FMT_YUYV:
724 src_format = PIXMAN_yuy2;
726 case V4L2_PIX_FMT_RGB565:
727 src_format = PIXMAN_r5g6b5;
729 case V4L2_PIX_FMT_RGB24:
730 src_format = PIXMAN_r8g8b8;
732 case V4L2_PIX_FMT_RGB32:
733 src_format = PIXMAN_a8r8g8b8;
739 switch (hdisp->pixfmt)
741 case V4L2_PIX_FMT_YUV420:
742 dst_format = PIXMAN_x8b8g8r8;
745 dst_format = PIXMAN_x8r8g8b8;
749 if (src_format == PIXMAN_yv12 && img.width % 16)
751 int src_p[3] = {0,}, src_o[3] = {0,}, src_l[3] = {0,};
752 int dst_p[3] = {0,}, dst_o[3] = {0,}, dst_l[3] = {0,};
753 unsigned short src_w, src_h, dst_w, dst_h;
758 fbdevVideoQueryImageAttributes (NULL, FOURCC_I420, &src_w, &src_h,
759 src_p, src_o, src_l);
761 dst_w = (img.width + 15) & ~15;
763 size = fbdevVideoQueryImageAttributes (NULL, FOURCC_I420, &dst_w, &dst_h,
764 dst_p, dst_o, dst_l);
766 if (!hdisp->aligned_buffer)
768 hdisp->aligned_buffer = malloc (size);
769 if (!hdisp->aligned_buffer)
773 fbdev_util_copy_image (src_w, src_h,
774 (char*)buf, src_w, src_h,
776 (char*)hdisp->aligned_buffer, dst_w, dst_h,
780 hdisp->aligned_width = dst_w;
782 buf = hdisp->aligned_buffer;
785 /* support only RGB */
786 fbdev_pixman_convert_image (PIXMAN_OP_SRC,
787 buf, hdisp->dst_buf[0].buf,
788 src_format, dst_format,
789 &img, &pxm, &src, &dst,
790 NULL, (hdisp->status.hw_rotate + (360 - hdisp->status.scn_rotate)) % 360,
791 hdisp->status.hflip, hdisp->status.vflip);
797 fbdevVideoV4l2GetFormatInfo (int id, int *type, uint *pixelformat, FBDevV4l2Memory *memory)
801 for (i = 0; i < sizeof (format_infos) / sizeof (FormatInfo); i++)
802 if (format_infos[i].id == id)
805 *type = format_infos[i].type;
807 *pixelformat = format_infos[i].pixelformat;
809 *memory = format_infos[i].memory;
816 /* img : original src size
817 * src : real src size (cropped area inside img)
818 * dst : real dst size
819 * original dst size (in case that image is drawn on opened framebuffer)
822 fbdevVideoV4l2CheckSize (void *handle, uint pixelformat,
823 xRectangle *img, xRectangle *src, xRectangle *dst,
824 int type, int memory)
830 xf86DrvMsg (0, X_WARNING, "img's width(%d) is not multiple of 16!!!\n", img->width);
832 if (type == TYPE_YUV420 && img->height % 2)
833 xf86DrvMsg (0, X_WARNING, "img's height(%d) is not multiple of 2!!!\n", img->height);
835 return_val_if_fail (img->width >= 16, FALSE);
836 return_val_if_fail (img->height >= 16, FALSE);
842 if (type == TYPE_YUV420 || type == TYPE_YUV422)
844 src->x = src->x & (~0x1);
845 src->width = src->width & (~0x1);
848 if (type == TYPE_YUV420)
849 src->height = src->height & (~0x1);
851 return_val_if_fail (src->width >= 16, FALSE);
852 return_val_if_fail (src->height >= 16, FALSE);
858 dst->width = dst->width & (~0x1);
859 dst->height = dst->height & (~0x1);
861 return_val_if_fail (dst->width >= 8, FALSE);
862 return_val_if_fail (dst->height >= 8, FALSE);
869 fbdevVideoGetFBInfo (void *handle, void **base, xRectangle *pos)
871 FBDevDispHandle *hdisp = (FBDevDispHandle*)handle;
877 *pos = hdisp->status.dst;
879 *base = hdisp->dst_buf[0].buf;