X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=xf86drm.c;h=728ac78cf9634ac240ba8ad57836d5ecdfa28420;hb=7e6bf88cac315a9fa41818cf72a7b5d18a2cb1fc;hp=7766bfe937dbcc1b1519154a993e9ea141b7ce99;hpb=2e57bba870399926e1a0d0be3f4918a0a8432474;p=android-x86%2Fexternal-libdrm.git diff --git a/xf86drm.c b/xf86drm.c index 7766bfe9..728ac78c 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -994,8 +994,10 @@ char *drmGetBusid(int fd) if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) return NULL; u.unique = drmMalloc(u.unique_len + 1); - if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) + if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) { + drmFree(u.unique); return NULL; + } u.unique[u.unique_len] = '\0'; return u.unique; @@ -1523,14 +1525,12 @@ drm_context_t *drmGetReservedContextList(int fd, int *count) if (!(list = drmMalloc(res.count * sizeof(*list)))) return NULL; - if (!(retval = drmMalloc(res.count * sizeof(*retval)))) { - drmFree(list); - return NULL; - } + if (!(retval = drmMalloc(res.count * sizeof(*retval)))) + goto err_free_list; res.contexts = list; if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res)) - return NULL; + goto err_free_context; for (i = 0; i < res.count; i++) retval[i] = list[i].handle; @@ -1538,6 +1538,12 @@ drm_context_t *drmGetReservedContextList(int fd, int *count) *count = res.count; return retval; + +err_free_list: + drmFree(list); +err_free_context: + drmFree(retval); + return NULL; } void drmFreeReservedContextList(drm_context_t *pt) @@ -2886,6 +2892,50 @@ char *drmGetRenderDeviceNameFromFd(int fd) return drmGetMinorNameForFD(fd, DRM_NODE_RENDER); } +#ifdef __linux__ +static char * DRM_PRINTFLIKE(2, 3) +sysfs_uevent_get(const char *path, const char *fmt, ...) +{ + char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL; + size_t size = 0, len; + ssize_t num; + va_list ap; + FILE *fp; + + va_start(ap, fmt); + num = vasprintf(&key, fmt, ap); + va_end(ap); + len = num; + + snprintf(filename, sizeof(filename), "%s/uevent", path); + + fp = fopen(filename, "r"); + if (!fp) { + free(key); + return NULL; + } + + while ((num = getline(&line, &size, fp)) >= 0) { + if ((strncmp(line, key, len) == 0) && (line[len] == '=')) { + char *start = line + len + 1, *end = line + num - 1; + + if (*end != '\n') + end++; + + value = strndup(start, end - start); + break; + } + } + + free(line); + fclose(fp); + + free(key); + + return value; +} +#endif + static int drmParseSubsystemType(int maj, int min) { #ifdef __linux__ @@ -2906,6 +2956,15 @@ static int drmParseSubsystemType(int maj, int min) if (strncmp(name, "/pci", 4) == 0) return DRM_BUS_PCI; + if (strncmp(name, "/usb", 4) == 0) + return DRM_BUS_USB; + + if (strncmp(name, "/platform", 9) == 0) + return DRM_BUS_PLATFORM; + + if (strncmp(name, "/host1x", 7) == 0) + return DRM_BUS_HOST1X; + return -EINVAL; #elif defined(__OpenBSD__) return DRM_BUS_PCI; @@ -2918,32 +2977,21 @@ static int drmParseSubsystemType(int maj, int min) static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) { #ifdef __linux__ - char path[PATH_MAX + 1]; - char data[512 + 1]; - char *str; - int domain, bus, dev, func; - int fd, ret; + unsigned int domain, bus, dev, func; + char path[PATH_MAX + 1], *value; + int num; - snprintf(path, PATH_MAX, "/sys/dev/char/%d:%d/device/uevent", maj, min); - fd = open(path, O_RDONLY); - if (fd < 0) - return -errno; + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); - ret = read(fd, data, sizeof(data)-1); - close(fd); - if (ret < 0) - return -errno; - data[ret] = '\0'; + value = sysfs_uevent_get(path, "PCI_SLOT_NAME"); + if (!value) + return -ENOENT; -#define TAG "PCI_SLOT_NAME=" - str = strstr(data, TAG); - if (str == NULL) - return -EINVAL; + num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func); + free(value); - if (sscanf(str, TAG "%04x:%02x:%02x.%1u", - &domain, &bus, &dev, &func) != 4) + if (num != 4) return -EINVAL; -#undef TAG info->domain = domain; info->bus = bus; @@ -2981,22 +3029,32 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) #endif } -static int drmCompareBusInfo(drmDevicePtr a, drmDevicePtr b) +int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b) { if (a == NULL || b == NULL) - return -1; + return 0; if (a->bustype != b->bustype) - return -1; + return 0; switch (a->bustype) { case DRM_BUS_PCI: - return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)); + return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0; + + case DRM_BUS_USB: + return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0; + + case DRM_BUS_PLATFORM: + return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0; + + case DRM_BUS_HOST1X: + return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0; + default: break; } - return -1; + return 0; } static int drmGetNodeType(const char *name) @@ -3136,11 +3194,55 @@ static int drmParsePciDeviceInfo(int maj, int min, #endif } +static void drmFreePlatformDevice(drmDevicePtr device) +{ + if (device->deviceinfo.platform) { + if (device->deviceinfo.platform->compatible) { + char **compatible = device->deviceinfo.platform->compatible; + + while (*compatible) { + free(*compatible); + compatible++; + } + + free(device->deviceinfo.platform->compatible); + } + } +} + +static void drmFreeHost1xDevice(drmDevicePtr device) +{ + if (device->deviceinfo.host1x) { + if (device->deviceinfo.host1x->compatible) { + char **compatible = device->deviceinfo.host1x->compatible; + + while (*compatible) { + free(*compatible); + compatible++; + } + + free(device->deviceinfo.host1x->compatible); + } + } +} + void drmFreeDevice(drmDevicePtr *device) { if (device == NULL) return; + if (*device) { + switch ((*device)->bustype) { + case DRM_BUS_PLATFORM: + drmFreePlatformDevice(*device); + break; + + case DRM_BUS_HOST1X: + drmFreeHost1xDevice(*device); + break; + } + } + free(*device); *device = NULL; } @@ -3235,6 +3337,327 @@ free_device: return ret; } +static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int bus, dev; + int ret; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "BUSNUM"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%03u", &bus); + free(value); + + if (ret <= 0) + return -errno; + + value = sysfs_uevent_get(path, "DEVNUM"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%03u", &dev); + free(value); + + if (ret <= 0) + return -errno; + + info->bus = bus; + info->dev = dev; + + return 0; +#else +#warning "Missing implementation of drmParseUsbBusInfo" + return -EINVAL; +#endif +} + +static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int vendor, product; + int ret; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "PRODUCT"); + if (!value) + return -ENOENT; + + ret = sscanf(value, "%x/%x", &vendor, &product); + free(value); + + if (ret <= 0) + return -errno; + + info->vendor = vendor; + info->product = product; + + return 0; +#else +#warning "Missing implementation of drmParseUsbDeviceInfo" + return -EINVAL; +#endif +} + +static int drmProcessUsbDevice(drmDevicePtr *device, const char *node, + int node_type, int maj, int min, + bool fetch_deviceinfo, uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo), + sizeof(drmUsbDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_USB; + + dev->businfo.usb = (drmUsbBusInfoPtr)ptr; + + ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmUsbBusInfo); + dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr; + + ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +static int drmParsePlatformBusInfo(int maj, int min, drmPlatformBusInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *name; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + name = sysfs_uevent_get(path, "OF_FULLNAME"); + if (!name) + return -ENOENT; + + strncpy(info->fullname, name, DRM_PLATFORM_DEVICE_NAME_LEN); + info->fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0'; + free(name); + + return 0; +#else +#warning "Missing implementation of drmParsePlatformBusInfo" + return -EINVAL; +#endif +} + +static int drmParsePlatformDeviceInfo(int maj, int min, + drmPlatformDeviceInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int count, i; + int err; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); + if (!value) + return -ENOENT; + + sscanf(value, "%u", &count); + free(value); + + info->compatible = calloc(count + 1, sizeof(*info->compatible)); + if (!info->compatible) + return -ENOMEM; + + for (i = 0; i < count; i++) { + value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); + if (!value) { + err = -ENOENT; + goto free; + } + + info->compatible[i] = value; + } + + return 0; + +free: + while (i--) + free(info->compatible[i]); + + free(info->compatible); + return err; +#else +#warning "Missing implementation of drmParsePlatformDeviceInfo" + return -EINVAL; +#endif +} + +static int drmProcessPlatformDevice(drmDevicePtr *device, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo, + uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo), + sizeof(drmPlatformDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_PLATFORM; + + dev->businfo.platform = (drmPlatformBusInfoPtr)ptr; + + ret = drmParsePlatformBusInfo(maj, min, dev->businfo.platform); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmPlatformBusInfo); + dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr; + + ret = drmParsePlatformDeviceInfo(maj, min, dev->deviceinfo.platform); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + +static int drmParseHost1xBusInfo(int maj, int min, drmHost1xBusInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *name; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + name = sysfs_uevent_get(path, "OF_FULLNAME"); + if (!name) + return -ENOENT; + + strncpy(info->fullname, name, DRM_HOST1X_DEVICE_NAME_LEN); + info->fullname[DRM_HOST1X_DEVICE_NAME_LEN - 1] = '\0'; + free(name); + + return 0; +#else +#warning "Missing implementation of drmParseHost1xBusInfo" + return -EINVAL; +#endif +} + +static int drmParseHost1xDeviceInfo(int maj, int min, + drmHost1xDeviceInfoPtr info) +{ +#ifdef __linux__ + char path[PATH_MAX + 1], *value; + unsigned int count, i; + int err; + + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "OF_COMPATIBLE_N"); + if (!value) + return -ENOENT; + + sscanf(value, "%u", &count); + free(value); + + info->compatible = calloc(count + 1, sizeof(*info->compatible)); + if (!info->compatible) + return -ENOMEM; + + for (i = 0; i < count; i++) { + value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i); + if (!value) { + err = -ENOENT; + goto free; + } + + info->compatible[i] = value; + } + + return 0; + +free: + while (i--) + free(info->compatible[i]); + + free(info->compatible); + return err; +#else +#warning "Missing implementation of drmParseHost1xDeviceInfo" + return -EINVAL; +#endif +} + +static int drmProcessHost1xDevice(drmDevicePtr *device, + const char *node, int node_type, + int maj, int min, bool fetch_deviceinfo, + uint32_t flags) +{ + drmDevicePtr dev; + char *ptr; + int ret; + + dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo), + sizeof(drmHost1xDeviceInfo), &ptr); + if (!dev) + return -ENOMEM; + + dev->bustype = DRM_BUS_HOST1X; + + dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr; + + ret = drmParseHost1xBusInfo(maj, min, dev->businfo.host1x); + if (ret < 0) + goto free_device; + + if (fetch_deviceinfo) { + ptr += sizeof(drmHost1xBusInfo); + dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr; + + ret = drmParseHost1xDeviceInfo(maj, min, dev->deviceinfo.host1x); + if (ret < 0) + goto free_device; + } + + *device = dev; + + return 0; + +free_device: + free(dev); + return ret; +} + /* Consider devices located on the same bus as duplicate and fold the respective * entries into a single one. * @@ -3246,7 +3669,7 @@ static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) for (i = 0; i < count; i++) { for (j = i + 1; j < count; j++) { - if (drmCompareBusInfo(local_devices[i], local_devices[j]) == 0) { + if (drmDevicesEqual(local_devices[i], local_devices[j])) { local_devices[i]->available_nodes |= local_devices[j]->available_nodes; node_type = log2(local_devices[j]->available_nodes); memcpy(local_devices[i]->nodes[node_type], @@ -3410,6 +3833,28 @@ int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device) continue; break; + + case DRM_BUS_USB: + ret = drmProcessUsbDevice(&d, node, node_type, maj, min, true, flags); + if (ret) + continue; + + break; + + case DRM_BUS_PLATFORM: + ret = drmProcessPlatformDevice(&d, node, node_type, maj, min, true, flags); + if (ret) + continue; + + break; + + case DRM_BUS_HOST1X: + ret = drmProcessHost1xDevice(&d, node, node_type, maj, min, true, flags); + if (ret) + continue; + + break; + default: continue; } @@ -3541,6 +3986,31 @@ int drmGetDevices2(uint32_t flags, drmDevicePtr devices[], int max_devices) continue; break; + + case DRM_BUS_USB: + ret = drmProcessUsbDevice(&device, node, node_type, maj, min, + devices != NULL, flags); + if (ret) + goto free_devices; + + break; + + case DRM_BUS_PLATFORM: + ret = drmProcessPlatformDevice(&device, node, node_type, maj, min, + devices != NULL, flags); + if (ret) + goto free_devices; + + break; + + case DRM_BUS_HOST1X: + ret = drmProcessHost1xDevice(&device, node, node_type, maj, min, + devices != NULL, flags); + if (ret) + goto free_devices; + + break; + default: continue; } @@ -3609,13 +4079,8 @@ char *drmGetDeviceNameFromFd2(int fd) { #ifdef __linux__ struct stat sbuf; - char *device_name = NULL; + char path[PATH_MAX + 1], *value; unsigned int maj, min; - FILE *f; - char buf[512]; - static const char match[9] = "\nDEVNAME="; - size_t expected = 1; - if (fstat(fd, &sbuf)) return NULL; @@ -3626,30 +4091,16 @@ char *drmGetDeviceNameFromFd2(int fd) if (maj != DRM_MAJOR || !S_ISCHR(sbuf.st_mode)) return NULL; - snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/uevent", maj, min); - if (!(f = fopen(buf, "r"))) - return NULL; + snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min); - while (expected < sizeof(match)) { - int c = getc(f); - - if (c == EOF) { - fclose(f); - return NULL; - } else if (c == match[expected] ) - expected++; - else - expected = 0; - } + value = sysfs_uevent_get(path, "DEVNAME"); + if (!value) + return NULL; - strcpy(buf, "/dev/"); - if (fgets(buf + 5, sizeof(buf) - 5, f)) { - buf[strcspn(buf, "\n")] = '\0'; - device_name = strdup(buf); - } + snprintf(path, sizeof(path), "/dev/%s", value); + free(value); - fclose(f); - return device_name; + return strdup(path); #else struct stat sbuf; char node[PATH_MAX + 1];