diff -ruN source-old/include/drm/drm.h source/include/drm/drm.h --- source-old/include/drm/drm.h +++ source/include/drm/drm.h @@ -44,7 +44,11 @@ #else /* One of the BSDs */ #include +#if defined(__redox__) +#include +#else #include +#endif #include typedef int8_t __s8; typedef uint8_t __u8; diff -ruN source-old/xf86drm.c source/xf86drm.c --- source-old/xf86drm.c +++ source/xf86drm.c @@ -57,6 +57,19 @@ #ifdef MAJOR_IN_SYSMACROS #include #endif +#if defined(__redox__) +// From musl sys/sysmacros.h +#define major(x) \ + ((unsigned)( (((x)>>31>>1) & 0xfffff000) | (((x)>>8) & 0x00000fff) )) +#define minor(x) \ + ((unsigned)( (((x)>>12) & 0xffffff00) | ((x) & 0x000000ff) )) + +#define makedev(x,y) ( \ + (((x)&0xfffff000ULL) << 32) | \ + (((x)&0x00000fffULL) << 8) | \ + (((y)&0xffffff00ULL) << 12) | \ + (((y)&0x000000ffULL)) ) +#endif #if HAVE_SYS_SYSCTL_H #include #endif @@ -75,6 +88,7 @@ #endif #include "xf86drm.h" +#include "xf86drm_redox.h" #include "libdrm_macros.h" #include "drm_fourcc.h" @@ -300,13 +314,18 @@ uint64_t type = (modifier >> 52) & 0xf; FILE *fp; - size_t size = 0; char *modifier_name = NULL; bool result = false; +#if defined(__redox__) + 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; +#endif switch (type) { case DRM_FORMAT_MOD_ARM_TYPE_AFBC: @@ -407,11 +426,16 @@ 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; +#endif switch (tile_version) { case AMD_FMT_MOD_TILE_VER_GFX9: @@ -680,18 +704,259 @@ 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; + 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 0x0C: + case 0xA6: + case 0xB3: + 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 (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) @@ -823,6 +1088,21 @@ return NULL; } +static int drmGetNodePath(char *buf, size_t buf_len, int type, int minor) +{ + const char *dev_name = drmGetDeviceName(type); + +#if defined(__redox__) + if (type == DRM_NODE_RENDER) + return snprintf(buf, buf_len, "%s/" DRM_RENDER_MINOR_NAME, DRM_DIR_NAME); +#endif + + if (!dev_name) + return -1; + + return snprintf(buf, buf_len, dev_name, DRM_DIR_NAME, minor); +} + /** * Open the DRM device, creating it if necessary. * @@ -839,7 +1119,6 @@ static int drmOpenDevice(dev_t dev, int minor, int type) { stat_t st; - const char *dev_name = drmGetDeviceName(type); char buf[DRM_NODE_NAME_MAX]; int fd; mode_t devmode = DRM_DEV_MODE, serv_mode; @@ -850,10 +1129,8 @@ gid_t group = DRM_DEV_GID; #endif - if (!dev_name) + if (drmGetNodePath(buf, sizeof(buf), type, minor) < 0) return -EINVAL; - - sprintf(buf, dev_name, DRM_DIR_NAME, minor); drmMsg("drmOpenDevice: node name is %s\n", buf); if (drm_server_info && drm_server_info->get_perms) { @@ -958,15 +1235,13 @@ { int fd; char buf[DRM_NODE_NAME_MAX]; - const char *dev_name = drmGetDeviceName(type); if (create) return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type); - if (!dev_name) + if (drmGetNodePath(buf, sizeof(buf), type, minor) < 0) return -EINVAL; - sprintf(buf, dev_name, DRM_DIR_NAME, minor); if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0) return fd; return -errno; @@ -1060,6 +1335,7 @@ return -1; } +#if !defined(__redox__) static const char *drmGetMinorName(int type) { switch (type) { @@ -1071,6 +1347,7 @@ return NULL; } } +#endif /** * Open the device by bus ID. @@ -1168,7 +1445,11 @@ 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"); @@ -1321,6 +1602,7 @@ * 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) @@ -1330,6 +1612,7 @@ drmFree(v->desc); drmFree(v); } +#endif /** @@ -1342,6 +1625,7 @@ * 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; @@ -1354,6 +1638,7 @@ d->desc_len = s->desc_len; d->desc = s->desc ? strdup(s->desc) : NULL; } +#endif /** @@ -1373,6 +1658,27 @@ */ 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; + return retval; + #else drmVersionPtr retval; drm_version_t *version = drmMalloc(sizeof(*version)); @@ -1403,6 +1709,7 @@ drmCopyVersion(retval, version); drmFreeKernelVersion(version); return retval; + #endif } @@ -3306,7 +3613,8 @@ d = sbuf.st_rdev; for (i = 0; i < DRM_MAX_MINOR; i++) { - snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); + if (drmGetNodePath(name, sizeof(name), DRM_NODE_PRIMARY, i) < 0) + return NULL; if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) break; } @@ -3366,6 +3674,23 @@ 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; @@ -3379,10 +3704,27 @@ *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; @@ -3394,6 +3736,7 @@ *handle = args.handle; return 0; + #endif } drm_public int drmCloseBufferHandle(int fd, uint32_t handle) @@ -3495,7 +3838,6 @@ #else struct stat sbuf; char buf[PATH_MAX + 1]; - const char *dev_name = drmGetDeviceName(type); unsigned int maj, min; int n; @@ -3508,11 +3850,10 @@ if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) return NULL; - if (!dev_name) + n = drmGetNodePath(buf, sizeof(buf), type, min); + if (n < 0) return NULL; - - n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min); - if (n == -1 || n >= sizeof(buf)) + if ((size_t)n >= sizeof(buf)) return NULL; return strdup(buf); @@ -4877,7 +5218,6 @@ #else struct stat sbuf; char node[PATH_MAX + 1]; - const char *dev_name; int node_type; int maj, min, n; @@ -4894,12 +5234,8 @@ if (node_type == -1) return NULL; - dev_name = drmGetDeviceName(node_type); - if (!dev_name) - return NULL; - - n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min); - if (n == -1 || n >= PATH_MAX) + n = drmGetNodePath(node, sizeof(node), node_type, min); + if (n < 0 || n >= PATH_MAX) return NULL; return strdup(node); diff -ruN source-old/xf86drm.h source/xf86drm.h --- source-old/xf86drm.h +++ source/xf86drm.h @@ -47,7 +47,7 @@ #define DRM_MAX_MINOR 64 /* deprecated */ #endif -#if defined(__linux__) +#if defined(__linux__) || defined(__redox__) #define DRM_IOCTL_NR(n) _IOC_NR(n) #define DRM_IOC_VOID _IOC_NONE @@ -81,6 +81,12 @@ #define DRM_PRIMARY_MINOR_NAME "drm" #define DRM_CONTROL_MINOR_NAME "drmC" /* deprecated */ #define DRM_RENDER_MINOR_NAME "drmR" +#elif defined(__redox__) +#define DRM_DIR_NAME "/scheme/drm" +#define DRM_PRIMARY_MINOR_NAME "card" +#define DRM_CONTROL_MINOR_NAME "controlD" /* deprecated */ +#define DRM_RENDER_MINOR_NAME "renderD" +#define DRM_PROC_NAME "/proc/dri/" /* For backward Linux compatibility */ #else #define DRM_DIR_NAME "/dev/dri" #define DRM_PRIMARY_MINOR_NAME "card" diff -ruN source-old/xf86drmMode.c source/xf86drmMode.c --- source-old/xf86drmMode.c +++ source/xf86drmMode.c @@ -50,6 +50,7 @@ #include "libdrm_macros.h" #include "xf86drmMode.h" #include "xf86drm.h" +#include "xf86drm_redox.h" #include #include #include @@ -68,6 +69,212 @@ return ret < 0 ? -errno : ret; } +static void* drmAllocCpy(char *array, int count, int entry_size); + +#if defined(__redox__) +static void redox_drm_mode_from_wire(drmModeModeInfoPtr mode, + const struct redox_drm_mode_wire *wire, + const char *name) +{ + memclear(*mode); + mode->clock = wire->clock; + mode->hdisplay = wire->hdisplay; + mode->hsync_start = wire->hsync_start; + mode->hsync_end = wire->hsync_end; + mode->htotal = wire->htotal; + mode->hskew = wire->hskew; + mode->vdisplay = wire->vdisplay; + mode->vsync_start = wire->vsync_start; + mode->vsync_end = wire->vsync_end; + mode->vtotal = wire->vtotal; + mode->vscan = wire->vscan; + mode->vrefresh = wire->vrefresh; + mode->flags = wire->flags; + mode->type = wire->type; + if (name) { + size_t name_len = strlen(name); + if (name_len >= DRM_DISPLAY_MODE_LEN) + name_len = DRM_DISPLAY_MODE_LEN - 1; + memcpy(mode->name, name, name_len); + } +} + +static void redox_drm_mode_to_wire(struct redox_drm_mode_wire *wire, + const drmModeModeInfo *mode) +{ + memclear(*wire); + wire->clock = mode->clock; + wire->hdisplay = mode->hdisplay; + wire->hsync_start = mode->hsync_start; + wire->hsync_end = mode->hsync_end; + wire->htotal = mode->htotal; + wire->hskew = mode->hskew; + wire->vdisplay = mode->vdisplay; + wire->vsync_start = mode->vsync_start; + wire->vsync_end = mode->vsync_end; + wire->vtotal = mode->vtotal; + wire->vscan = mode->vscan; + wire->vrefresh = mode->vrefresh; + wire->flags = mode->flags; + wire->type = mode->type; +} + +static int redox_drm_fetch_resources(int fd, + struct redox_drm_resources_wire *header, + uint32_t **connector_ids) +{ + void *response = NULL; + size_t response_size = 0; + size_t expected_size; + + if (redox_drm_exchange_alloc(fd, REDOX_DRM_IOCTL_MODE_GETRESOURCES, + NULL, 0, + &response, &response_size) != 0) { + return -1; + } + + if (response_size < sizeof(*header)) { + drmFree(response); + errno = EPROTO; + return -1; + } + + memcpy(header, response, sizeof(*header)); + expected_size = sizeof(*header) + + ((size_t)header->connector_count * sizeof(uint32_t)); + if (response_size < expected_size) { + drmFree(response); + errno = EPROTO; + return -1; + } + + *connector_ids = NULL; + if (header->connector_count != 0) { + *connector_ids = drmAllocCpy((char *)response + sizeof(*header), + header->connector_count, sizeof(uint32_t)); + if (!*connector_ids) { + drmFree(response); + errno = ENOMEM; + return -1; + } + } + + drmFree(response); + return 0; +} + +static int redox_drm_parse_connector_response(const void *blob, size_t blob_size, + struct redox_drm_connector_wire *header, + drmModeModeInfoPtr *modes_out) +{ + const uint8_t *bytes = blob; + drmModeModeInfoPtr modes = NULL; + size_t offset = sizeof(*header); + uint32_t i; + + if (blob_size < sizeof(*header)) { + errno = EPROTO; + return -1; + } + + memcpy(header, bytes, sizeof(*header)); + if (header->mode_count != 0) { + modes = drmMalloc(header->mode_count * sizeof(*modes)); + if (!modes) { + errno = ENOMEM; + return -1; + } + } + + for (i = 0; i < header->mode_count; ++i) { + struct redox_drm_mode_wire mode_wire; + const char *name; + size_t name_len; + + if (blob_size - offset < sizeof(mode_wire)) { + drmFree(modes); + errno = EPROTO; + return -1; + } + + memcpy(&mode_wire, bytes + offset, sizeof(mode_wire)); + offset += sizeof(mode_wire); + name = (const char *)bytes + offset; + name_len = strnlen(name, blob_size - offset); + if (offset + name_len >= blob_size) { + drmFree(modes); + errno = EPROTO; + return -1; + } + + redox_drm_mode_from_wire(&modes[i], &mode_wire, name); + offset += name_len + 1; + } + + *modes_out = modes; + return 0; +} + +static int redox_drm_fetch_connector(int fd, uint32_t connector_id, + struct redox_drm_connector_wire *header, + drmModeModeInfoPtr *modes_out) +{ + void *response = NULL; + size_t response_size = 0; + int ret; + + if (redox_drm_exchange_alloc(fd, REDOX_DRM_IOCTL_MODE_GETCONNECTOR, + &connector_id, sizeof(connector_id), + &response, &response_size) != 0) { + return -1; + } + + ret = redox_drm_parse_connector_response(response, response_size, + header, modes_out); + drmFree(response); + return ret; +} + +static uint32_t redox_drm_connector_type_id(int fd, uint32_t connector_id, + uint32_t connector_type) +{ + struct redox_drm_resources_wire resources; + uint32_t *connector_ids = NULL; + uint32_t ordinal = 0; + uint32_t i; + + if (redox_drm_fetch_resources(fd, &resources, &connector_ids) != 0) + return 0; + + for (i = 0; i < resources.connector_count; ++i) { + struct redox_drm_connector_wire header; + drmModeModeInfoPtr modes = NULL; + + if (redox_drm_fetch_connector(fd, connector_ids[i], &header, &modes) != 0) + break; + drmFree(modes); + + if (header.connector_type == connector_type) + ++ordinal; + if (header.connector_id == connector_id) + break; + } + + drmFree(connector_ids); + return ordinal; +} + +static int redox_drm_page_flip_unsupported(uint32_t flags) +{ + if (flags & (DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET)) { + errno = EOPNOTSUPP; + return -1; + } + + return 0; +} +#endif + /* * Util functions */ @@ -153,16 +360,104 @@ drm_public int drmIsKMS(int fd) { + #if defined(__redox__) + struct redox_drm_resources_wire resources; + uint32_t *connector_ids = NULL; + int is_kms; + + if (redox_drm_fetch_resources(fd, &resources, &connector_ids) != 0) + return 0; + + is_kms = resources.crtc_count > 0 && + resources.connector_count > 0 && + resources.encoder_count > 0; + drmFree(connector_ids); + return is_kms; + #else struct drm_mode_card_res res = {0}; if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res) != 0) return 0; return res.count_crtcs > 0 && res.count_connectors > 0 && res.count_encoders > 0; + #endif } drm_public drmModeResPtr drmModeGetResources(int fd) { + #if defined(__redox__) + struct redox_drm_resources_wire resources; + uint32_t *connector_ids = NULL; + drmModeResPtr r = NULL; + uint32_t i; + + if (redox_drm_fetch_resources(fd, &resources, &connector_ids) != 0) + return NULL; + + r = drmMalloc(sizeof(*r)); + if (!r) { + drmFree(connector_ids); + return NULL; + } + memclear(*r); + + r->count_connectors = resources.connector_count; + r->count_crtcs = resources.crtc_count; + r->count_encoders = resources.encoder_count; + r->connectors = connector_ids; + + if (resources.crtc_count != 0) { + r->crtcs = drmMalloc(resources.crtc_count * sizeof(*r->crtcs)); + if (!r->crtcs) + goto err_allocs; + for (i = 0; i < resources.crtc_count; ++i) + r->crtcs[i] = i + 1; + } + + if (resources.encoder_count != 0) { + r->encoders = drmMalloc(resources.encoder_count * sizeof(*r->encoders)); + if (!r->encoders) + goto err_allocs; + memset(r->encoders, 0, resources.encoder_count * sizeof(*r->encoders)); + } + + for (i = 0; i < resources.connector_count; ++i) { + struct redox_drm_connector_wire connector; + drmModeModeInfoPtr modes = NULL; + uint32_t j; + + if (redox_drm_fetch_connector(fd, connector_ids[i], &connector, &modes) != 0) + goto err_allocs; + + if (i < resources.encoder_count) + r->encoders[i] = connector.encoder_id; + + for (j = 0; j < connector.mode_count; ++j) { + uint32_t width = modes[j].hdisplay; + uint32_t height = modes[j].vdisplay; + if (r->min_width == 0 || width < r->min_width) + r->min_width = width; + if (width > r->max_width) + r->max_width = width; + if (r->min_height == 0 || height < r->min_height) + r->min_height = height; + if (height > r->max_height) + r->max_height = height; + } + drmFree(modes); + } + + if (resources.encoder_count > resources.connector_count) { + for (i = resources.connector_count; i < resources.encoder_count; ++i) + r->encoders[i] = 0; + } + + return r; + +err_allocs: + drmModeFreeResources(r); + return NULL; + #else struct drm_mode_card_res res, counts; drmModeResPtr r = 0; @@ -253,6 +548,7 @@ drmFree(U642VOID(res.encoder_id_ptr)); return r; + #endif } @@ -260,6 +556,26 @@ uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id) { + #if defined(__redox__) + struct redox_drm_add_fb_wire wire; + + memclear(wire); + wire.width = width; + wire.height = height; + wire.pitch = pitch; + wire.bpp = bpp; + wire.depth = depth; + wire.handle = bo_handle; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_ADDFB, + &wire, sizeof(wire), + &wire, sizeof(wire), + NULL) != 0) { + return -errno; + } + + *buf_id = wire.fb_id; + return 0; + #else struct drm_mode_fb_cmd f; int ret; @@ -276,6 +592,7 @@ *buf_id = f.fb_id; return 0; + #endif } drm_public int drmModeAddFB2WithModifiers(int fd, uint32_t width, @@ -317,7 +634,22 @@ drm_public int drmModeRmFB(int fd, uint32_t bufferId) { + #if defined(__redox__) + struct redox_drm_rm_fb_wire wire; + + memclear(wire); + wire.fb_id = bufferId; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_RMFB, + &wire, sizeof(wire), + NULL, 0, + NULL) != 0) { + return -errno; + } + + return 0; + #else return DRM_IOCTL(fd, DRM_IOCTL_MODE_RMFB, &bufferId); + #endif } drm_public int drmModeCloseFB(int fd, uint32_t buffer_id) @@ -374,6 +706,40 @@ drm_public drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) { + #if defined(__redox__) + struct redox_drm_get_crtc_wire wire; + drmModeCrtcPtr r; + + memclear(wire); + wire.crtc_id = crtcId; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_GETCRTC, + &wire, sizeof(wire), + &wire, sizeof(wire), + NULL) != 0) { + return NULL; + } + + r = drmMalloc(sizeof(*r)); + if (!r) + return NULL; + + memclear(*r); + r->crtc_id = wire.crtc_id; + r->x = wire.x; + r->y = wire.y; + r->mode_valid = wire.mode_valid; + if (r->mode_valid) { + char mode_name[DRM_DISPLAY_MODE_LEN]; + snprintf(mode_name, sizeof(mode_name), "%ux%u@%u", + wire.mode.hdisplay, wire.mode.vdisplay, wire.mode.vrefresh); + redox_drm_mode_from_wire(&r->mode, &wire.mode, mode_name); + r->width = wire.mode.hdisplay; + r->height = wire.mode.vdisplay; + } + r->buffer_id = wire.fb_id; + r->gamma_size = 0; + return r; + #else struct drm_mode_crtc crtc; drmModeCrtcPtr r; @@ -402,12 +768,47 @@ r->buffer_id = crtc.fb_id; r->gamma_size = crtc.gamma_size; return r; + #endif } drm_public int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode) { + #if defined(__redox__) + struct redox_drm_set_crtc_wire wire; + + if ((x != 0 || y != 0) && bufferId != 0) { + errno = EOPNOTSUPP; + return -errno; + } + if (count < 0 || count > 8) { + errno = EINVAL; + return -errno; + } + if (bufferId != 0 && !mode) { + errno = EINVAL; + return -errno; + } + + memclear(wire); + wire.crtc_id = crtcId; + wire.fb_handle = bufferId; + wire.connector_count = count; + if (count > 0) + memcpy(wire.connectors, connectors, count * sizeof(*connectors)); + if (mode) + redox_drm_mode_to_wire(&wire.mode, mode); + + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_SETCRTC, + &wire, sizeof(wire), + NULL, 0, + NULL) != 0) { + return -errno; + } + + return 0; + #else struct drm_mode_crtc crtc; memclear(crtc); @@ -423,6 +824,7 @@ } return DRM_IOCTL(fd, DRM_IOCTL_MODE_SETCRTC, &crtc); + #endif } /* @@ -480,6 +882,30 @@ */ drm_public drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) { + #if defined(__redox__) + struct drm_mode_get_encoder enc; + drmModeEncoderPtr r = NULL; + + memclear(enc); + enc.encoder_id = encoder_id; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_GETENCODER, + &enc, sizeof(enc), + &enc, sizeof(enc), + NULL) != 0) { + return NULL; + } + + r = drmMalloc(sizeof(*r)); + if (!r) + return NULL; + + r->encoder_id = enc.encoder_id; + r->crtc_id = enc.crtc_id; + r->encoder_type = enc.encoder_type; + r->possible_crtcs = enc.possible_crtcs; + r->possible_clones = enc.possible_clones; + return r; + #else struct drm_mode_get_encoder enc; drmModeEncoderPtr r = NULL; @@ -499,6 +925,7 @@ r->possible_clones = enc.possible_clones; return r; + #endif } /* @@ -507,6 +934,50 @@ static drmModeConnectorPtr _drmModeGetConnector(int fd, uint32_t connector_id, int probe) { + #if defined(__redox__) + struct redox_drm_connector_wire conn; + drmModeConnectorPtr r = NULL; + drmModeModeInfoPtr modes = NULL; + + (void)probe; + if (redox_drm_fetch_connector(fd, connector_id, &conn, &modes) != 0) + return NULL; + + r = drmMalloc(sizeof(*r)); + if (!r) + goto err_allocs; + memclear(*r); + + r->connector_id = conn.connector_id; + r->encoder_id = conn.encoder_id; + r->connection = conn.connection; + r->mmWidth = conn.mm_width; + r->mmHeight = conn.mm_height; + r->subpixel = DRM_MODE_SUBPIXEL_UNKNOWN; + r->count_modes = conn.mode_count; + r->modes = modes; + r->count_props = 0; + r->props = NULL; + r->prop_values = NULL; + r->count_encoders = conn.encoder_id ? 1 : 0; + if (r->count_encoders != 0) { + r->encoders = drmMalloc(sizeof(*r->encoders)); + if (!r->encoders) + goto err_allocs; + r->encoders[0] = conn.encoder_id; + } + r->connector_type = conn.connector_type; + r->connector_type_id = redox_drm_connector_type_id(fd, + conn.connector_id, + conn.connector_type); + return r; + +err_allocs: + drmFree(modes); + drmFree(r ? r->encoders : NULL); + drmFree(r); + return NULL; + #else struct drm_mode_get_connector conn, counts; drmModeConnectorPtr r = NULL; struct drm_mode_modeinfo stack_mode; @@ -608,6 +1079,7 @@ drmFree(U642VOID(conn.encoders_ptr)); return r; + #endif } drm_public drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connector_id) @@ -1100,6 +1572,27 @@ drm_public int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data) { + #if defined(__redox__) + struct redox_drm_page_flip_wire flip; + uint64_t sequence; + + (void)user_data; + if (redox_drm_page_flip_unsupported(flags) != 0) + return -errno; + + memclear(flip); + flip.fb_handle = fb_id; + flip.crtc_id = crtc_id; + flip.flags = flags; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_PAGE_FLIP, + &flip, sizeof(flip), + &sequence, sizeof(sequence), + NULL) != 0) { + return -errno; + } + + return 0; + #else struct drm_mode_crtc_page_flip flip; memclear(flip); @@ -1109,12 +1602,23 @@ flip.flags = flags; return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip); + #endif } drm_public int drmModePageFlipTarget(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data, uint32_t target_vblank) { + #if defined(__redox__) + (void)fd; + (void)crtc_id; + (void)fb_id; + (void)flags; + (void)user_data; + (void)target_vblank; + errno = EOPNOTSUPP; + return -errno; + #else struct drm_mode_crtc_page_flip_target flip_target; memclear(flip_target); @@ -1125,6 +1629,7 @@ flip_target.sequence = target_vblank; return DRM_IOCTL(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip_target); + #endif } drm_public int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, @@ -1839,6 +2344,26 @@ uint32_t flags, uint32_t *handle, uint32_t *pitch, uint64_t *size) { + #if defined(__redox__) + struct redox_drm_create_dumb_wire create; + + memclear(create); + create.width = width; + create.height = height; + create.bpp = bpp; + create.flags = flags; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_CREATE_DUMB, + &create, sizeof(create), + &create, sizeof(create), + NULL) != 0) { + return -errno; + } + + *handle = create.handle; + *pitch = create.pitch; + *size = create.size; + return 0; + #else int ret; struct drm_mode_create_dumb create = { .width = width, @@ -1855,21 +2380,52 @@ *pitch = create.pitch; *size = create.size; return 0; + #endif } drm_public int drmModeDestroyDumbBuffer(int fd, uint32_t handle) { + #if defined(__redox__) + struct redox_drm_destroy_dumb_wire destroy; + + memclear(destroy); + destroy.handle = handle; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_DESTROY_DUMB, + &destroy, sizeof(destroy), + NULL, 0, + NULL) != 0) { + return -errno; + } + + return 0; + #else struct drm_mode_destroy_dumb destroy = { .handle = handle, }; return DRM_IOCTL(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy); + #endif } drm_public int drmModeMapDumbBuffer(int fd, uint32_t handle, uint64_t *offset) { + #if defined(__redox__) + struct redox_drm_map_dumb_wire map; + + memclear(map); + map.handle = handle; + if (redox_drm_exchange(fd, REDOX_DRM_IOCTL_MODE_MAP_DUMB, + &map, sizeof(map), + &map, sizeof(map), + NULL) != 0) { + return -errno; + } + + *offset = map.offset; + return 0; + #else int ret; struct drm_mode_map_dumb map = { .handle = handle, @@ -1881,4 +2437,5 @@ *offset = map.offset; return 0; + #endif } diff -ruN source-old/xf86drm_redox.h source/xf86drm_redox.h --- source-old/xf86drm_redox.h +++ source/xf86drm_redox.h @@ -0,0 +1,162 @@ +#ifndef _XF86DRM_REDOX_H_ +#define _XF86DRM_REDOX_H_ + +#if defined(__redox__) + +#include +#include + +#define REDOX_DRM_IOCTL_BASE 0x00A0UL + +#define REDOX_LINUX_IOCTL_NR(request) ((unsigned long)((request) & 0xffUL)) +#define REDOX_LINUX_IOCTL_SIZE(request) (((unsigned long)(request) >> 16) & 0x3fffUL) + +#define REDOX_DRM_IOCTL_MODE_GETRESOURCES (REDOX_DRM_IOCTL_BASE + 0) +#define REDOX_DRM_IOCTL_MODE_SETCRTC (REDOX_DRM_IOCTL_BASE + 2) +#define REDOX_DRM_IOCTL_MODE_GETCRTC (REDOX_DRM_IOCTL_BASE + 3) +#define REDOX_DRM_IOCTL_MODE_GETENCODER (REDOX_DRM_IOCTL_BASE + 6) +#define REDOX_DRM_IOCTL_MODE_GETCONNECTOR (REDOX_DRM_IOCTL_BASE + 7) +#define REDOX_DRM_IOCTL_MODE_PAGE_FLIP (REDOX_DRM_IOCTL_BASE + 16) +#define REDOX_DRM_IOCTL_MODE_CREATE_DUMB (REDOX_DRM_IOCTL_BASE + 18) +#define REDOX_DRM_IOCTL_MODE_MAP_DUMB (REDOX_DRM_IOCTL_BASE + 19) +#define REDOX_DRM_IOCTL_MODE_DESTROY_DUMB (REDOX_DRM_IOCTL_BASE + 20) +#define REDOX_DRM_IOCTL_MODE_ADDFB (REDOX_DRM_IOCTL_BASE + 21) +#define REDOX_DRM_IOCTL_MODE_RMFB (REDOX_DRM_IOCTL_BASE + 22) +#define REDOX_DRM_IOCTL_GET_CAP (REDOX_DRM_IOCTL_BASE + 23) +#define REDOX_DRM_IOCTL_SET_CLIENT_CAP (REDOX_DRM_IOCTL_BASE + 24) +#define REDOX_DRM_IOCTL_VERSION (REDOX_DRM_IOCTL_BASE + 25) +#define REDOX_DRM_IOCTL_GEM_CLOSE (REDOX_DRM_IOCTL_BASE + 27) +#define REDOX_DRM_IOCTL_PRIME_HANDLE_TO_FD (REDOX_DRM_IOCTL_BASE + 29) +#define REDOX_DRM_IOCTL_PRIME_FD_TO_HANDLE (REDOX_DRM_IOCTL_BASE + 30) + +struct redox_drm_resources_wire { + uint32_t connector_count; + uint32_t crtc_count; + uint32_t encoder_count; +}; + +struct redox_drm_connector_wire { + uint32_t connector_id; + uint32_t connection; + uint32_t connector_type; + uint32_t mm_width; + uint32_t mm_height; + uint32_t encoder_id; + uint32_t mode_count; +}; + +struct redox_drm_mode_wire { + uint32_t clock; + uint16_t hdisplay; + uint16_t hsync_start; + uint16_t hsync_end; + uint16_t htotal; + uint16_t hskew; + uint16_t vdisplay; + uint16_t vsync_start; + uint16_t vsync_end; + uint16_t vtotal; + uint16_t vscan; + uint32_t vrefresh; + uint32_t flags; + uint32_t type; +}; + +struct redox_drm_set_crtc_wire { + uint32_t crtc_id; + uint32_t fb_handle; + uint32_t connector_count; + uint32_t connectors[8]; + struct redox_drm_mode_wire mode; +}; + +struct redox_drm_page_flip_wire { + uint32_t crtc_id; + uint32_t fb_handle; + uint32_t flags; +}; + +struct redox_drm_create_dumb_wire { + uint32_t width; + uint32_t height; + uint32_t bpp; + uint32_t flags; + uint32_t pitch; + uint32_t reserved0; + uint64_t size; + uint32_t handle; + uint32_t reserved1; +}; + +struct redox_drm_map_dumb_wire { + uint32_t handle; + uint32_t pad; + uint64_t offset; +}; + +struct redox_drm_destroy_dumb_wire { + uint32_t handle; +}; + +struct redox_drm_add_fb_wire { + uint32_t width; + uint32_t height; + uint32_t pitch; + uint32_t bpp; + uint32_t depth; + uint32_t handle; + uint32_t fb_id; +}; + +struct redox_drm_rm_fb_wire { + uint32_t fb_id; +}; + +struct redox_drm_get_crtc_wire { + uint32_t crtc_id; + uint32_t fb_id; + uint32_t x; + uint32_t y; + uint32_t mode_valid; + struct redox_drm_mode_wire mode; +}; + +struct redox_drm_version_wire { + int32_t major; + int32_t minor; + int32_t patch; +}; + +struct redox_drm_prime_handle_to_fd_wire { + uint32_t handle; + uint32_t flags; +}; + +struct redox_drm_prime_handle_to_fd_response_wire { + int32_t fd; + uint32_t pad; +}; + +struct redox_drm_prime_fd_to_handle_wire { + int32_t fd; + uint32_t pad; +}; + +struct redox_drm_prime_fd_to_handle_response_wire { + uint32_t handle; + uint32_t pad; +}; + +unsigned long redox_translate_request(unsigned long linux_nr); +int redox_drm_simple_ioctl(int fd, unsigned long request, void *arg); +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); +int redox_drm_exchange_alloc(int fd, unsigned long request_code, + const void *payload, size_t payload_size, + void **response, size_t *response_size); + +#endif + +#endif