X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=xf86drm.c;h=dbb7c14bf6af5c547631cdf0aa8db10ae58db2ae;hb=c7ed900d0188d72084fe30a57d111872d12462ad;hp=db9823daf392135d24331250628ce9bfcf234069;hpb=e321dd7a4db361b0c3d56ce93d93b7b59d7bb3c8;p=platform%2Fupstream%2Flibdrm.git diff --git a/xf86drm.c b/xf86drm.c index db9823d..dbb7c14 100644 --- a/xf86drm.c +++ b/xf86drm.c @@ -122,6 +122,23 @@ struct drm_pciinfo { static drmServerInfoPtr drm_server_info; static bool drmNodeIsDRM(int maj, int min); +static char *drmGetMinorNameForFD(int fd, int type); + +static unsigned log2_int(unsigned x) +{ + unsigned l; + + if (x < 2) { + return 0; + } + for (l = 2; ; l++) { + if ((unsigned)(1 << l) > x) { + return l - 1; + } + } + return 0; +} + drm_public void drmSetServerInfo(drmServerInfoPtr info) { @@ -695,7 +712,7 @@ static int drmOpenByName(const char *name, int type) int retcode; sprintf(proc_name, "/proc/dri/%d/name", i); - if ((fd = open(proc_name, 0, 0)) >= 0) { + if ((fd = open(proc_name, O_RDONLY, 0)) >= 0) { retcode = read(fd, buf, sizeof(buf)-1); close(fd); if (retcode) { @@ -2776,24 +2793,16 @@ drm_public char *drmGetDeviceNameFromFd(int fd) { #ifdef __FreeBSD__ struct stat sbuf; - char dname[SPECNAMELEN]; - char name[SPECNAMELEN]; int maj, min; + int nodetype; if (fstat(fd, &sbuf)) return NULL; maj = major(sbuf.st_rdev); min = minor(sbuf.st_rdev); - - if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) - return NULL; - - if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname))) - return NULL; - - snprintf(name, sizeof(name), "/dev/%s", dname); - return strdup(name); + nodetype = drmGetMinorType(maj, min); + return drmGetMinorNameForFD(fd, nodetype); #else char name[128]; struct stat sbuf; @@ -2829,7 +2838,7 @@ static bool drmNodeIsDRM(int maj, int min) snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm", maj, min); return stat(path, &sbuf) == 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) char name[SPECNAMELEN]; if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name))) @@ -2942,12 +2951,12 @@ static char *drmGetMinorNameForFD(int fd, int type) closedir(sysdir); return NULL; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) struct stat sbuf; char dname[SPECNAMELEN]; const char *mname; char name[SPECNAMELEN]; - int id, maj, min; + int id, maj, min, nodetype, i; if (fstat(fd, &sbuf)) return NULL; @@ -2965,14 +2974,25 @@ static char *drmGetMinorNameForFD(int fd, int type) * FreeBSD on amd64/i386/powerpc external kernel modules create node in * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates * only device nodes in /dev/dri/ */ + + /* Get the node type represented by fd so we can deduce the target name */ + nodetype = drmGetMinorType(maj, min); + if (nodetype == -1) + return (NULL); mname = drmGetMinorName(type); - if (sscanf(dname, "drm/%d", &id) != 1) { - snprintf(name, sizeof(name), "dri/%s", mname); - if (strncmp(name, dname, strlen(name)) != 0) - return NULL; - snprintf(name, sizeof(name), "/dev/%s", dname); - } else - snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, id); + + for (i = 0; i < SPECNAMELEN; i++) { + if (isalpha(dname[i]) == 0 && dname[i] != '/') + break; + } + if (dname[i] == '\0') + return (NULL); + + id = (int)strtol(&dname[i], NULL, 10); + id -= drmGetMinorBase(nodetype); + snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname, + id + drmGetMinorBase(type)); + return strdup(name); #else struct stat sbuf; @@ -3103,15 +3123,18 @@ static int drmParseSubsystemType(int maj, int min) int subsystem_type; snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); - if (!realpath(path, real_path)) - return -errno; - snprintf(path, sizeof(path), "%s", real_path); subsystem_type = get_subsystem_type(path); + /* Try to get the parent (underlying) device type */ if (subsystem_type == DRM_BUS_VIRTIO) { + /* Assume virtio-pci on error */ + if (!realpath(path, real_path)) + return DRM_BUS_VIRTIO; strncat(path, "/..", PATH_MAX); subsystem_type = get_subsystem_type(path); - } + if (subsystem_type < 0) + return DRM_BUS_VIRTIO; + } return subsystem_type; #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__) return DRM_BUS_PCI; @@ -3248,7 +3271,7 @@ static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info) info->func = pinfo.func; return 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) return get_sysctl_pci_bus_info(maj, min, info); #else #warning "Missing implementation of drmParsePciBusInfo" @@ -3417,7 +3440,7 @@ static int drmParsePciDeviceInfo(int maj, int min, device->subdevice_id = pinfo.subdevice_id; return 0; -#elif __FreeBSD__ +#elif defined(__FreeBSD__) drmPciBusInfo info; struct pci_conf_io pc; struct pci_match_conf patterns[1]; @@ -3608,6 +3631,46 @@ free_device: return ret; } +#ifdef __linux__ +static int drm_usb_dev_path(int maj, int min, char *path, size_t len) +{ + char *value, *tmp_path, *slash; + + snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min); + + value = sysfs_uevent_get(path, "DEVTYPE"); + if (!value) + return -ENOENT; + + if (strcmp(value, "usb_device") == 0) + return 0; + if (strcmp(value, "usb_interface") != 0) + return -ENOTSUP; + + /* The parent of a usb_interface is a usb_device */ + + tmp_path = realpath(path, NULL); + if (!tmp_path) + return -errno; + + slash = strrchr(tmp_path, '/'); + if (!slash) { + free(tmp_path); + return -EINVAL; + } + + *slash = '\0'; + + if (snprintf(path, len, "%s", tmp_path) >= (int)len) { + free(tmp_path); + return -EINVAL; + } + + free(tmp_path); + return 0; +} +#endif + static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) { #ifdef __linux__ @@ -3615,7 +3678,9 @@ static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info) unsigned int bus, dev; int ret; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; value = sysfs_uevent_get(path, "BUSNUM"); if (!value) @@ -3654,7 +3719,9 @@ static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info) unsigned int vendor, product; int ret; - snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min); + ret = drm_usb_dev_path(maj, min, path, sizeof(path)); + if (ret < 0) + return ret; value = sysfs_uevent_get(path, "PRODUCT"); if (!value) @@ -3920,6 +3987,7 @@ process_device(drmDevicePtr *device, const char *d_name, switch (subsystem_type) { case DRM_BUS_PCI: + case DRM_BUS_VIRTIO: return drmProcessPciDevice(device, node, node_type, maj, min, fetch_deviceinfo, flags); case DRM_BUS_USB: @@ -3949,7 +4017,7 @@ static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count) for (j = i + 1; j < count; j++) { 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); + node_type = log2_int(local_devices[j]->available_nodes); memcpy(local_devices[i]->nodes[node_type], local_devices[j]->nodes[node_type], drmGetMaxNodeName()); drmFreeDevice(&local_devices[j]); @@ -4250,7 +4318,7 @@ drm_public char *drmGetDeviceNameFromFd2(int fd) free(value); return strdup(path); -#elif __FreeBSD__ +#elif defined(__FreeBSD__) return drmGetDeviceNameFromFd(fd); #else struct stat sbuf;