Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2011 Intel Corporation
  4.  * Copyright 2012 Francisco Jerez
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22.  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  23.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  * Authors:
  28.  *    Kristian Høgsberg <krh@bitplanet.net>
  29.  *    Benjamin Franzke <benjaminfranzke@googlemail.com>
  30.  *
  31.  **************************************************************************/
  32.  
  33. #include <fcntl.h>
  34. #include <stdio.h>
  35. #include <libudev.h>
  36. #include <xf86drm.h>
  37.  
  38. #ifdef HAVE_PIPE_LOADER_XCB
  39.  
  40. #include <xcb/dri2.h>
  41.  
  42. #endif
  43.  
  44. #include "state_tracker/drm_driver.h"
  45. #include "pipe_loader_priv.h"
  46.  
  47. #include "util/u_memory.h"
  48. #include "util/u_dl.h"
  49. #include "util/u_debug.h"
  50.  
  51. #define DRIVER_MAP_GALLIUM_ONLY
  52. #include "pci_ids/pci_id_driver_map.h"
  53.  
  54. struct pipe_loader_drm_device {
  55.    struct pipe_loader_device base;
  56.    struct util_dl_library *lib;
  57.    int fd;
  58. };
  59.  
  60. #define pipe_loader_drm_device(dev) ((struct pipe_loader_drm_device *)dev)
  61.  
  62. static boolean
  63. find_drm_pci_id(struct pipe_loader_drm_device *ddev)
  64. {
  65.    struct udev *udev = NULL;
  66.    struct udev_device *parent, *device = NULL;
  67.    struct stat stat;
  68.    const char *pci_id;
  69.  
  70.    if (fstat(ddev->fd, &stat) < 0)
  71.       goto fail;
  72.  
  73.    udev = udev_new();
  74.    if (!udev)
  75.       goto fail;
  76.  
  77.    device = udev_device_new_from_devnum(udev, 'c', stat.st_rdev);
  78.    if (!device)
  79.       goto fail;
  80.  
  81.    parent = udev_device_get_parent(device);
  82.    if (!parent)
  83.       goto fail;
  84.  
  85.    pci_id = udev_device_get_property_value(parent, "PCI_ID");
  86.    if (!pci_id ||
  87.        sscanf(pci_id, "%x:%x", &ddev->base.u.pci.vendor_id,
  88.               &ddev->base.u.pci.chip_id) != 2)
  89.       goto fail;
  90.  
  91.    return TRUE;
  92.  
  93.   fail:
  94.    if (device)
  95.       udev_device_unref(device);
  96.    if (udev)
  97.       udev_unref(udev);
  98.  
  99.    return FALSE;
  100. }
  101.  
  102. static boolean
  103. find_drm_driver_name(struct pipe_loader_drm_device *ddev)
  104. {
  105.    struct pipe_loader_device *dev = &ddev->base;
  106.    int i, j;
  107.  
  108.    for (i = 0; driver_map[i].driver; i++) {
  109.       if (dev->u.pci.vendor_id != driver_map[i].vendor_id)
  110.          continue;
  111.  
  112.       if (driver_map[i].num_chips_ids == -1) {
  113.          dev->driver_name = driver_map[i].driver;
  114.          goto found;
  115.       }
  116.  
  117.       for (j = 0; j < driver_map[i].num_chips_ids; j++) {
  118.          if (dev->u.pci.chip_id == driver_map[i].chip_ids[j]) {
  119.             dev->driver_name = driver_map[i].driver;
  120.             goto found;
  121.          }
  122.       }
  123.    }
  124.  
  125.    return FALSE;
  126.  
  127.   found:
  128.    return TRUE;
  129. }
  130.  
  131. static struct pipe_loader_ops pipe_loader_drm_ops;
  132.  
  133. static void
  134. pipe_loader_drm_x_auth(int fd)
  135. {
  136. #if HAVE_PIPE_LOADER_XCB
  137.    /* Try authenticate with the X server to give us access to devices that X
  138.     * is running on. */
  139.    xcb_connection_t *xcb_conn;
  140.    const xcb_setup_t *xcb_setup;
  141.    xcb_screen_iterator_t s;
  142.    xcb_dri2_connect_cookie_t connect_cookie;
  143.    xcb_dri2_connect_reply_t *connect;
  144.    drm_magic_t magic;
  145.    xcb_dri2_authenticate_cookie_t authenticate_cookie;
  146.    xcb_dri2_authenticate_reply_t *authenticate;
  147.  
  148.    xcb_conn = xcb_connect(NULL,  NULL);
  149.  
  150.    if(!xcb_conn)
  151.       return;
  152.  
  153.    xcb_setup = xcb_get_setup(xcb_conn);
  154.  
  155.   if (!xcb_setup)
  156.     goto disconnect;
  157.  
  158.    s = xcb_setup_roots_iterator(xcb_setup);
  159.    connect_cookie = xcb_dri2_connect_unchecked(xcb_conn, s.data->root,
  160.                                                XCB_DRI2_DRIVER_TYPE_DRI);
  161.    connect = xcb_dri2_connect_reply(xcb_conn, connect_cookie, NULL);
  162.  
  163.    if (!connect || connect->driver_name_length
  164.                    + connect->device_name_length == 0) {
  165.  
  166.       goto disconnect;
  167.    }
  168.  
  169.    if (drmGetMagic(fd, &magic))
  170.       goto disconnect;
  171.  
  172.    authenticate_cookie = xcb_dri2_authenticate_unchecked(xcb_conn,
  173.                                                          s.data->root,
  174.                                                          magic);
  175.    authenticate = xcb_dri2_authenticate_reply(xcb_conn,
  176.                                               authenticate_cookie,
  177.                                               NULL);
  178.    FREE(authenticate);
  179.  
  180. disconnect:
  181.    xcb_disconnect(xcb_conn);
  182.  
  183. #endif
  184. }
  185.  
  186. boolean
  187. pipe_loader_drm_probe_fd(struct pipe_loader_device **dev, int fd)
  188. {
  189.    struct pipe_loader_drm_device *ddev = CALLOC_STRUCT(pipe_loader_drm_device);
  190.  
  191.    ddev->base.type = PIPE_LOADER_DEVICE_PCI;
  192.    ddev->base.ops = &pipe_loader_drm_ops;
  193.    ddev->fd = fd;
  194.  
  195.    pipe_loader_drm_x_auth(fd);
  196.  
  197.    if (!find_drm_pci_id(ddev))
  198.       goto fail;
  199.  
  200.    if (!find_drm_driver_name(ddev))
  201.       goto fail;
  202.  
  203.    *dev = &ddev->base;
  204.    return TRUE;
  205.  
  206.   fail:
  207.    FREE(ddev);
  208.    return FALSE;
  209. }
  210.  
  211. static int
  212. open_drm_minor(int minor)
  213. {
  214.    char path[PATH_MAX];
  215.    snprintf(path, sizeof(path), DRM_DEV_NAME, DRM_DIR_NAME, minor);
  216.    return open(path, O_RDWR, 0);
  217. }
  218.  
  219. int
  220. pipe_loader_drm_probe(struct pipe_loader_device **devs, int ndev)
  221. {
  222.    int i, j, fd;
  223.  
  224.    for (i = 0, j = 0; i < DRM_MAX_MINOR; i++) {
  225.       fd = open_drm_minor(i);
  226.       if (fd < 0)
  227.          continue;
  228.  
  229.       if (j >= ndev || !pipe_loader_drm_probe_fd(&devs[j], fd))
  230.          close(fd);
  231.  
  232.       j++;
  233.    }
  234.  
  235.    return j;
  236. }
  237.  
  238. static void
  239. pipe_loader_drm_release(struct pipe_loader_device **dev)
  240. {
  241.    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(*dev);
  242.  
  243.    if (ddev->lib)
  244.       util_dl_close(ddev->lib);
  245.  
  246.    close(ddev->fd);
  247.    FREE(ddev);
  248.    *dev = NULL;
  249. }
  250.  
  251. static struct pipe_screen *
  252. pipe_loader_drm_create_screen(struct pipe_loader_device *dev,
  253.                               const char *library_paths)
  254. {
  255.    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
  256.    const struct drm_driver_descriptor *dd;
  257.  
  258.    if (!ddev->lib)
  259.       ddev->lib = pipe_loader_find_module(dev, library_paths);
  260.    if (!ddev->lib)
  261.       return NULL;
  262.  
  263.    dd = (const struct drm_driver_descriptor *)
  264.       util_dl_get_proc_address(ddev->lib, "driver_descriptor");
  265.  
  266.    /* sanity check on the name */
  267.    if (!dd || strcmp(dd->name, ddev->base.driver_name) != 0)
  268.       return NULL;
  269.  
  270.    return dd->create_screen(ddev->fd);
  271. }
  272.  
  273. static struct pipe_loader_ops pipe_loader_drm_ops = {
  274.    .create_screen = pipe_loader_drm_create_screen,
  275.    .release = pipe_loader_drm_release
  276. };
  277.