Subversion Repositories Kolibri OS

Rev

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 VMWARE 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 <xf86drm.h>
  36. #include <unistd.h>
  37.  
  38. #ifdef HAVE_PIPE_LOADER_XCB
  39.  
  40. #include <xcb/dri2.h>
  41.  
  42. #endif
  43.  
  44. #include "loader.h"
  45. #include "state_tracker/drm_driver.h"
  46. #include "pipe_loader_priv.h"
  47.  
  48. #include "util/u_memory.h"
  49. #include "util/u_dl.h"
  50. #include "util/u_debug.h"
  51.  
  52. #define DRM_RENDER_NODE_DEV_NAME_FORMAT "%s/renderD%d"
  53. #define DRM_RENDER_NODE_MAX_NODES 63
  54. #define DRM_RENDER_NODE_MIN_MINOR 128
  55. #define DRM_RENDER_NODE_MAX_MINOR (DRM_RENDER_NODE_MIN_MINOR + DRM_RENDER_NODE_MAX_NODES)
  56.  
  57. struct pipe_loader_drm_device {
  58.    struct pipe_loader_device base;
  59.    struct util_dl_library *lib;
  60.    int fd;
  61. };
  62.  
  63. #define pipe_loader_drm_device(dev) ((struct pipe_loader_drm_device *)dev)
  64.  
  65. static struct pipe_loader_ops pipe_loader_drm_ops;
  66.  
  67. #ifdef HAVE_PIPE_LOADER_XCB
  68.  
  69. static xcb_screen_t *
  70. get_xcb_screen(xcb_screen_iterator_t iter, int screen)
  71. {
  72.     for (; iter.rem; --screen, xcb_screen_next(&iter))
  73.         if (screen == 0)
  74.             return iter.data;
  75.  
  76.     return NULL;
  77. }
  78.  
  79. #endif
  80.  
  81. static void
  82. pipe_loader_drm_x_auth(int fd)
  83. {
  84. #ifdef HAVE_PIPE_LOADER_XCB
  85.    /* Try authenticate with the X server to give us access to devices that X
  86.     * is running on. */
  87.    xcb_connection_t *xcb_conn;
  88.    const xcb_setup_t *xcb_setup;
  89.    xcb_screen_iterator_t s;
  90.    xcb_dri2_connect_cookie_t connect_cookie;
  91.    xcb_dri2_connect_reply_t *connect;
  92.    drm_magic_t magic;
  93.    xcb_dri2_authenticate_cookie_t authenticate_cookie;
  94.    xcb_dri2_authenticate_reply_t *authenticate;
  95.    int screen;
  96.  
  97.    xcb_conn = xcb_connect(NULL, &screen);
  98.  
  99.    if(!xcb_conn)
  100.       return;
  101.  
  102.    xcb_setup = xcb_get_setup(xcb_conn);
  103.  
  104.   if (!xcb_setup)
  105.     goto disconnect;
  106.  
  107.    s = xcb_setup_roots_iterator(xcb_setup);
  108.    connect_cookie = xcb_dri2_connect_unchecked(xcb_conn,
  109.                                                get_xcb_screen(s, screen)->root,
  110.                                                XCB_DRI2_DRIVER_TYPE_DRI);
  111.    connect = xcb_dri2_connect_reply(xcb_conn, connect_cookie, NULL);
  112.  
  113.    if (!connect || connect->driver_name_length
  114.                    + connect->device_name_length == 0) {
  115.  
  116.       goto disconnect;
  117.    }
  118.  
  119.    if (drmGetMagic(fd, &magic))
  120.       goto disconnect;
  121.  
  122.    authenticate_cookie = xcb_dri2_authenticate_unchecked(xcb_conn,
  123.                                                          s.data->root,
  124.                                                          magic);
  125.    authenticate = xcb_dri2_authenticate_reply(xcb_conn,
  126.                                               authenticate_cookie,
  127.                                               NULL);
  128.    FREE(authenticate);
  129.  
  130. disconnect:
  131.    xcb_disconnect(xcb_conn);
  132.  
  133. #endif
  134. }
  135.  
  136. bool
  137. pipe_loader_drm_probe_fd(struct pipe_loader_device **dev, int fd,
  138.                          boolean auth_x)
  139. {
  140.    struct pipe_loader_drm_device *ddev = CALLOC_STRUCT(pipe_loader_drm_device);
  141.    int vendor_id, chip_id;
  142.  
  143.    if (!ddev)
  144.       return false;
  145.  
  146.    if (loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) {
  147.       ddev->base.type = PIPE_LOADER_DEVICE_PCI;
  148.       ddev->base.u.pci.vendor_id = vendor_id;
  149.       ddev->base.u.pci.chip_id = chip_id;
  150.    } else {
  151.       ddev->base.type = PIPE_LOADER_DEVICE_PLATFORM;
  152.    }
  153.    ddev->base.ops = &pipe_loader_drm_ops;
  154.    ddev->fd = fd;
  155.  
  156.    if (auth_x)
  157.       pipe_loader_drm_x_auth(fd);
  158.  
  159.    ddev->base.driver_name = loader_get_driver_for_fd(fd, _LOADER_GALLIUM);
  160.    if (!ddev->base.driver_name)
  161.       goto fail;
  162.  
  163.    *dev = &ddev->base;
  164.    return true;
  165.  
  166.   fail:
  167.    FREE(ddev);
  168.    return false;
  169. }
  170.  
  171. static int
  172. open_drm_minor(int minor)
  173. {
  174.    char path[PATH_MAX];
  175.    snprintf(path, sizeof(path), DRM_DEV_NAME, DRM_DIR_NAME, minor);
  176.    return open(path, O_RDWR, 0);
  177. }
  178.  
  179. static int
  180. open_drm_render_node_minor(int minor)
  181. {
  182.    char path[PATH_MAX];
  183.    snprintf(path, sizeof(path), DRM_RENDER_NODE_DEV_NAME_FORMAT, DRM_DIR_NAME,
  184.             minor);
  185.    return open(path, O_RDWR, 0);
  186. }
  187.  
  188. int
  189. pipe_loader_drm_probe(struct pipe_loader_device **devs, int ndev)
  190. {
  191.    int i, k, fd, num_render_node_devs;
  192.    int j = 0;
  193.  
  194.    struct {
  195.       unsigned vendor_id;
  196.       unsigned chip_id;
  197.    } render_node_devs[DRM_RENDER_NODE_MAX_NODES];
  198.  
  199.    /* Look for render nodes first */
  200.    for (i = DRM_RENDER_NODE_MIN_MINOR, j = 0;
  201.         i <= DRM_RENDER_NODE_MAX_MINOR; i++) {
  202.       fd = open_drm_render_node_minor(i);
  203.       struct pipe_loader_device *dev;
  204.       if (fd < 0)
  205.          continue;
  206.  
  207.       if (!pipe_loader_drm_probe_fd(&dev, fd, false)) {
  208.          close(fd);
  209.          continue;
  210.       }
  211.  
  212.       render_node_devs[j].vendor_id = dev->u.pci.vendor_id;
  213.       render_node_devs[j].chip_id = dev->u.pci.chip_id;
  214.  
  215.       if (j < ndev) {
  216.          devs[j] = dev;
  217.       } else {
  218.          close(fd);
  219.          dev->ops->release(&dev);
  220.       }
  221.       j++;
  222.    }
  223.  
  224.    num_render_node_devs = j;
  225.  
  226.    /* Next look for drm devices. */
  227.    for (i = 0; i < DRM_MAX_MINOR; i++) {
  228.       struct pipe_loader_device *dev;
  229.       boolean duplicate = FALSE;
  230.       fd = open_drm_minor(i);
  231.       if (fd < 0)
  232.          continue;
  233.  
  234.       if (!pipe_loader_drm_probe_fd(&dev, fd, true)) {
  235.          close(fd);
  236.          continue;
  237.       }
  238.  
  239.       /* Check to make sure we aren't already accessing this device via
  240.        * render nodes.
  241.        */
  242.       for (k = 0; k < num_render_node_devs; k++) {
  243.          if (dev->u.pci.vendor_id == render_node_devs[k].vendor_id &&
  244.              dev->u.pci.chip_id == render_node_devs[k].chip_id) {
  245.             close(fd);
  246.             dev->ops->release(&dev);
  247.             duplicate = TRUE;
  248.             break;
  249.          }
  250.       }
  251.  
  252.       if (duplicate)
  253.          continue;
  254.  
  255.       if (j < ndev) {
  256.          devs[j] = dev;
  257.       } else {
  258.          dev->ops->release(&dev);
  259.       }
  260.  
  261.       j++;
  262.    }
  263.  
  264.    return j;
  265. }
  266.  
  267. static void
  268. pipe_loader_drm_release(struct pipe_loader_device **dev)
  269. {
  270.    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(*dev);
  271.  
  272.    if (ddev->lib)
  273.       util_dl_close(ddev->lib);
  274.  
  275.    close(ddev->fd);
  276.    FREE(ddev->base.driver_name);
  277.    FREE(ddev);
  278.    *dev = NULL;
  279. }
  280.  
  281. static const struct drm_conf_ret *
  282. pipe_loader_drm_configuration(struct pipe_loader_device *dev,
  283.                               enum drm_conf conf)
  284. {
  285.    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
  286.    const struct drm_driver_descriptor *dd;
  287.  
  288.    if (!ddev->lib)
  289.       return NULL;
  290.  
  291.    dd = (const struct drm_driver_descriptor *)
  292.       util_dl_get_proc_address(ddev->lib, "driver_descriptor");
  293.  
  294.    /* sanity check on the name */
  295.    if (!dd || strcmp(dd->name, ddev->base.driver_name) != 0)
  296.       return NULL;
  297.  
  298.    if (!dd->configuration)
  299.       return NULL;
  300.  
  301.    return dd->configuration(conf);
  302. }
  303.  
  304. static struct pipe_screen *
  305. pipe_loader_drm_create_screen(struct pipe_loader_device *dev,
  306.                               const char *library_paths)
  307. {
  308.    struct pipe_loader_drm_device *ddev = pipe_loader_drm_device(dev);
  309.    const struct drm_driver_descriptor *dd;
  310.  
  311.    if (!ddev->lib)
  312.       ddev->lib = pipe_loader_find_module(dev, library_paths);
  313.    if (!ddev->lib)
  314.       return NULL;
  315.  
  316.    dd = (const struct drm_driver_descriptor *)
  317.       util_dl_get_proc_address(ddev->lib, "driver_descriptor");
  318.  
  319.    /* sanity check on the name */
  320.    if (!dd || strcmp(dd->name, ddev->base.driver_name) != 0)
  321.       return NULL;
  322.  
  323.    return dd->create_screen(ddev->fd);
  324. }
  325.  
  326. static struct pipe_loader_ops pipe_loader_drm_ops = {
  327.    .create_screen = pipe_loader_drm_create_screen,
  328.    .configuration = pipe_loader_drm_configuration,
  329.    .release = pipe_loader_drm_release
  330. };
  331.