Tizen 2.1 base
[adaptation/xorg/driver/xserver-xorg-video-emulfb.git] / src / xv / fbdev_video.c
1 /*
2  * xserver-xorg-video-emulfb
3  *
4  * Copyright 2004 Keith Packard
5  * Copyright 2005 Eric Anholt
6  * Copyright 2006 Nokia Corporation
7  * Copyright 2010 - 2011 Samsung Electronics co., Ltd. All Rights Reserved.
8  *
9  * Contact: Boram Park <boram1288.park@samsung.com>
10  *
11  * Permission to use, copy, modify, distribute and sell this software and its
12  * documentation for any purpose is hereby granted without fee, provided that
13  * the above copyright notice appear in all copies and that both that
14  * copyright notice and this permission notice appear in supporting
15  * documentation, and that the names of the authors and/or copyright holders
16  * not be used in advertising or publicity pertaining to distribution of the
17  * software without specific, written prior permission.  The authors and
18  * copyright holders make no representations about the suitability of this
19  * software for any purpose.  It is provided "as is" without any express
20  * or implied warranty.
21  *
22  * THE AUTHORS AND COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO
23  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
24  * FITNESS, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
25  * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
26  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
27  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
28  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
29  *
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <unistd.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/time.h>
39 #include <sys/ioctl.h>
40
41 #include <pixman.h>
42 #include <X11/Xatom.h>
43 #include <X11/extensions/Xv.h>
44 #include <X11/extensions/Xvproto.h>
45 #include <X11/extensions/dpmsconst.h>
46 #include "fourcc.h"
47
48 #include "fb.h"
49 #include "fbdevhw.h"
50 #include "damage.h"
51
52 #include "xf86xv.h"
53
54 #include "fbdev.h"
55
56 #include "fbdev_dpms.h"
57 #include "fbdev_video.h"
58 #include "fbdev_util.h"
59 #include "fbdev_util.h"
60 #include "fbdev_pixman.h"
61 #include "fbdev_fb.h"
62 #include "fbdev_video_fourcc.h"
63 #include "fbdev_video_v4l2.h"
64 #include "fbdev_video_virtual.h"
65
66 #include "xv_types.h"
67
68 extern CallbackListPtr DPMSCallback;
69
70 static XF86VideoEncodingRec DummyEncoding[] =
71 {
72         { 0, "XV_IMAGE", -1, -1, { 1, 1 } },
73         { 1, "XV_IMAGE", 2560, 2560, { 1, 1 } },
74 };
75
76 static XF86VideoFormatRec Formats[] =
77 {
78         { 16, TrueColor },
79         { 24, TrueColor },
80         { 32, TrueColor },
81 };
82
83 static XF86AttributeRec Attributes[] =
84 {
85         { 0, -1, 270, "_USER_WM_PORT_ATTRIBUTE_ROTATION" },
86         { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_HFLIP" },
87         { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_VFLIP" },
88         { 0, -1, 1, "_USER_WM_PORT_ATTRIBUTE_PREEMPTION" },
89         { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_DRAWING_MODE" },
90         { 0, 0, 1, "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF" },
91 };
92
93 typedef enum
94 {
95         PAA_MIN,
96         PAA_ROTATION,
97         PAA_HFLIP,
98         PAA_VFLIP,
99         PAA_PREEMPTION,
100         PAA_DRAWINGMODE,
101         PAA_STREAMOFF,
102         PAA_MAX
103 } FBDevPortAttrAtom;
104
105 enum
106 {
107         ON_NONE,
108         ON_FB,
109         ON_WINDOW,
110         ON_PIXMAP
111 };
112
113 static struct
114 {
115         FBDevPortAttrAtom  paa;
116         const char      *name;
117         Atom             atom;
118 } atom_list[] =
119 {
120         { PAA_ROTATION, "_USER_WM_PORT_ATTRIBUTE_ROTATION", None },
121         { PAA_HFLIP, "_USER_WM_PORT_ATTRIBUTE_HFLIP", None },
122         { PAA_VFLIP, "_USER_WM_PORT_ATTRIBUTE_VFLIP", None },
123         { PAA_PREEMPTION, "_USER_WM_PORT_ATTRIBUTE_PREEMPTION", None },
124         { PAA_DRAWINGMODE, "_USER_WM_PORT_ATTRIBUTE_DRAWING_MODE", None },
125         { PAA_STREAMOFF, "_USER_WM_PORT_ATTRIBUTE_STREAM_OFF", None },
126 };
127
128 static int registered_handler;
129 extern CallbackListPtr DPMSCallback;
130
131 #define FBDEV_MAX_PORT    16
132 #define REQ_BUF_NUM       3
133
134 #define NUM_FORMATS       (sizeof(Formats) / sizeof(Formats[0]))
135 #define NUM_ATTRIBUTES    (sizeof(Attributes) / sizeof(Attributes[0]))
136 #define NUM_ATOMS         (sizeof(atom_list) / sizeof(atom_list[0]))
137
138 static PixmapPtr
139 _fbdevVideoGetPixmap (DrawablePtr pDraw)
140 {
141     if (pDraw->type == DRAWABLE_WINDOW)
142         return pDraw->pScreen->GetWindowPixmap ((WindowPtr) pDraw);
143     else
144         return (PixmapPtr) pDraw;
145 }
146
147 static void
148 _fbdevVideoGetRotation (ScreenPtr      pScreen,
149                         FBDevPortPrivPtr pPortPriv,
150                         DrawablePtr    pDraw,
151                         int           *scn_rotate,
152                         int           *rotate,
153                         int           *hw_rotate)
154 {
155         ScrnInfoPtr pScrnInfo = xf86Screens[pScreen->myNum];
156         FBDevPtr pFBDev = FBDEVPTR (pScrnInfo);
157
158         *scn_rotate = 0;
159         *rotate = 0;
160         *hw_rotate = 0;
161
162 #ifdef RANDR
163         switch (pFBDev->rotate)
164         {
165         case RR_Rotate_90:
166                 *scn_rotate = 270;
167         break;
168         case RR_Rotate_180:
169                 *scn_rotate = 180;
170         break;
171         case RR_Rotate_270:
172                 *scn_rotate = 90;
173         break;
174         case RR_Rotate_0:
175                 break;
176         }
177 #endif
178
179         if (pPortPriv->rotate >= 0)
180                 *rotate = pPortPriv->rotate;
181
182         *hw_rotate = (*rotate + *scn_rotate + 360) % 360;
183 }
184
185 static void
186 _fbdevVideoCloseV4l2Handle (ScrnInfoPtr pScrnInfo, FBDevPortPrivPtr pPortPriv)
187 {
188         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
189
190         if (!pPortPriv->v4l2_handle)
191                 return;
192
193         fbdevVideoV4l2CloseHandle (pPortPriv->v4l2_handle);
194
195         pFBDev->v4l2_owner[pPortPriv->v4l2_index] = NULL;
196
197         pPortPriv->v4l2_handle = NULL;
198         pPortPriv->v4l2_index = -1;
199 }
200
201 static Atom
202 _fbdevVideoGetPortAtom (FBDevPortAttrAtom paa)
203 {
204         int i;
205
206         return_val_if_fail (paa > PAA_MIN && paa < PAA_MAX, None);
207
208         for (i = 0; i < NUM_ATOMS; i++)
209         {
210                 if (paa == atom_list[i].paa)
211                 {
212                         if (atom_list[i].atom == None)
213                                 atom_list[i].atom = MakeAtom (atom_list[i].name, strlen (atom_list[i].name), TRUE);
214
215                         return atom_list[i].atom;
216                 }
217         }
218
219         ErrorF ("Error: Unknown Port Attribute Name!\n");
220
221         return None;
222 }
223
224 static int
225 _fbdevVideoInterfbdevtXRects (xRectangle *dest, xRectangle *src1, xRectangle *src2)
226 {
227         int dest_x, dest_y;
228         int dest_x2, dest_y2;
229         int return_val;
230
231         return_val_if_fail (src1 != NULL, FALSE);
232         return_val_if_fail (src2 != NULL, FALSE);
233
234         return_val = FALSE;
235
236         dest_x = MAX (src1->x, src2->x);
237         dest_y = MAX (src1->y, src2->y);
238         dest_x2 = MIN (src1->x + src1->width, src2->x + src2->width);
239         dest_y2 = MIN (src1->y + src1->height, src2->y + src2->height);
240
241         if (dest_x2 > dest_x && dest_y2 > dest_y)
242         {
243                 if (dest)
244                 {
245                         dest->x = dest_x;
246                         dest->y = dest_y;
247                         dest->width = dest_x2 - dest_x;
248                         dest->height = dest_y2 - dest_y;
249                 }
250                 return_val = TRUE;
251         }
252         else if (dest)
253         {
254                 dest->width = 0;
255                 dest->height = 0;
256         }
257
258         return return_val;
259 }
260
261 static int
262 _fbdevVideodrawingOn (FBDevPortPrivPtr pPortPriv, DrawablePtr pDraw)
263 {
264     if (pDraw->type == DRAWABLE_PIXMAP)
265         return ON_PIXMAP;
266     else if (pDraw->type == DRAWABLE_WINDOW)
267     {
268         PropertyPtr prop = fbdev_util_get_window_property ((WindowPtr)pDraw,
269                                                            "XV_ON_DRAWABLE");
270         if (prop && *(int*)prop->data > 0)
271             return ON_WINDOW;
272     }
273
274     return ON_FB;
275 }
276
277 static int
278 _fbdevVideoParseFormatBuffer (uchar *buf, uint *phy_addrs)
279 {
280         XV_PUTIMAGE_DATA_PTR data = (XV_PUTIMAGE_DATA_PTR) buf;
281
282         int valid = XV_PUTIMAGE_VALIDATE_DATA (data);
283         if (valid < 0)
284                 return valid;
285
286         phy_addrs[0] = data->YPhyAddr;
287         phy_addrs[1] = data->CbPhyAddr;
288         phy_addrs[2] = data->CrPhyAddr;
289
290         return 0;
291 }
292
293 static XF86ImageRec *
294 _fbdevVideoGetImageInfo (int id)
295 {
296         XF86ImagePtr pImages;
297         int i, count = 0;
298
299         pImages = fbdevVideoV4l2SupportImages (&count);
300
301         for (i = 0; i < count; i++)
302         {
303                 if (pImages[i].id == id)
304                         return &pImages[i];
305         }
306
307         return NULL;
308 };
309
310 static Bool
311 _fbdevVideoSetMode (ScrnInfoPtr pScrnInfo, FBDevPortPrivPtr pPortPriv, int *index)
312 {
313         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
314         Bool full = TRUE;
315         int  i = 0;
316
317         *index = -1;
318
319         if (pPortPriv->preemption == -1)
320         {
321                 pPortPriv->mode = PORT_MODE_WAITING;
322                 return TRUE;
323         }
324
325         for (i = 0; i < pFBDev->v4l2_num; i++)
326                 if (!fbdevVideoV4l2HandleOpened (i))
327                 {
328                         full = FALSE;
329                         break;
330                 }
331
332         if (!full)
333         {
334                 *index = i;
335                 pPortPriv->mode = PORT_MODE_V4L2;
336                 return TRUE;
337         }
338
339         /* All handles are occupied. So we need to steal one of them. */
340
341         if (pPortPriv->preemption == 0)
342         {
343                 pPortPriv->mode = PORT_MODE_WAITING;
344                 return TRUE;
345         }
346
347         for (i = 0; i < pFBDev->v4l2_num; i++)
348         {
349                 FBDevPortPrivPtr pOwnerPort = (FBDevPortPrivPtr) pFBDev->v4l2_owner[i];
350
351                 if (pOwnerPort && pOwnerPort->preemption == 0)
352                 {
353                         _fbdevVideoCloseV4l2Handle (pScrnInfo, pOwnerPort);
354
355                         pOwnerPort->mode = PORT_MODE_WAITING;
356                         pPortPriv->mode = PORT_MODE_V4L2;
357                         *index = i;
358                         return TRUE;
359                 }
360         }
361
362         xf86DrvMsg (0, X_ERROR, "fbdev/put_image: Three or more preemptive ports were requested\n");
363
364         return FALSE;
365 }
366
367 static int
368 _fbdevVideoPutImageV4l2 (ScrnInfoPtr pScrnInfo,
369                          FBDevPortPrivPtr pPortPriv,
370                          xRectangle *img,
371                          xRectangle *src,
372                          xRectangle *dst,
373                          RegionPtr   clip_boxes,
374                          int scn_rotate,
375                          int rotate,
376                          int hw_rotate,
377                          XF86ImageRec *image_info,
378                          uchar *buf,
379                          FBDevPortMode modeBefore,
380                          int v4l2_index,
381                          DrawablePtr pDraw)
382 {
383         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
384         uint phy_addrs[4] = {0,};
385         FBDevV4l2Memory memory;
386         uint pixelformat;
387         int fmt_type = 0;
388
389         if (!fbdevVideoV4l2GetFormatInfo (image_info->id, &fmt_type, &pixelformat, &memory))
390         {
391                 xf86DrvMsg (0, X_ERROR, "ID(%c%c%c%c) is not in 'format_infos'.\n",
392                             image_info->id & 0xFF, (image_info->id & 0xFF00) >> 8,
393                             (image_info->id & 0xFF0000) >> 16,  (image_info->id & 0xFF000000) >> 24);
394                 return BadRequest;
395         }
396
397         if (memory == V4L2_MEMORY_USERPTR)
398         {
399                 int ret;
400                 if ((ret = _fbdevVideoParseFormatBuffer (buf, phy_addrs)) < 0)
401                 {
402                         if (ret == XV_HEADER_ERROR)
403                                 xf86DrvMsg (0, X_ERROR, "XV_HEADER_ERROR\n");
404                         else if (ret == XV_VERSION_MISMATCH)
405                                 xf86DrvMsg (0, X_ERROR, "XV_VERSION_MISMATCH\n");
406
407                         return BadRequest;
408                 }
409
410                 /* Skip frame */
411                 if (phy_addrs[0] == 0)
412                         return Success;
413         }
414
415         if (!pPortPriv->v4l2_handle)
416         {
417                 pPortPriv->v4l2_handle = fbdevVideoV4l2OpenHandle (pScrnInfo->pScreen, v4l2_index, REQ_BUF_NUM);
418                 if (!pPortPriv->v4l2_handle)
419                 {
420                         int other_index = (v4l2_index == 0) ? 1 : 0;
421                         if (fbdevVideoV4l2HandleOpened (other_index))
422                         {
423                                 xf86DrvMsg (0, X_ERROR, "fbdevVideoV4l2OpenHandle failed. no empty.\n");
424                                 return BadRequest;
425                         }
426                         else
427                         {
428                                 pPortPriv->v4l2_handle = fbdevVideoV4l2OpenHandle (pScrnInfo->pScreen, other_index, REQ_BUF_NUM);
429                                 if (!pPortPriv->v4l2_handle)
430                                 {
431                                         xf86DrvMsg (0, X_ERROR, "fbdevVideoV4l2OpenHandle failed. fail open.\n");
432                                         return BadRequest;
433                                 }
434                         }
435
436                         v4l2_index = other_index;
437                 }
438
439                 pFBDev->v4l2_owner[v4l2_index] = (void*)pPortPriv;
440                 pPortPriv->v4l2_index = v4l2_index;
441         }
442
443         if (!fbdevVideoV4l2CheckSize (pPortPriv->v4l2_handle, pixelformat, img, src, dst, fmt_type, V4L2_MEMORY_MMAP))
444                 return BadRequest;
445
446         if (fbdevVideoV4l2SetFormat (pPortPriv->v4l2_handle, img, src, dst,
447                                      image_info->id, scn_rotate, hw_rotate,
448                                      pPortPriv->hflip, pPortPriv->vflip,
449                                      REQ_BUF_NUM, FALSE))
450         {
451                 fbdevVideoV4l2Draw (pPortPriv->v4l2_handle, buf, phy_addrs);
452
453                 if (modeBefore == PORT_MODE_WAITING)
454                         pScrnInfo->pScreen->WindowExposures ((WindowPtr) pDraw, clip_boxes, NULL);
455
456 #if ENABLE_ARM
457                 /* update cliplist */
458                 if (!REGION_EQUAL (pScrnInfo->pScreen, &pPortPriv->clip, clip_boxes))
459                 {
460                         /* setting transparency length to 8 */
461                         if (!pFBDev->bFbAlphaEnabled)
462                         {
463                                 fbdevFbScreenAlphaInit (fbdevHWGetFD (pScrnInfo));
464                                 pFBDev->bFbAlphaEnabled = TRUE;
465                         }
466                 }
467 #endif
468
469                 return Success;
470         }
471
472         _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
473
474         pPortPriv->mode = PORT_MODE_WAITING;
475
476         return Success;
477 }
478
479 static int
480 _fbdevVideoPutImageOnDrawable (ScrnInfoPtr pScrnInfo,
481                                FBDevPortPrivPtr pPortPriv,
482                                xRectangle *img,
483                                xRectangle *src,
484                                xRectangle *dst,
485                                RegionPtr   clip_boxes,
486                                int scn_rotate,
487                                int rotate,
488                                XF86ImageRec *image_info,
489                                uchar *buf,
490                                DrawablePtr pDraw)
491 {
492         pixman_format_code_t src_format, dst_format;
493         xRectangle pxm = {0,};
494
495         PixmapPtr pPixmap = _fbdevVideoGetPixmap (pDraw);
496
497         pxm.width = pPixmap->drawable.width;
498         pxm.height = pPixmap->drawable.height;
499
500         switch (image_info->id)
501         {
502         case FOURCC_I420:
503         case FOURCC_YV12:
504                 src_format = PIXMAN_yv12;
505                 break;
506         case FOURCC_YUY2:
507                 src_format = PIXMAN_yuy2;
508                 break;
509         case FOURCC_RGB565:
510                 src_format = PIXMAN_r5g6b5;
511                 break;
512         case FOURCC_RGB32:
513                 src_format = PIXMAN_a8r8g8b8;
514                 break;
515         default:
516                 return FALSE;
517         }
518
519         switch (image_info->id)
520         {
521         case FOURCC_I420:
522                 dst_format = PIXMAN_x8b8g8r8;
523                 break;
524         default:
525                 dst_format = PIXMAN_x8r8g8b8;
526                 break;
527         }
528
529         /* support only RGB  */
530         fbdev_pixman_convert_image (PIXMAN_OP_SRC,
531                                     buf, pPixmap->devPrivate.ptr,
532                                     src_format, dst_format,
533                                     img, &pxm, src, dst,
534                                     NULL, rotate,
535                                     pPortPriv->hflip, pPortPriv->vflip);
536
537     DamageDamageRegion (pDraw, clip_boxes);
538
539         return Success;
540 }
541
542 static Bool
543 _fbdevVideoSetHWPortsProperty (ScreenPtr pScreen, int nums)
544 {
545         WindowPtr pWin = pScreen->root;
546         Atom atom_hw_ports;
547
548         if (!pWin || !serverClient)
549                 return FALSE;
550
551         atom_hw_ports = MakeAtom ("X_HW_PORTS", strlen ("X_HW_PORTS"), TRUE);
552
553         dixChangeWindowProperty (serverClient,
554                                  pWin, atom_hw_ports, XA_CARDINAL, 32,
555                                  PropModeReplace, 1, (unsigned int*)&nums, FALSE);
556
557         return TRUE;
558 }
559
560 static void
561 _fbdevVideoDPMSHandler(CallbackListPtr *list, pointer closure, pointer calldata)
562 {
563         FBDevDPMSPtr pDPMSInfo = (FBDevDPMSPtr) calldata;
564
565         if(!pDPMSInfo || !pDPMSInfo->pScrn)
566         {
567                 xf86DrvMsg (0, X_ERROR, "[%s] DPMS info or screen info is invalid !\n", __FUNCTION__);
568                 return;
569         }
570
571         switch(DPMSPowerLevel)
572         {
573         case DPMSModeOn:
574                 break;
575
576         case DPMSModeSuspend:
577                 break;
578
579         case DPMSModeStandby://LCD on
580         {
581                 ScrnInfoPtr pScrnInfo = pDPMSInfo->pScrn;
582                 FBDevPtr pFBDev = FBDEVPTR (pScrnInfo);
583                 XF86VideoAdaptorPtr pAdaptor = pFBDev->pAdaptor[0];
584                 int i;
585
586                 DRVLOG ("%s : DPMSModeStandby \n", __FUNCTION__);
587
588                 for (i = 0; i < FBDEV_MAX_PORT; i++)
589                 {
590                         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pAdaptor->pPortPrivates[i].ptr;
591                         if (!pPortPriv->v4l2_handle || !pPortPriv->need_streamon)
592                                 continue;
593
594                         if (!fbdevVideoV4l2StreamOn (pPortPriv->v4l2_handle))
595                         {
596                                 /* will re-open if failed */
597                                 _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
598                                 pPortPriv->v4l2_handle = NULL;
599                         }
600                         pPortPriv->need_streamon = FALSE;
601                 }
602                 break;
603         }
604         case DPMSModeOff://LCD off
605         {
606                 ScrnInfoPtr pScrnInfo = pDPMSInfo->pScrn;
607                 FBDevPtr pFBDev = FBDEVPTR (pScrnInfo);
608                 XF86VideoAdaptorPtr pAdaptor = pFBDev->pAdaptor[0];
609                 int i;
610
611                 DRVLOG ("%s : DPMSModeOff \n", __FUNCTION__);
612
613                 for (i = 0; i < FBDEV_MAX_PORT; i++)
614                 {
615                         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pAdaptor->pPortPrivates[i].ptr;
616                         if (!pPortPriv->v4l2_handle || pPortPriv->need_streamon)
617                                 continue;
618
619                         fbdevVideoV4l2StreamOff (pPortPriv->v4l2_handle);
620                         pPortPriv->need_streamon = TRUE;
621                 }
622
623                 break;
624         }
625         default:
626                 return;
627         }
628 }
629
630 static void
631 _fbdevVideoBlockHandler (pointer data, OSTimePtr pTimeout, pointer pRead)
632 {
633         ScrnInfoPtr pScrnInfo = (ScrnInfoPtr)data;
634         FBDevPtr pFBDev = FBDEVPTR (pScrnInfo);
635         ScreenPtr pScreen = pScrnInfo->pScreen;
636
637         if(registered_handler && _fbdevVideoSetHWPortsProperty (pScreen, pFBDev->v4l2_num))
638         {
639                 RemoveBlockAndWakeupHandlers(_fbdevVideoBlockHandler, (WakeupHandlerProcPtr)NoopDDA, data);
640                 registered_handler = FALSE;
641         }
642 }
643
644 static int
645 FBDevVideoGetPortAttribute (ScrnInfoPtr pScrnInfo,
646                             Atom        attribute,
647                             INT32      *value,
648                             pointer     data)
649 {
650         DRVLOG ("[GetPortAttribute] \n");
651
652         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) data;
653
654         if (attribute == _fbdevVideoGetPortAtom (PAA_ROTATION))
655         {
656                 *value = pPortPriv->rotate;
657                 return Success;
658         }
659         else if (attribute == _fbdevVideoGetPortAtom (PAA_HFLIP))
660         {
661                 *value = pPortPriv->hflip;
662                 return Success;
663         }
664         else if (attribute == _fbdevVideoGetPortAtom (PAA_VFLIP))
665         {
666                 *value = pPortPriv->vflip;
667                 return Success;
668         }
669         else if (attribute == _fbdevVideoGetPortAtom (PAA_PREEMPTION))
670         {
671                 *value = pPortPriv->preemption;
672                 return Success;
673         }
674         else if (attribute == _fbdevVideoGetPortAtom (PAA_DRAWINGMODE))
675         {
676                 *value = (pPortPriv->mode == PORT_MODE_WAITING);
677                 return Success;
678         }
679         return BadMatch;
680 }
681
682 static int
683 FBDevVideoSetPortAttribute (ScrnInfoPtr pScrnInfo,
684                             Atom        attribute,
685                             INT32       value,
686                             pointer     data)
687 {
688         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) data;
689
690         if (attribute == _fbdevVideoGetPortAtom (PAA_ROTATION))
691         {
692                 pPortPriv->rotate = value;
693                 DRVLOG ("[SetPortAttribute] rotate(%d) \n", value);
694                 return Success;
695         }
696         else if (attribute == _fbdevVideoGetPortAtom (PAA_HFLIP))
697         {
698                 pPortPriv->hflip = value;
699                 DRVLOG ("[SetPortAttribute] hflip(%d) \n", value);
700                 return Success;
701         }
702         else if (attribute == _fbdevVideoGetPortAtom (PAA_VFLIP))
703         {
704                 pPortPriv->vflip = value;
705                 DRVLOG ("[SetPortAttribute] vflip(%d) \n", value);
706                 return Success;
707         }
708         else if (attribute == _fbdevVideoGetPortAtom (PAA_PREEMPTION))
709         {
710                 pPortPriv->preemption = value;
711                 DRVLOG ("[SetPortAttribute] preemption(%d) \n", value);
712                 return Success;
713         }
714         else if (attribute == _fbdevVideoGetPortAtom (PAA_STREAMOFF))
715         {
716                 DRVLOG ("[SetPortAttribute] STREAMOFF \n");
717                 _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
718                 return Success;
719         }
720         return BadMatch;
721 }
722
723 static void
724 FBDevVideoQueryBestSize (ScrnInfoPtr pScrnInfo,
725                          Bool motion,
726                          short vid_w, short vid_h,
727                          short dst_w, short dst_h,
728                          uint *p_w, uint *p_h,
729                          pointer data)
730 {
731         DRVLOG ("%s (%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);
732
733         *p_w = dst_w;
734         *p_h = dst_h;
735 }
736
737 static void
738 FBDevVideoStop (ScrnInfoPtr pScrnInfo, pointer data, Bool exit)
739 {
740         DRVLOG ("%s (%s:%d) exit(%d)\n", __FUNCTION__, __FILE__, __LINE__, exit);
741
742         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) data;
743
744         if (pPortPriv->mode == PORT_MODE_V4L2)
745         {
746                 _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
747
748 #if ENABLE_ARM
749                 FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
750
751                 if (pFBDev->bFbAlphaEnabled)
752                 {
753                         fbdevFbScreenAlphaDeinit (fbdevHWGetFD (pScrnInfo));
754                         pFBDev->bFbAlphaEnabled = FALSE;
755                 }
756 #endif
757         }
758
759         pPortPriv->mode = PORT_MODE_INIT;
760         pPortPriv->preemption = 0;
761         pPortPriv->rotate = -1;
762         pPortPriv->need_streamon = FALSE;
763
764         if (exit)
765                 REGION_EMPTY (pScrnInfo, &pPortPriv->clip);
766 }
767
768 static int
769 FBDevVideoReputImage (ScrnInfoPtr pScrn, short src_x, short src_y,
770                                   short drw_x, short drw_y, short src_w,
771                                   short src_h, short drw_w, short drw_h,
772                                   RegionPtr clipBoxes, pointer data,
773                                   DrawablePtr pDraw)
774
775 {
776         return Success;
777 }
778
779 int
780 fbdevVideoQueryImageAttributes (ScrnInfoPtr    pScrnInfo,
781                                 int            id,
782                                 unsigned short *w,
783                                 unsigned short *h,
784                                 int            *pitches,
785                                 int            *offsets)
786 {
787         int size = 0, tmp = 0;
788
789         *w = (*w + 1) & ~1;
790         if (offsets)
791                 offsets[0] = 0;
792
793         switch (id)
794         {
795         case FOURCC_RGB565:
796                 size += (*w << 1);
797                 if (pitches)
798                         pitches[0] = size;
799                 size *= *h;
800                 break;
801         case FOURCC_RGB24:
802                 size += (*w << 1) + *w;
803                 if (pitches)
804                         pitches[0] = size;
805                 size *= *h;
806                 break;
807         case FOURCC_RGB32:
808                 size += (*w << 2);
809                 if (pitches)
810                         pitches[0] = size;
811                 size *= *h;
812                 break;
813         case FOURCC_I420:
814         case FOURCC_S420:
815         case FOURCC_YV12:
816                 *h = (*h + 1) & ~1;
817                 size = (*w + 3) & ~3;
818                 if (pitches)
819                         pitches[0] = size;
820
821                 size *= *h;
822                 if (offsets)
823                         offsets[1] = size;
824
825                 tmp = ((*w >> 1) + 3) & ~3;
826                 if (pitches)
827                         pitches[1] = pitches[2] = tmp;
828
829                 tmp *= (*h >> 1);
830                 size += tmp;
831                 if (offsets)
832                         offsets[2] = size;
833
834                 size += tmp;
835                 break;
836         case FOURCC_UYVY:
837         case FOURCC_SUYV:
838         case FOURCC_YUY2:
839         case FOURCC_ST12:
840         case FOURCC_SN12:
841                 size = *w << 1;
842                 if (pitches)
843                         pitches[0] = size;
844
845                 size *= *h;
846                 break;
847         case FOURCC_NV12:
848                 size = *w;
849                 if (pitches)
850                         pitches[0] = size;
851
852                 size *= *h;
853                 if (offsets)
854                         offsets[1] = size;
855
856                 tmp = *w;
857                 if (pitches)
858                         pitches[1] = tmp;
859
860                 tmp *= (*h >> 1);
861                 size += tmp;
862                 break;
863         default:
864                 return BadIDChoice;
865         }
866
867         return size;
868 }
869
870 static int
871 FBDevVideoPutImage (ScrnInfoPtr pScrnInfo,
872                     short src_x, short src_y, short dst_x, short dst_y,
873                     short src_w, short src_h, short dst_w, short dst_h,
874                     int id,
875                     uchar *buf,
876                     short width, short height,
877                     Bool sync,
878                     RegionPtr clip_boxes,
879                     pointer data,
880                     DrawablePtr pDraw)
881 {
882         ScreenPtr pScreen = pScrnInfo->pScreen;
883         FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) data;
884         XF86ImageRec *image_info;
885         FBDevPortMode modeBefore = pPortPriv->mode;
886         xRectangle img = {0, 0, width, height};
887         xRectangle src = {src_x, src_y, src_w, src_h};
888         xRectangle dst = {dst_x, dst_y, dst_w, dst_h};
889         int scn_rotate, rotate, hw_rotate;
890         int v4l2_index = 0;
891         FBDevPtr pFBDev = FBDEVPTR (pScrnInfo);
892         int drawing;
893
894         if (pFBDev->isLcdOff)
895                 return Success;
896
897         pPortPriv->pDraw = pDraw;
898         drawing = _fbdevVideodrawingOn (pPortPriv, pDraw);
899
900         image_info = _fbdevVideoGetImageInfo (id);
901         if (!image_info)
902         {
903                 xf86DrvMsg (0, X_ERROR, "ID(%c%c%c%c) not supported.\n",
904                             id & 0xFF, (id & 0xFF00) >> 8,
905                             (id & 0xFF0000) >> 16,  (id & 0xFF000000) >> 24);
906                 return BadRequest;
907         }
908
909         _fbdevVideoGetRotation (pScreen, pPortPriv, pDraw, &scn_rotate, &rotate, &hw_rotate);
910
911         DRVLOG ("[PutImage] buf(%p) ID(%c%c%c%c) mode(%s) preem(%d) handle(%p) rot(%d+%d=%d) res(%dx%d) drawing(%d)\n",
912                 buf, id & 0xFF, (id & 0xFF00) >> 8, (id & 0xFF0000) >> 16,  (id & 0xFF000000) >> 24,
913                 pPortPriv->mode == PORT_MODE_WAITING ? "waiting" : "V4L2",
914                 pPortPriv->preemption,
915                 pPortPriv->v4l2_handle,
916                 scn_rotate, rotate, hw_rotate,
917                 pScreen->width, pScreen->height, drawing);
918
919         DRVLOG ("[PutImage] \t   img(%d,%d %dx%d) src(%d,%d %dx%d) dst(%d,%d %dx%d) \n",
920                 img.x, img.y, img.width, img.height,
921                 src.x, src.y, src.width, src.height,
922                 dst.x, dst.y, dst.width, dst.height);
923
924         _fbdevVideoInterfbdevtXRects (&src, &src, &img);
925
926         DRVLOG ("[PutImage] \t=> img(%d,%d %dx%d) src(%d,%d %dx%d) dst(%d,%d %dx%d) \n",
927                 img.x, img.y, img.width, img.height,
928                 src.x, src.y, src.width, src.height,
929                 dst.x, dst.y, dst.width, dst.height);
930
931         if (drawing == ON_PIXMAP || drawing == ON_WINDOW)
932                 return _fbdevVideoPutImageOnDrawable (pScrnInfo, pPortPriv, &img, &src, &dst, clip_boxes,
933                                                       scn_rotate, hw_rotate, image_info, buf, pDraw);
934
935         if (pPortPriv->need_streamon && pPortPriv->v4l2_handle)
936         {
937                 _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
938                 pPortPriv->need_streamon = FALSE;
939                 pPortPriv->v4l2_handle = NULL;
940         }
941
942         if (!pPortPriv->v4l2_handle)
943                 if (!_fbdevVideoSetMode (pScrnInfo, pPortPriv, &v4l2_index))
944                         return BadRequest;
945
946         if (pPortPriv->mode != PORT_MODE_V4L2)
947                 return Success;
948
949         return _fbdevVideoPutImageV4l2 (pScrnInfo, pPortPriv, &img, &src, &dst, clip_boxes,
950                                         scn_rotate, rotate, hw_rotate,
951                                         image_info, buf, modeBefore, v4l2_index, pDraw);
952 }
953
954 /**
955  * Set up all our internal structures.
956  */
957 static XF86VideoAdaptorPtr
958 fbdevVideoSetupImageVideo (ScreenPtr pScreen)
959 {
960         DRVLOG ("%s (%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);
961
962         XF86VideoAdaptorPtr pAdaptor;
963         FBDevPortPrivPtr pPortPriv;
964         XF86ImagePtr pImages;
965         int i, count = 0;
966
967         pAdaptor = calloc (1, sizeof (XF86VideoAdaptorRec) +
968                            (sizeof (DevUnion) + sizeof (FBDevPortPriv)) * FBDEV_MAX_PORT);
969         if (pAdaptor == NULL)
970                 return NULL;
971
972         DummyEncoding[0].width = pScreen->width;
973         DummyEncoding[0].height = pScreen->height;
974
975         pAdaptor->type = XvWindowMask | XvPixmapMask | XvInputMask | XvImageMask;
976         pAdaptor->flags = (VIDEO_CLIP_TO_VIEWPORT | VIDEO_OVERLAID_IMAGES);
977         pAdaptor->name = "FBDEV supporting Software Video Conversions";
978         pAdaptor->nEncodings = sizeof (DummyEncoding) / sizeof (XF86VideoEncodingRec);
979         pAdaptor->pEncodings = DummyEncoding;
980         pAdaptor->nFormats = NUM_FORMATS;
981         pAdaptor->pFormats = Formats;
982         pAdaptor->nPorts = FBDEV_MAX_PORT;
983         pAdaptor->pPortPrivates = (DevUnion*)(&pAdaptor[1]);
984
985         pPortPriv =
986             (FBDevPortPrivPtr) (&pAdaptor->pPortPrivates[FBDEV_MAX_PORT]);
987
988         for (i=0; i<FBDEV_MAX_PORT; i++)
989         {
990                 pAdaptor->pPortPrivates[i].ptr = &pPortPriv[i];
991
992                 pPortPriv[i].index = i;
993                 pPortPriv[i].rotate = -1;
994                 pPortPriv[i].v4l2_index = -1;
995
996                 REGION_INIT (pScreen, &pPortPriv[i].clipBoxes, NullBox, 0);
997         }
998
999         pImages = fbdevVideoV4l2SupportImages (&count);
1000
1001         pAdaptor->nAttributes = NUM_ATTRIBUTES;
1002         pAdaptor->pAttributes = Attributes;
1003         pAdaptor->nImages = count;
1004         pAdaptor->pImages = pImages;
1005
1006         pAdaptor->PutImage             = FBDevVideoPutImage;
1007         pAdaptor->ReputImage           = FBDevVideoReputImage;
1008         pAdaptor->StopVideo            = FBDevVideoStop;
1009         pAdaptor->GetPortAttribute     = FBDevVideoGetPortAttribute;
1010         pAdaptor->SetPortAttribute     = FBDevVideoSetPortAttribute;
1011         pAdaptor->QueryBestSize        = FBDevVideoQueryBestSize;
1012         pAdaptor->QueryImageAttributes = fbdevVideoQueryImageAttributes;
1013
1014         return pAdaptor;
1015 }
1016
1017 #ifdef XV
1018 /**
1019  * Set up everything we need for Xv.
1020  */
1021 Bool fbdevVideoInit (ScreenPtr pScreen)
1022 {
1023         DRVLOG ("%s (%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);
1024
1025         ScrnInfoPtr pScrnInfo = xf86Screens[pScreen->myNum];
1026         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
1027
1028         pFBDev->pAdaptor[0] = fbdevVideoSetupImageVideo (pScreen);
1029         if (!pFBDev->pAdaptor[0])
1030                 return FALSE;
1031
1032         pFBDev->pAdaptor[1] = fbdevVideoSetupVirtualVideo (pScreen);
1033         if (!pFBDev->pAdaptor[1])
1034         {
1035                 free (pFBDev->pAdaptor[0]);
1036                 return FALSE;
1037         }
1038
1039         xf86XVScreenInit (pScreen, pFBDev->pAdaptor, ADAPTOR_NUM);
1040
1041         pFBDev->v4l2_num   = fbdevVideoV4l2GetHandleNums ();
1042         pFBDev->v4l2_owner = (void**)calloc (sizeof (void*), pFBDev->v4l2_num);
1043
1044         if(registered_handler == FALSE)
1045         {
1046                 RegisterBlockAndWakeupHandlers(_fbdevVideoBlockHandler, (WakeupHandlerProcPtr)NoopDDA, pScrnInfo);
1047                 registered_handler = TRUE;
1048         }
1049
1050         if (AddCallback (&DPMSCallback, _fbdevVideoDPMSHandler, NULL) != TRUE)
1051         {
1052                 xf86DrvMsg (pScrnInfo->scrnIndex, X_ERROR, "Failed to register _fbdevVideoDPMSHandler. \n");
1053                 return FALSE;
1054         }
1055
1056         return TRUE;
1057 }
1058
1059 /**
1060  * Shut down Xv, used on regeneration.
1061  */
1062 void fbdevVideoFini (ScreenPtr pScreen)
1063 {
1064         DRVLOG ("%s (%s:%d)\n", __FUNCTION__, __FILE__, __LINE__);
1065
1066         ScrnInfoPtr pScrnInfo = xf86Screens[pScreen->myNum];
1067         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
1068
1069         XF86VideoAdaptorPtr pAdaptor = pFBDev->pAdaptor[0];
1070         int i;
1071
1072         if (!pAdaptor)
1073                 return;
1074
1075         DeleteCallback (&DPMSCallback, _fbdevVideoDPMSHandler, NULL);
1076
1077         for (i = 0; i < FBDEV_MAX_PORT; i++)
1078         {
1079                 FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pAdaptor->pPortPrivates[i].ptr;
1080
1081                 REGION_UNINIT (pScreen, &pPortPriv->clipBoxes);
1082
1083                 _fbdevVideoCloseV4l2Handle (pScrnInfo, pPortPriv);
1084         }
1085
1086         free (pFBDev->pAdaptor[0]);
1087         pFBDev->pAdaptor[0] = NULL;
1088
1089         free (pFBDev->pAdaptor[1]);
1090         pFBDev->pAdaptor[1] = NULL;
1091
1092         if (pFBDev->v4l2_owner)
1093         {
1094                 free (pFBDev->v4l2_owner);
1095                 pFBDev->v4l2_owner = NULL;
1096                 pFBDev->v4l2_num = 0;
1097         }
1098 }
1099
1100 #endif
1101
1102 void
1103 fbdevVideoSetOffset (ScrnInfoPtr pScrnInfo, int x, int y)
1104 {
1105         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
1106         int i;
1107         for (i = 0; i < pFBDev->v4l2_num; i++)
1108         {
1109                 FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pFBDev->v4l2_owner[i];
1110
1111                 if (pPortPriv)
1112                 {
1113                         if (!pPortPriv->v4l2_handle)
1114                                 continue;
1115
1116                         fbdevVideoV4l2VideoOffset (pPortPriv->v4l2_handle, x , y);
1117                 }
1118         }
1119 }
1120
1121 void
1122 fbdevVideoGetV4l2Handles (ScrnInfoPtr pScrnInfo, void ***handles, int *cnt)
1123 {
1124         FBDevPtr pFBDev = (FBDevPtr) pScrnInfo->driverPrivate;
1125         void **ret;
1126         int i, j;
1127
1128         *cnt = 0;
1129
1130         for (i = 0; i < pFBDev->v4l2_num; i++)
1131         {
1132                 FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pFBDev->v4l2_owner[i];
1133                 if (pPortPriv && pPortPriv->v4l2_handle)
1134                         (*cnt)++;
1135         }
1136
1137         if (*cnt == 0)
1138         {
1139                 *handles = NULL;
1140                 return;
1141         }
1142
1143         ret = (void**)calloc (*cnt, sizeof (void*));
1144         *handles = ret;
1145
1146         j = 0;
1147
1148         for (i = 0; i < pFBDev->v4l2_num; i++)
1149         {
1150                 FBDevPortPrivPtr pPortPriv = (FBDevPortPrivPtr) pFBDev->v4l2_owner[i];
1151                 if (pPortPriv && pPortPriv->v4l2_handle)
1152                 {
1153                         ret[j] = pPortPriv->v4l2_handle;
1154                         j++;
1155                 }
1156         }
1157 }