diff --git a/xf86drm.c b/xf86drm.c index 3a10589..207c456 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -88,8 +88,10 @@ #endif #include "xf86drm.h" +#include "xf86drm_redox.h" #include "libdrm_macros.h" #include "drm_fourcc.h" +#include "virtgpu_drm.h" #include "util_math.h" @@ -113,7 +115,7 @@ #define DRM_MAJOR 226 /* Linux */ #endif -#if defined(__OpenBSD__) || defined(__DragonFly__) +#if defined(__OpenBSD__) || defined(__DragonFly__) || defined(__redox__) struct drm_pciinfo { uint16_t domain; uint8_t bus; @@ -313,7 +315,6 @@ drmGetFormatModifierNameFromArm(uint64_t modifier) uint64_t type = (modifier >> 52) & 0xf; FILE *fp; - size_t size = 0; char *modifier_name = NULL; bool result = false; @@ -321,6 +322,7 @@ drmGetFormatModifierNameFromArm(uint64_t modifier) fprintf(stderr, "open_memstream not available on Redox\n"); return NULL; #else + size_t size = 0; fp = open_memstream(&modifier_name, &size); if (!fp) return NULL; @@ -425,12 +427,12 @@ drmGetFormatModifierNameFromAmd(uint64_t modifier) uint64_t tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier); FILE *fp; char *mod_amd = NULL; - size_t size = 0; #if defined(__redox__) fprintf(stderr, "open_memstream not available on Redox\n"); return NULL; #else + size_t size = 0; fp = open_memstream(&mod_amd, &size); if (!fp) return NULL; @@ -703,18 +705,366 @@ drm_public void drmFree(void *pt) free(pt); } +#if defined(__redox__) +static int redox_drm_write_all(int fd, const void *buf, size_t len) +{ + const uint8_t *bytes = buf; + size_t offset = 0; + + while (offset < len) { + ssize_t written = write(fd, bytes + offset, len - offset); + if (written < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + } + if (written == 0) { + errno = EIO; + return -1; + } + offset += (size_t)written; + } + + return 0; +} + +static int redox_drm_read_all(int fd, void *buf, size_t len) +{ + uint8_t *bytes = buf; + size_t offset = 0; + + while (offset < len) { + ssize_t read_count = read(fd, bytes + offset, len - offset); + if (read_count < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + return -1; + } + if (read_count == 0) { + errno = EIO; + return -1; + } + offset += (size_t)read_count; + } + + return 0; +} + +static int redox_drm_send_request(int fd, unsigned long request_code, + const void *payload, size_t payload_size) +{ + const size_t request_word_size = sizeof(uintptr_t); + const size_t total_size = request_word_size + payload_size; + uint8_t stack_request[sizeof(uintptr_t)]; + uint8_t *request_bytes = stack_request; + uintptr_t request_word = (uintptr_t)request_code; + size_t i; + + if (total_size > sizeof(stack_request)) { + request_bytes = drmMalloc(total_size); + if (!request_bytes) { + errno = ENOMEM; + return -1; + } + } + + for (i = 0; i < request_word_size; ++i) + request_bytes[i] = (uint8_t)((request_word >> (i * 8)) & 0xffU); + + if (payload_size != 0) + memcpy(request_bytes + request_word_size, payload, payload_size); + + if (redox_drm_write_all(fd, request_bytes, total_size) != 0) { + if (request_bytes != stack_request) + drmFree(request_bytes); + return -1; + } + + if (request_bytes != stack_request) + drmFree(request_bytes); + + return 0; +} + +static int redox_drm_get_response_size(int fd, size_t *response_size) +{ + stat_t st; + + if (fstat(fd, &st) != 0) + return -1; + + *response_size = (size_t)st.st_size; + return 0; +} + +unsigned long redox_translate_request(unsigned long linux_nr) +{ + switch (linux_nr) { + case 0x0C: + return REDOX_DRM_IOCTL_GET_CAP; + case 0x0D: + return REDOX_DRM_IOCTL_SET_CLIENT_CAP; + case 0x09: + return REDOX_DRM_IOCTL_GEM_CLOSE; + case 0xA6: + return REDOX_DRM_IOCTL_MODE_GETENCODER; + case 0xB3: + return REDOX_DRM_IOCTL_MODE_MAP_DUMB; + case 0xB4: + return REDOX_DRM_IOCTL_MODE_DESTROY_DUMB; + case 0xAF: + return REDOX_DRM_IOCTL_MODE_RMFB; + /* VirtGPU ioctls (NR 0x41-0x4B) */ + case 0x41: + return REDOX_DRM_IOCTL_VIRTGPU_MAP; + case 0x42: + return REDOX_DRM_IOCTL_VIRTGPU_EXECBUFFER; + case 0x43: + return REDOX_DRM_IOCTL_VIRTGPU_GETPARAM; + case 0x44: + return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE; + case 0x45: + return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_INFO; + case 0x46: + return REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST; + case 0x47: + return REDOX_DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST; + case 0x48: + return REDOX_DRM_IOCTL_VIRTGPU_WAIT; + case 0x49: + return REDOX_DRM_IOCTL_VIRTGPU_GET_CAPS; + case 0x4A: + return REDOX_DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB; + case 0x4B: + return REDOX_DRM_IOCTL_VIRTGPU_CONTEXT_INIT; + /* Additional standard DRM ioctls */ + case 0x00: + return REDOX_DRM_IOCTL_VERSION; + case 0xA0: + return REDOX_DRM_IOCTL_MODE_GETRESOURCES; + case 0xA1: + return REDOX_DRM_IOCTL_MODE_GETCRTC; + case 0xA2: + return REDOX_DRM_IOCTL_MODE_SETCRTC; + case 0xA3: + return REDOX_DRM_IOCTL_MODE_GETCONNECTOR; + case 0xA4: + return REDOX_DRM_IOCTL_MODE_PAGE_FLIP; + case 0xA8: + return REDOX_DRM_IOCTL_MODE_CREATE_DUMB; + case 0xAC: + return REDOX_DRM_IOCTL_MODE_ADDFB; + case 0x2B: + return REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD; + case 0x2C: + return REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE; + /* DRM_IOCTL_GET_PCIINFO — PCI device information for driver discovery */ + case 0x15: + return REDOX_DRM_IOCTL_GET_PCI_INFO; + /* DRM auth/master ioctls */ + case 0x02: /* GET_MAGIC — DRM_IOR(0x02, struct drm_auth) */ + return REDOX_DRM_IOCTL_GET_MAGIC; + case 0x11: /* AUTH_MAGIC — DRM_IOW(0x11, struct drm_auth) */ + return REDOX_DRM_IOCTL_AUTH_MAGIC; + case 0x1e: /* SET_MASTER — DRM_IO(0x1e) */ + return REDOX_DRM_IOCTL_SET_MASTER; + case 0x1f: /* DROP_MASTER — DRM_IO(0x1f) */ + return REDOX_DRM_IOCTL_DROP_MASTER; + default: + return 0; + } +} + +int redox_drm_exchange(int fd, unsigned long request_code, + const void *payload, size_t payload_size, + void *response, size_t response_capacity, + size_t *response_size) +{ + uint8_t stack_buffer[64]; + uint8_t *response_buffer = stack_buffer; + size_t actual_response_size = 0; + + if (redox_drm_send_request(fd, request_code, payload, payload_size) != 0) + return -1; + + if (redox_drm_get_response_size(fd, &actual_response_size) != 0) + return -1; + + if (response_size) + *response_size = actual_response_size; + + if (actual_response_size == 0) + return 0; + + if (response && response_capacity >= actual_response_size) { + return redox_drm_read_all(fd, response, actual_response_size); + } + + if (actual_response_size > sizeof(stack_buffer)) { + response_buffer = drmMalloc(actual_response_size); + if (!response_buffer) { + errno = ENOMEM; + return -1; + } + } + + if (redox_drm_read_all(fd, response_buffer, actual_response_size) != 0) { + if (response_buffer != stack_buffer) + drmFree(response_buffer); + return -1; + } + + if (response_buffer != stack_buffer) + drmFree(response_buffer); + + if (response && response_capacity < actual_response_size) { + errno = EMSGSIZE; + return -1; + } + + return 0; +} + +int redox_drm_exchange_alloc(int fd, unsigned long request_code, + const void *payload, size_t payload_size, + void **response, size_t *response_size) +{ + size_t actual_response_size = 0; + void *allocated_response = NULL; + + if (!response) { + errno = EINVAL; + return -1; + } + + if (redox_drm_send_request(fd, request_code, payload, payload_size) != 0) + return -1; + + if (redox_drm_get_response_size(fd, &actual_response_size) != 0) + return -1; + + if (actual_response_size != 0) { + allocated_response = drmMalloc(actual_response_size); + if (!allocated_response) { + errno = ENOMEM; + return -1; + } + + if (redox_drm_read_all(fd, allocated_response, actual_response_size) != 0) { + drmFree(allocated_response); + return -1; + } + } + + *response = allocated_response; + if (response_size) + *response_size = actual_response_size; + return 0; +} + +static size_t redox_drm_expected_response_size(unsigned long linux_nr, size_t arg_size) +{ + switch (linux_nr) { + case 0x00: /* VERSION */ + case 0x0C: + case 0x2B: /* PRIME_HANDLE_TO_FD */ + case 0x2C: /* PRIME_FD_TO_HANDLE */ + case 0x41: /* VIRTGPU_MAP */ + case 0x43: /* VIRTGPU_GETPARAM */ + case 0x44: /* VIRTGPU_RESOURCE_CREATE */ + case 0x45: /* VIRTGPU_RESOURCE_INFO */ + case 0xA0: /* MODE_GETRESOURCES */ + case 0xA1: /* MODE_GETCRTC */ + case 0xA3: /* MODE_GETCONNECTOR */ + case 0xA8: /* MODE_CREATE_DUMB */ + case 0xAC: /* MODE_ADDFB */ + case 0xA6: + case 0xB3: + return arg_size; + case 0x02: /* GET_MAGIC — returns struct drm_auth (magic u32) */ + return arg_size; + case 0x11: /* AUTH_MAGIC — returns struct drm_auth (magic u32) */ + return arg_size; + default: + return 0; + } +} + +int redox_drm_simple_ioctl(int fd, unsigned long request, void *arg) +{ + const unsigned long linux_nr = REDOX_LINUX_IOCTL_NR(request); + const unsigned long request_code = redox_translate_request(linux_nr); + const size_t arg_size = REDOX_LINUX_IOCTL_SIZE(request); + const size_t expected_response_size = redox_drm_expected_response_size(linux_nr, arg_size); + + if (request_code == 0) { + errno = ENOTTY; + return -1; + } + + if (linux_nr == 0x42) { /* VIRTGPU_EXECBUFFER */ + struct drm_virtgpu_execbuffer *eb = arg; + size_t total = arg_size + eb->size; + uint8_t *buf = drmMalloc((int)total); + int ret; + + if (!buf) + return -1; + + memcpy(buf, arg, arg_size); + if (eb->size > 0 && eb->command) + memcpy(buf + arg_size, (void *)(uintptr_t)eb->command, eb->size); + + ret = redox_drm_exchange(fd, request_code, buf, total, NULL, 0, NULL); + drmFree(buf); + return ret; + } + + if (linux_nr == 0x49) { /* VIRTGPU_GET_CAPS */ + struct drm_virtgpu_get_caps *gc = arg; + void *resp; + size_t resp_size; + int ret; + + ret = redox_drm_exchange_alloc(fd, request_code, arg, arg_size, &resp, &resp_size); + if (ret == 0 && resp && resp_size > 0) { + size_t copy = resp_size < gc->size ? resp_size : gc->size; + + memcpy((void *)(uintptr_t)gc->addr, resp, copy); + drmFree(resp); + } + + return ret; + } + + if (redox_drm_exchange(fd, request_code, + arg, arg ? arg_size : 0, + expected_response_size ? arg : NULL, + expected_response_size, + NULL) != 0) { + return -1; + } + + return 0; +} +#endif + /** * Call ioctl, restarting if it is interrupted */ drm_public int drmIoctl(int fd, unsigned long request, void *arg) { + #if defined(__redox__) + return redox_drm_simple_ioctl(fd, request, arg); + #else int ret; do { ret = ioctl(fd, request, arg); } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); return ret; + #endif } static unsigned long drmGetKeyFromFd(int fd) @@ -1093,6 +1443,7 @@ static int drmGetMinorType(int major, int minor) return -1; } +#if !defined(__redox__) static const char *drmGetMinorName(int type) { switch (type) { @@ -1104,6 +1455,7 @@ static const char *drmGetMinorName(int type) return NULL; } } +#endif /** * Open the device by bus ID. @@ -1201,7 +1553,11 @@ static int drmOpenByName(const char *name, int type) for (i = base; i < base + DRM_MAX_MINOR; i++) { if ((fd = drmOpenMinor(i, 1, type)) >= 0) { if ((version = drmGetVersion(fd))) { + #if defined(__redox__) + if (!version->name || !strcmp(version->name, name)) { + #else if (!strcmp(version->name, name)) { + #endif drmFreeVersion(version); id = drmGetBusid(fd); drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL"); @@ -1354,6 +1710,7 @@ drm_public void drmFreeVersion(drmVersionPtr v) * Used by drmGetVersion() to free the memory pointed by \p %v as well as all * the non-null strings pointers in it. */ +#if !defined(__redox__) static void drmFreeKernelVersion(drm_version_t *v) { if (!v) @@ -1363,6 +1720,7 @@ static void drmFreeKernelVersion(drm_version_t *v) drmFree(v->desc); drmFree(v); } +#endif /** @@ -1375,6 +1733,7 @@ static void drmFreeKernelVersion(drm_version_t *v) * Used by drmGetVersion() to translate the information returned by the ioctl * interface in a private structure into the public structure counterpart. */ +#if !defined(__redox__) static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) { d->version_major = s->version_major; @@ -1387,6 +1746,7 @@ static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) d->desc_len = s->desc_len; d->desc = s->desc ? strdup(s->desc) : NULL; } +#endif /** @@ -1406,6 +1766,50 @@ static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s) */ drm_public drmVersionPtr drmGetVersion(int fd) { + #if defined(__redox__) + drmVersionPtr retval = drmMalloc(sizeof(*retval)); + struct redox_drm_version_wire version; + + if (!retval) + return NULL; + + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_VERSION, + NULL, 0, + &version, sizeof(version), + NULL) != 0) { + drmFree(retval); + return NULL; + } + + memclear(*retval); + retval->version_major = version.major; + retval->version_minor = version.minor; + retval->version_patchlevel = version.patch; + + /* The scheme returns a NUL-terminated driver name in version.name. + * KWin drm_gpu.cpp dereferences version->name unconditionally + * (strstr checks for "i915", "amdgpu", "virtio" etc.) so it must + * never be NULL. + */ + version.name[sizeof(version.name) - 1] = '\0'; + if (version.name[0] != '\0') { + size_t len = strlen(version.name); + retval->name = drmMalloc(len + 1); + if (retval->name) { + memcpy(retval->name, version.name, len + 1); + retval->name_len = len; + } + } else { + const char fallback[] = "redox-drm"; + retval->name = drmMalloc(sizeof(fallback)); + if (retval->name) { + memcpy(retval->name, fallback, sizeof(fallback)); + retval->name_len = sizeof(fallback) - 1; + } + } + + return retval; + #else drmVersionPtr retval; drm_version_t *version = drmMalloc(sizeof(*version)); @@ -1436,6 +1840,7 @@ drm_public drmVersionPtr drmGetVersion(int fd) drmCopyVersion(retval, version); drmFreeKernelVersion(version); return retval; + #endif } @@ -3400,6 +3805,23 @@ drm_public int drmGetNodeTypeFromFd(int fd) drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) { + #if defined(__redox__) + struct redox_drm_prime_handle_to_fd_wire request; + struct redox_drm_prime_handle_to_fd_response_wire response; + + memclear(request); + request.handle = handle; + request.flags = flags; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD, + &request, sizeof(request), + &response, sizeof(response), + NULL) != 0) { + return -errno; + } + + *prime_fd = response.fd; + return 0; + #else struct drm_prime_handle args; int ret; @@ -3413,10 +3835,27 @@ drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, *prime_fd = args.fd; return 0; + #endif } drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) { + #if defined(__redox__) + struct redox_drm_prime_fd_to_handle_wire request; + struct redox_drm_prime_fd_to_handle_response_wire response; + + memclear(request); + request.fd = prime_fd; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE, + &request, sizeof(request), + &response, sizeof(response), + NULL) != 0) { + return -errno; + } + + *handle = response.handle; + return 0; + #else struct drm_prime_handle args; int ret; @@ -3428,6 +3867,7 @@ drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) *handle = args.handle; return 0; + #endif } drm_public int drmCloseBufferHandle(int fd, uint32_t handle) @@ -3544,7 +3984,7 @@ static char *drmGetMinorNameForFD(int fd, int type) n = drmGetNodePath(buf, sizeof(buf), type, min); if (n < 0) return NULL; - if (n == -1 || n >= sizeof(buf)) + if ((size_t)n >= sizeof(buf)) return NULL; return strdup(buf); @@ -3666,7 +4106,7 @@ static int drmParseSubsystemType(int maj, int min) return DRM_BUS_VIRTIO; } return subsystem_type; -#elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) +#elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__redox__) return DRM_BUS_PCI; #else #warning "Missing implementation of drmParseSubsystemType" @@ -3800,6 +4240,21 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) return 0; #elif defined(__FreeBSD__) return get_sysctl_pci_bus_info(maj, min, info); +#elif defined(__redox__) + int rfd = open("/scheme/drm/card0", O_RDONLY); + if (rfd < 0) + return -errno; + uint8_t buf[22]; + size_t rsize = 0; + int ret = redox_drm_exchange(rfd, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, buf, sizeof(buf), &rsize); + close(rfd); + if (ret != 0 || rsize < 17) + return -EIO; + info->domain = buf[10] | (buf[11] << 8) | (buf[12] << 16) | (buf[13] << 24); + info->bus = buf[14]; + info->dev = buf[15]; + info->func = buf[16]; + return 0; #else #warning "Missing implementation of drmParsePciBusInfo" return -EINVAL; @@ -4009,6 +4464,23 @@ static int drmParsePciDeviceInfo(int maj, int min, device->revision_id = results[0].pc_revid; return 0; +#elif defined(__redox__) + int rfd2 = open("/scheme/drm/card0", O_RDONLY); + if (rfd2 < 0) + return -errno; + uint8_t dbuf[22]; + size_t drsize = 0; + int dret = redox_drm_exchange(rfd2, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, dbuf, sizeof(dbuf), &drsize); + close(rfd2); + if (dret != 0 || drsize < 9) + return -EIO; + device->vendor_id = dbuf[0] | (dbuf[1] << 8); + device->device_id = dbuf[2] | (dbuf[3] << 8); + device->subvendor_id = dbuf[4] | (dbuf[5] << 8); + device->subdevice_id = dbuf[6] | (dbuf[7] << 8); + if (drsize >= 9) + device->revision_id = dbuf[8]; + return 0; #else #warning "Missing implementation of drmParsePciDeviceInfo" return -EINVAL; @@ -4661,6 +5133,66 @@ drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDeviceP *device = d; + return 0; +#elif defined(__redox__) + /* On Redox there is no /dev/dri/ directory to enumerate. + * Instead, open /scheme/drm/card0 and query PCI info to + * construct a single drmDevice that serves as both primary + * and render node. */ + drmDevicePtr devp; + char *pptr; + int max_node_length = 64, i; + size_t extra, psize; + uint8_t pbuf[22]; + size_t prsize = 0; + int pret, fd; + + if (device == NULL) + return -EINVAL; + if (drm_device_validate_flags(flags)) + return -EINVAL; + + fd = open("/scheme/drm/card0", O_RDWR | O_CLOEXEC); + if (fd < 0) + return -errno; + + pret = redox_drm_exchange(fd, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, + pbuf, sizeof(pbuf), &prsize); + close(fd); + if (pret != 0 || prsize < 17) + return -EIO; + + extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); + psize = sizeof(drmDevice) + extra + sizeof(drmPciBusInfo) + sizeof(drmPciDeviceInfo); + devp = calloc(1, psize); + if (!devp) + return -ENOMEM; + + devp->bustype = DRM_BUS_PCI; + /* Advertise both PRIMARY and RENDER — same path on Redox */ + devp->available_nodes = (1 << DRM_NODE_PRIMARY) | (1 << DRM_NODE_RENDER); + pptr = (char *)devp + sizeof(drmDevice); + devp->nodes = (char **)pptr; + pptr += DRM_NODE_MAX * sizeof(void *); + for (i = 0; i < DRM_NODE_MAX; i++) { devp->nodes[i] = pptr; pptr += max_node_length; } + snprintf(devp->nodes[DRM_NODE_PRIMARY], max_node_length, "/scheme/drm/card0"); + snprintf(devp->nodes[DRM_NODE_RENDER], max_node_length, "/scheme/drm/card0"); + + devp->businfo.pci = (drmPciBusInfoPtr)pptr; + pptr += sizeof(drmPciBusInfo); + devp->businfo.pci->domain = pbuf[10] | (pbuf[11] << 8) | (pbuf[12] << 16) | (pbuf[13] << 24); + devp->businfo.pci->bus = pbuf[14]; + devp->businfo.pci->dev = pbuf[15]; + devp->businfo.pci->func = pbuf[16]; + + devp->deviceinfo.pci = (drmPciDeviceInfoPtr)pptr; + devp->deviceinfo.pci->vendor_id = pbuf[0] | (pbuf[1] << 8); + devp->deviceinfo.pci->device_id = pbuf[2] | (pbuf[3] << 8); + devp->deviceinfo.pci->subvendor_id = pbuf[4] | (pbuf[5] << 8); + devp->deviceinfo.pci->subdevice_id = pbuf[6] | (pbuf[7] << 8); + devp->deviceinfo.pci->revision_id = pbuf[8]; + + *device = devp; return 0; #else drmDevicePtr local_devices[MAX_DRM_NODES]; @@ -4761,6 +5293,66 @@ drm_public int drmGetNodeTypeFromDevId(dev_t devid) */ drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) { +#if defined(__redox__) + uint8_t pbuf[22]; + size_t prsize = 0; + int pret; + uint16_t pvendor_id, pdevice_id, psubvendor_id, psubdevice_id, pdomain; + uint8_t prevision_id, pbus, pdev, pfunc; + const char *pnode; + int max_node_length, i; + size_t extra, psize; + drmDevicePtr devp; + char *pptr; + + pret = redox_drm_exchange(fd, REDOX_DRM_IOCTL_GET_PCI_INFO, NULL, 0, + pbuf, sizeof(pbuf), &prsize); + if (pret != 0 || prsize < 17) + return -EIO; + + pvendor_id = pbuf[0] | (pbuf[1] << 8); + pdevice_id = pbuf[2] | (pbuf[3] << 8); + psubvendor_id = pbuf[4] | (pbuf[5] << 8); + psubdevice_id = pbuf[6] | (pbuf[7] << 8); + prevision_id = pbuf[8]; + pdomain = pbuf[10] | (pbuf[11] << 8) | (pbuf[12] << 16) | (pbuf[13] << 24); + pbus = pbuf[14]; + pdev = pbuf[15]; + pfunc = pbuf[16]; + + pnode = "/scheme/drm/card0"; + max_node_length = 64; + extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length); + psize = sizeof(drmDevice) + extra + sizeof(drmPciBusInfo) + sizeof(drmPciDeviceInfo); + devp = calloc(1, psize); + if (!devp) + return -ENOMEM; + + devp->bustype = DRM_BUS_PCI; + devp->available_nodes = 1 << DRM_NODE_PRIMARY; + pptr = (char *)devp + sizeof(drmDevice); + devp->nodes = (char **)pptr; + pptr += DRM_NODE_MAX * sizeof(void *); + for (i = 0; i < DRM_NODE_MAX; i++) { devp->nodes[i] = pptr; pptr += max_node_length; } + snprintf(devp->nodes[DRM_NODE_PRIMARY], max_node_length, "%s", pnode); + + devp->businfo.pci = (drmPciBusInfoPtr)pptr; + pptr += sizeof(drmPciBusInfo); + devp->businfo.pci->domain = pdomain; + devp->businfo.pci->bus = pbus; + devp->businfo.pci->dev = pdev; + devp->businfo.pci->func = pfunc; + + devp->deviceinfo.pci = (drmPciDeviceInfoPtr)pptr; + devp->deviceinfo.pci->vendor_id = pvendor_id; + devp->deviceinfo.pci->device_id = pdevice_id; + devp->deviceinfo.pci->subvendor_id = psubvendor_id; + devp->deviceinfo.pci->subdevice_id = psubdevice_id; + devp->deviceinfo.pci->revision_id = prevision_id; + + *device = devp; + return 0; +#else struct stat sbuf; if (fd == -1) @@ -4773,6 +5365,7 @@ drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) return -EINVAL; return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device); +#endif } /**