15ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson"""
25ff4624633a375231c052b38510f279c9f2bbc28Corbin SimpsonA wrapper around the Direct Rendering Manager (DRM) library, which itself is a
35ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonwrapper around the Direct Rendering Interface (DRI) between the kernel and
45ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonuserland.
55ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
65ff4624633a375231c052b38510f279c9f2bbc28Corbin SimpsonSince we are masochists, we use ctypes instead of cffi to load libdrm and
75ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonaccess several symbols within it. We use Python's file descriptor and mmap
85ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonwrappers.
95ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
105ff4624633a375231c052b38510f279c9f2bbc28Corbin SimpsonAt some point in the future, cffi could be used, for approximately the same
115ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsoncost in lines of code.
125ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson"""
135ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
145ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonfrom ctypes import *
155ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonimport mmap
165ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonimport os
175f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedelimport subprocess
185ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
19c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr# drmModeConnection enum
20c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTED         = 1
21c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_DISCONNECTED      = 2
22c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_UNKNOWNCONNECTION = 3
23c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
24c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_Unknown     = 0
25c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_VGA         = 1
26c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_DVII        = 2
27c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_DVID        = 3
28c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_DVIA        = 4
29c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_Composite   = 5
30c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_SVIDEO      = 6
31c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_LVDS        = 7
32c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_Component   = 8
33c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_9PinDIN     = 9
34c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_DisplayPort = 10
35c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_HDMIA       = 11
36c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_HDMIB       = 12
37c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_TV          = 13
38c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_eDP         = 14
39c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_VIRTUAL     = 15
40c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik BehrDRM_MODE_CONNECTOR_DSI         = 16
41c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
42557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# This constant is not defined in any one header; it is the pieced-together
43557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# incantation for the ioctl that performs dumb mappings. I would love for this
44557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# to not have to be here, but it can't be imported from any header easily.
45557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe KnissDRM_IOCTL_MODE_MAP_DUMB = 0xc01064b3
46557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss
47557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# This define should be equal to O_CLOEXEC, which should be available in
48557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# python's os module, but isn't until version 3.3.  If we version up, we can
49557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss# set this to os.O_CLOEXEC.
50557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe KnissDRM_CLOEXEC = 02000000
51557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss
525ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
535ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass DrmVersion(Structure):
545ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
555ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    The version of a DRM node.
565ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
575ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
585ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fields_ = [
595ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("version_major", c_int),
605ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("version_minor", c_int),
615ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("version_patchlevel", c_int),
625ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("name_len", c_int),
635ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("name", c_char_p),
645ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("date_len", c_int),
655ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("date", c_char_p),
665ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("desc_len", c_int),
675ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("desc", c_char_p),
685ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    ]
695ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
705ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _l = None
715ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
725ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __repr__(self):
735f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        return "%s %d.%d.%d (%s) (%s)" % (self.name,
745f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                                          self.version_major,
755f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                                          self.version_minor,
765f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                                          self.version_patchlevel,
775f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                                          self.desc,
785f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                                          self.date,)
795ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
805ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __del__(self):
815ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._l:
825ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._l.drmFreeVersion(self)
835ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
845ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
855ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass DrmModeResources(Structure):
865ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
875ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    Resources associated with setting modes on a DRM node.
885ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
895ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
905ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fields_ = [
915ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("count_fbs", c_int),
925ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("fbs", POINTER(c_uint)),
935ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("count_crtcs", c_int),
945ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("crtcs", POINTER(c_uint)),
95d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("count_connectors", c_int),
96d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("connectors", POINTER(c_uint)),
97d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("count_encoders", c_int),
98d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("encoders", POINTER(c_uint)),
99d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("min_width", c_int),
100d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("max_width", c_int),
101d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("min_height", c_int),
102d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("max_height", c_int),
1035ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    ]
1045ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1055ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fd = None
1065ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _l = None
1075ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1085ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __repr__(self):
1095ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return "<DRM mode resources>"
1105ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1115ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __del__(self):
1125ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._l:
1135ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._l.drmModeFreeResources(self)
1145ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1155f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel    def _wakeup_screen(self):
1165f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        """
1175f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        Send a synchronous dbus message to power on screen.
1185f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        """
1195f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        # Get and process reply to make this synchronous.
1205f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        subprocess.check_output([
1215f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            "dbus-send", "--type=method_call", "--system", "--print-reply",
1225f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            "--dest=org.chromium.PowerManager", "/org/chromium/PowerManager",
1235f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            "org.chromium.PowerManager.HandleUserActivity", "int32:0"
1245f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        ])
1255f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel
126d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel    def getValidCrtc(self):
127d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        for i in xrange(0, self.count_crtcs):
128d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel            crtc_id = self.crtcs[i]
129d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel            crtc = self._l.drmModeGetCrtc(self._fd, crtc_id).contents
130d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel            if crtc.mode_valid:
131d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel                return crtc
132d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        return None
133d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel
1345f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel    def getCrtc(self, crtc_id):
1355ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
1365ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Obtain the CRTC at a given index.
1375ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
138c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang        @param crtc_id: The CRTC to get.
1395ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
140d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        if crtc_id:
1415f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            return self._l.drmModeGetCrtc(self._fd, crtc_id).contents
1425f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        return self.getValidCrtc()
1435f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel
1445f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel    def getCrtcRobust(self, crtc_id=None):
1455f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        crtc = self.getCrtc(crtc_id)
1465f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        if crtc is None:
1475f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            self._wakeup_screen()
1485f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            crtc = self.getCrtc(crtc_id)
1495f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        if crtc is not None:
1505f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            crtc._fd = self._fd
1515f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel            crtc._l = self._l
1525ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return crtc
1535ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1545ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
155c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behrclass DrmModeModeInfo(Structure):
156c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
157c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    A DRM modesetting mode info.
158c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
159c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
160c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _fields_ = [
161c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("clock", c_uint),
162c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("hdisplay", c_ushort),
163c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("hsync_start", c_ushort),
164c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("hsync_end", c_ushort),
165c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("htotal", c_ushort),
166c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("hskew", c_ushort),
167c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vdisplay", c_ushort),
168c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vsync_start", c_ushort),
169c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vsync_end", c_ushort),
170c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vtotal", c_ushort),
171c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vscan", c_ushort),
172c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("vrefresh", c_uint),
173c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("flags", c_uint),
174c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("type", c_uint),
175c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("name", c_char * 32),
176c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    ]
177c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
178c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
1795ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass DrmModeCrtc(Structure):
1805ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
1815ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    A DRM modesetting CRTC.
1825ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
1835ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1845ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fields_ = [
1855ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("crtc_id", c_uint),
1865ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("buffer_id", c_uint),
187d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("x", c_uint),
188d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("y", c_uint),
189d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("width", c_uint),
190d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("height", c_uint),
191d2c9f442b031fc47f6196b92bb96ecbbd796c10cIlja H. Friedel        ("mode_valid", c_int),
192c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("mode", DrmModeModeInfo),
193c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("gamma_size", c_int),
1945ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    ]
1955ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1965ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fd = None
1975ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _l = None
1985ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
1995ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __repr__(self):
2005ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return "<CRTC (%d)>" % self.crtc_id
2015ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2025ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __del__(self):
2035ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._l:
2045ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._l.drmModeFreeCrtc(self)
2055ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2065ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def hasFb(self):
2075ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
2085ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Whether this CRTC has an associated framebuffer.
2095ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
2105ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2115ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return self.buffer_id != 0
2125ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2135ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def fb(self):
2145ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
2155ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Obtain the framebuffer, if one is associated.
2165ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
2175ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2185ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self.hasFb():
2195ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            fb = self._l.drmModeGetFB(self._fd, self.buffer_id).contents
2205ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            fb._fd = self._fd
2215ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            fb._l = self._l
2225ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            return fb
223f2a4b9f6e2697ef7f6c82b7f276e9e102b61e62bCorbin Simpson        else:
224f2a4b9f6e2697ef7f6c82b7f276e9e102b61e62bCorbin Simpson            raise RuntimeError("CRTC %d doesn't have a framebuffer!" %
225d94feb65407b07bd2c17ffd94cfcace57f9d0650Ilja H. Friedel                               self.crtc_id)
2265ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2275ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
228c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behrclass DrmModeEncoder(Structure):
229c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
230c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    A DRM modesetting encoder.
231c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
232c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
233c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _fields_ = [
234c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("encoder_id", c_uint),
235c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("encoder_type", c_uint),
236c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("crtc_id", c_uint),
237c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("possible_crtcs", c_uint),
238c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("possible_clones", c_uint),
239c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    ]
240c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
241c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _fd = None
242c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _l = None
243c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
244c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def __repr__(self):
245c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return "<Encoder (%d)>" % self.encoder_id
246c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
247c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def __del__(self):
248c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if self._l:
249c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            self._l.drmModeFreeEncoder(self)
250c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
251c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
252c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behrclass DrmModeConnector(Structure):
253c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
254c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    A DRM modesetting connector.
255c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    """
256c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
257c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _fields_ = [
258c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("connector_id", c_uint),
259c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("encoder_id", c_uint),
260c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("connector_type", c_uint),
261c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("connector_type_id", c_uint),
262c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("connection", c_uint), # drmModeConnection enum
263c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("mmWidth", c_uint),
264c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("mmHeight", c_uint),
265c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("subpixel", c_uint), # drmModeSubPixel enum
266c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("count_modes", c_int),
267c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("modes", POINTER(DrmModeModeInfo)),
268c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("count_propts", c_int),
269c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("props", POINTER(c_uint)),
270c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("prop_values", POINTER(c_ulonglong)),
271c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("count_encoders", c_int),
272c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ("encoders", POINTER(c_uint)),
273c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    ]
274c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
275c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _fd = None
276c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    _l = None
277c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
278c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def __repr__(self):
279c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return "<Connector (%d)>" % self.connector_id
280c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
281c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def __del__(self):
282c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if self._l:
283c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            self._l.drmModeFreeConnector(self)
284c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
285c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def isInternal(self):
286c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return (self.connector_type == DRM_MODE_CONNECTOR_LVDS or
287c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                self.connector_type == DRM_MODE_CONNECTOR_eDP or
288c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                self.connector_type == DRM_MODE_CONNECTOR_DSI)
289c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
290c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def isConnected(self):
291c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return self.connection == DRM_MODE_CONNECTED
292c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
293c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
2945ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass drm_mode_map_dumb(Structure):
2955ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
2965ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    Request a mapping of a modesetting buffer.
2975ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
2985ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    The map will be "dumb;" it will be accessible via mmap() but very slow.
2995ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
3005ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3015ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fields_ = [
3025ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("handle", c_uint),
3035ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("pad", c_uint),
3045ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("offset", c_ulonglong),
3055ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    ]
3065ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3075ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3085ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass DrmModeFB(Structure):
3095ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
3105ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    A DRM modesetting framebuffer.
3115ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
3125ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3135ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _fields_ = [
3145ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("fb_id", c_uint),
3155ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("width", c_uint),
3165ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("height", c_uint),
3175ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("pitch", c_uint),
3185ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("bpp", c_uint),
3195ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("depth", c_uint),
3205ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        ("handle", c_uint),
3215ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    ]
3225ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3235ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _l = None
3245ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    _map = None
3255ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3265ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __repr__(self):
3275ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        s = "<Framebuffer (%dx%d (pitch %d bytes), %d bits/pixel, depth %d)"
3285f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        vitals = s % (self.width,
3295f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                      self.height,
3305f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                      self.pitch,
3315f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                      self.bpp,
3325f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                      self.depth,)
3335ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._map:
3345ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            tail = " (mapped)>"
3355ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        else:
3365ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            tail = ">"
3375ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return vitals + tail
3385ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3395ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __del__(self):
3405ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._l:
3415ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._l.drmModeFreeFB(self)
3425ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
343d0762edbad798a5203df727ddb9eab2d24fdc860Haixia Shi    def map(self, size):
3445ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
3455ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Map the framebuffer.
3465ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
3475ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3485ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._map:
3495ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            return
3505ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3515ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        mapDumb = drm_mode_map_dumb()
3525ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        mapDumb.handle = self.handle
3535ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3545ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        rv = self._l.drmIoctl(self._fd, DRM_IOCTL_MODE_MAP_DUMB,
355d94feb65407b07bd2c17ffd94cfcace57f9d0650Ilja H. Friedel                              pointer(mapDumb))
3565ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if rv:
3575ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            raise IOError(rv, os.strerror(rv))
3585ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3595ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        # mmap.mmap() has a totally different order of arguments in Python
3605ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        # compared to C; check the documentation before altering this
3615ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        # incantation.
3625f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel        self._map = mmap.mmap(self._fd,
3635f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                              size,
3645f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                              flags=mmap.MAP_SHARED,
3655f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                              prot=mmap.PROT_READ,
3665f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel                              offset=mapDumb.offset)
3675ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3685ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def unmap(self):
3695ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
3705ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Unmap the framebuffer.
3715ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
3725ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3735ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        if self._map:
3745ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._map.close()
3755ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson            self._map = None
3765ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
377557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    def getFD(self):
378557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        """
379557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        Convert handle to a FD.
380557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        """
381557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        prime_fd = c_int(0)
382557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        rv = self._l.drmPrimeHandleToFD(self._fd, self.handle,
383557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss                                        DRM_CLOEXEC, byref(prime_fd))
384557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        if rv:
385557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss            raise RuntimeError("Failed to convert FB handle to FD. %d" % rv)
386557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        return prime_fd
3875ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3885ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsondef loadDRM():
3895ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
3905ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    Load a handle to libdrm.
3915ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
3925ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    In addition to loading, this function also configures the argument and
3935ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    return types of functions.
3945ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
3955ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
396c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l = None
397c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
398c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    try:
399c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        l = cdll.LoadLibrary("libdrm.so")
400c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    except OSError:
401c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        l = cdll.LoadLibrary("libdrm.so.2") # ubuntu doesn't have libdrm.so
4025ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4035ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmGetVersion.argtypes = [c_int]
4045ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmGetVersion.restype = POINTER(DrmVersion)
4055ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4065ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmFreeVersion.argtypes = [POINTER(DrmVersion)]
4075ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmFreeVersion.restype = None
4085ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4095ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetResources.argtypes = [c_int]
4105ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetResources.restype = POINTER(DrmModeResources)
4115ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4125ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeResources.argtypes = [POINTER(DrmModeResources)]
4135ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeResources.restype = None
4145ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4155ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetCrtc.argtypes = [c_int, c_uint]
4165ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetCrtc.restype = POINTER(DrmModeCrtc)
4175ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4185ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeCrtc.argtypes = [POINTER(DrmModeCrtc)]
4195ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeCrtc.restype = None
4205ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
421c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeGetEncoder.argtypes = [c_int, c_uint]
422c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeGetEncoder.restype = POINTER(DrmModeEncoder)
423c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
424c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeFreeEncoder.argtypes = [POINTER(DrmModeEncoder)]
425c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeFreeEncoder.restype = None
426c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
427c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeGetConnector.argtypes = [c_int, c_uint]
428c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeGetConnector.restype = POINTER(DrmModeConnector)
429c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
430c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeFreeConnector.argtypes = [POINTER(DrmModeConnector)]
431c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    l.drmModeFreeConnector.restype = None
432c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
4335ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetFB.argtypes = [c_int, c_uint]
4345ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeGetFB.restype = POINTER(DrmModeFB)
4355ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4365ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeFB.argtypes = [POINTER(DrmModeFB)]
4375ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmModeFreeFB.restype = None
4385ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4395ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmIoctl.argtypes = [c_int, c_ulong, c_voidp]
4405ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    l.drmIoctl.restype = c_int
4415ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
442557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    l.drmPrimeHandleToFD.argtypes = [c_int, c_uint, c_uint, POINTER(c_int)]
443557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    l.drmPrimeHandleToFD.restype = c_int
444557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss
4455ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    return l
4465ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4475ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4485ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpsonclass DRM(object):
4495ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
4505ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    A DRM node.
4515ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
4525ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4535ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __init__(self, library, fd):
4545ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        self._l = library
4555ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        self._fd = fd
4565ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4575ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def __repr__(self):
4585ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return "<DRM (FD %d)>" % self._fd
4595ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4605ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    @classmethod
4615ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def fromHandle(cls, handle):
4625ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4635ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Create a node from a file handle.
4645ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4655ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        @param handle: A file-like object backed by a file descriptor.
4665ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4675ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4685ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        self = cls(loadDRM(), handle.fileno())
4695ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        # We must keep the handle alive, and we cannot trust the caller to
4705ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        # keep it alive for us.
4715ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        self._handle = handle
4725ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return self
4735ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4745ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def version(self):
4755ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4765ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Obtain the version.
4775ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4785ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4795ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        v = self._l.drmGetVersion(self._fd).contents
4805ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        v._l = self._l
4815ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        return v
4825ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
4835ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    def resources(self):
4845ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4855ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        Obtain the modesetting resources.
4865ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson        """
4875ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
488c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang        resources_ptr = self._l.drmModeGetResources(self._fd)
489c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang        if resources_ptr:
490c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang            r = resources_ptr.contents
491c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang            r._fd = self._fd
492c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang            r._l = self._l
493c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang            return r
494c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang
495c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang        return None
4965ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
497c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def getCrtc(self, crtc_id):
498c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        c_ptr = self._l.drmModeGetCrtc(self._fd, crtc_id)
499c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if c_ptr:
500c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c = c_ptr.contents
501c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c._fd = self._fd
502c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c._l = self._l
503c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            return c
504c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
505c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return None
506c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
507c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def getEncoder(self, encoder_id):
508c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        e_ptr = self._l.drmModeGetEncoder(self._fd, encoder_id)
509c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if e_ptr:
510c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            e = e_ptr.contents
511c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            e._fd = self._fd
512c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            e._l = self._l
513c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            return e
514c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
515c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return None
516c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
517c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr    def getConnector(self, connector_id):
518c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        c_ptr = self._l.drmModeGetConnector(self._fd, connector_id)
519c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if c_ptr:
520c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c = c_ptr.contents
521c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c._fd = self._fd
522c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            c._l = self._l
523c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            return c
524c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
525c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        return None
526c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
527c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
5285ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
529c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huangdef drmFromPath(path):
5305ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
531c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang    Given a DRM node path, open the corresponding node.
5325ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
533c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang    @param path: The path of the minor node to open.
5345ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
535557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    # Always open the device as RW (r+) so that mmap works later.
536557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    handle = open(path, "r+")
5375ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    return DRM.fromHandle(handle)
5385ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
5395ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson
540c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang_drm = None
541c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang
5425f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel
543557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Knissdef getCrtc(crtc_id=None):
5445ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
545557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    @param crtc_id: None for first found CRTC with mode set
546c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    or "internal" for crtc connected to internal LCD
547c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    or "external" for crtc connected to external display
548c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    or "usb" "evdi" or "udl" for crtc with valid mode on evdi or
549c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    udl display
550c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    or DRM integer crtc_id
5515ff4624633a375231c052b38510f279c9f2bbc28Corbin Simpson    """
552c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang    global _drm
553c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
554c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang    if not _drm:
555c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        paths = [
556c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            "/dev/dri/" + n
557c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            for n in filter(lambda x: x.startswith("card"),
558c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            os.listdir("/dev/dri"))
559c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        ]
560c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
561c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        if crtc_id == "usb" or crtc_id == "evdi" or crtc_id == "udl":
562c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            for p in paths:
563c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                d = drmFromPath(p)
564c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                v = d.version()
565c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
566c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if crtc_id == v.name:
567c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    _drm = d
568c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    break
569c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
570c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if crtc_id == "usb" and (v.name == "evdi" or v.name == "udl"):
571c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    _drm = d
572c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    break
573c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
574c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        elif crtc_id == "internal" or crtc_id == "external":
575c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            internal = crtc_id == "internal"
576c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            for p in paths:
577c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                d = drmFromPath(p)
578c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if d.resources() is None:
579c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    continue
580c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if d.resources() and d.resources().count_connectors > 0:
581c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    for c in xrange(0, d.resources().count_connectors):
582c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        connector = d.getConnector(d.resources().connectors[c])
583c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        if (internal == connector.isInternal()
584c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            and connector.isConnected()
585c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            and connector.encoder_id != 0):
586c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            e = d.getEncoder(connector.encoder_id)
587c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            crtc = d.getCrtc(e.crtc_id)
588c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                            if crtc.mode_valid:
589c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                                crtc_id = crtc.crtc_id
590c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                                _drm = d
591c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                                break
592c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if _drm:
593c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    break
594c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
595c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        elif crtc_id is None or crtc_id == 0:
596c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            for p in paths:
597c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                d = drmFromPath(p)
598c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if d.resources() is None:
599c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    continue
600c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                for c in xrange(0, d.resources().count_crtcs):
601c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    crtc = d.getCrtc(d.resources().crtcs[c])
602c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    if crtc.mode_valid:
603c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        crtc_id = d.resources().crtcs[c]
604c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        _drm = d
605c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        break
606c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if _drm:
607c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    break
608c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr
609c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr        else:
610c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr            for p in paths:
611c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                d = drmFromPath(p)
612c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if d.resources() is None:
613c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    continue
614c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                for c in xrange(0, d.resources().count_crtcs):
615c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    if crtc_id == d.resources().crtcs[c]:
616c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        _drm = d
617c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                        break
618c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                if _drm:
619c4d29ea43d5700dd9924e81d148384f5d63a09f1Dominik Behr                    break
620c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang
621c5c4cfb286ad25e89a9ab298c56d8e656b615fd0Yuli Huang    if _drm:
622557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss        return _drm.resources().getCrtcRobust(crtc_id)
6235f4922c627d9eb895f6fcf35e1e19b090a5894a8Ilja H. Friedel
624557946d18d625f8c14e0a1bf6a23d91b17d70f1dJoe Kniss    return None
625