├── .gitignore ├── AUTHORS ├── COPYING ├── Makefile.am ├── README ├── README.md ├── autogen.sh ├── configure.ac ├── doc └── libdevq.3 ├── include └── libdevq.h ├── src ├── freebsd │ ├── device.c │ ├── device_drm.c │ └── event_monitor_freebsd.c └── libdevq-1.0.pc.in └── tools ├── devq_evwatch └── devq_evwatch.c └── lsdri └── lsdri.c /.gitignore: -------------------------------------------------------------------------------- 1 | .sw? 2 | .*.sw? 3 | /ac-aux 4 | /aclocal.m4 5 | /autom4te.cache 6 | /configure 7 | /m4 8 | Makefile.in 9 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Baptiste Daroussin 2 | Jean-Sébastien Pédron 3 | Niclas Zeising 4 | Koop Mast 5 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | See the AUTHORS file to get the list of authors 2 | 3 | Copyright (c) 2014 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer 11 | in this position and unchanged. 12 | 2. Redistributions in binary form must reproduce the above copyright 13 | notice, this list of conditions and the following disclaimer in the 14 | documentation and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | 3 | include_HEADERS = include/libdevq.h 4 | 5 | lib_LTLIBRARIES = libdevq.la 6 | 7 | libdevq_la_SOURCES = src/freebsd/device.c \ 8 | src/freebsd/device_drm.c \ 9 | src/freebsd/event_monitor_freebsd.c 10 | 11 | libdevq_la_CPPFLAGS = -I$(top_srcdir)/include -DPREFIX="\"$(prefix)\"" 12 | 13 | if ENABLE_PROGRAMS 14 | bin_PROGRAMS = devq-lsdri devq-evwatch 15 | endif 16 | 17 | devq_evwatch_SOURCES = tools/devq_evwatch/devq_evwatch.c 18 | devq_evwatch_CPPFLAGS = -I$(top_srcdir)/include 19 | devq_evwatch_LDADD = libdevq.la 20 | 21 | devq_lsdri_SOURCES = tools/lsdri/lsdri.c 22 | devq_lsdri_CPPFLAGS = -I$(top_srcdir)/include 23 | devq_lsdri_LDADD = libdevq.la 24 | 25 | pkgconfigdir = $(libdir)/pkgconfig 26 | nodist_pkgconfig_DATA = src/libdevq-1.0.pc 27 | 28 | dist_man_MANS= doc/libdevq.3 29 | mandir= $(prefix)/man 30 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Generic Device Query and Monitor interface 2 | ========================================== 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Generic Device Query and Monitor interface 2 | ========================================== 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | autoreconf -i 3 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([libdevq],[0.0.4],[https://github.com/freebsd/libdevq],[libdevq]) 2 | AC_CONFIG_SRCDIR([configure.ac]) 3 | AC_CONFIG_AUX_DIR([ac-aux]) 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | AC_CANONICAL_TARGET 6 | 7 | AM_INIT_AUTOMAKE([1.11 foreign subdir-objects no-dist-gzip dist-xz]) 8 | AM_SILENT_RULES([yes]) 9 | 10 | LT_INIT([disable-static]) 11 | 12 | AC_PROG_CC_STDC 13 | 14 | case $target_os in 15 | freebsd*) opsys=freebsd ;; 16 | *) opsys=$target_os ;; 17 | esac 18 | 19 | AC_SUBST([opsys]) 20 | 21 | AC_CHECK_HEADERS([libprocstat.h], [ 22 | AC_SEARCH_LIBS([procstat_open_sysctl], [procstat]) 23 | ], [], [ 24 | #include 25 | #include 26 | #include 27 | ]) 28 | 29 | # ---------------------------------------------------------------------------- 30 | # Check if we want to build extra diagnostic programs 31 | 32 | AC_MSG_CHECKING([whether we should build diagnostic programs]) 33 | AC_ARG_ENABLE([programs], 34 | [AS_HELP_STRING([--enable-programs], 35 | [enable diagnose programs (default is no)])]) 36 | 37 | if test "$enable_programs" = "yes"; then 38 | AC_MSG_RESULT([yes]) 39 | else 40 | AC_MSG_RESULT([no]) 41 | fi 42 | 43 | AM_CONDITIONAL(ENABLE_PROGRAMS, test "$enable_programs" = "yes") 44 | 45 | # ---------------------------------------------------------------------------- 46 | 47 | AC_CONFIG_FILES([ 48 | Makefile 49 | src/libdevq-1.0.pc 50 | ]) 51 | 52 | AC_OUTPUT 53 | -------------------------------------------------------------------------------- /doc/libdevq.3: -------------------------------------------------------------------------------- 1 | .\" Copyright (c) 2015 Baptiste Daroussin 2 | .\" 2015 Koop Mast 3 | .\" Redistribution and use in source and binary forms, with or without 4 | .\" modification, are permitted provided that the following conditions 5 | .\" are met: 6 | .\" 1. Redistributions of source code must retain the above copyright 7 | .\" notice, this list of conditions and the following disclaimer. 8 | .\" 2. Redistributions in binary form must reproduce the above copyright 9 | .\" notice, this list of conditions and the following disclaimer in the 10 | .\" documentation and/or other materials provided with the distribution. 11 | .\" 12 | .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | .\" SUCH DAMAGE. 23 | .\" 24 | .Dd January 08, 2015 25 | .Dt LIBDEVQ 3 26 | .Os 27 | .Sh NAME 28 | .Nm libdevq 29 | .Nd Generic Device Query and Monitor interface 30 | .Sh LIBRARY 31 | Portable query and monitoring library (libdevq, -ldevq) 32 | .Sh SYNOPSIS 33 | .In sys/types.h 34 | .In libdevq.h 35 | .Ft devq_class_t 36 | .Fo devq_device_get_class 37 | .Fa "struct devq_device *device" 38 | .Fc 39 | .Ft const char * 40 | .Fo devq_device_get_devpath_from_fd 41 | .Fa "int fd" 42 | .Fa "char *path" 43 | .Fa "size_t *path_len" 44 | .Fc 45 | .Ft const char * 46 | .Fo devq_device_get_path 47 | .Fa "struct devq_device *device" 48 | .Fc 49 | .Ft int 50 | .Fo devq_device_get_pcibusaddr 51 | .Fa "int *domain" 52 | .Fa "int *bus" 53 | .Fa "int *slot" 54 | .Fa "int *function" 55 | .Fc 56 | .Ft int 57 | .Fo devq_device_get_pciid_from_fd 58 | .Fa "int fd" 59 | .Fa "int *vendor_id" 60 | .Fa "int *device_id" 61 | .Fc 62 | .Ft int 63 | .Fo devq_device_get_pciid_full_from_fd 64 | .Fa "int fd" 65 | .Fa "int *vendor_id" 66 | .Fa "int *device_id" 67 | .Fa "int *subvendor_id" 68 | .Fa "int *subdevice_id" 69 | .Fa "int *revision_id" 70 | .Fc 71 | .Ft const char * 72 | .Fo devq_device_get_product 73 | .Fa "struct devq_device *device" 74 | .Fc 75 | .Ft devq_device_t 76 | .Fo devq_device_get_type 77 | .Fa "struct devq_device *device" 78 | .Fc 79 | .Ft const char * 80 | .Fo devq_device_get_vendor 81 | .Fa "struct devq_device *device" 82 | .Fc 83 | .Ft int 84 | .Fo devq_drm_get_drvname_from_fd 85 | .Fa "int fd" 86 | .Fa "char *driver_name" 87 | .Fa "size_t *driver_name_len" 88 | .Fc 89 | .Ft const char * 90 | .Fo devq_event_dump 91 | .Fa "struct devq_event *" 92 | .Fc 93 | .Ft void 94 | .Fo devq_event_free 95 | .Fa "struct devq_event *" 96 | .Fc 97 | .Ft struct devq_device * 98 | .Fo devq_event_get_deviced 99 | .Fa "struct devq_event *" 100 | .Fc 101 | .Ft devq_event_t 102 | .Fo devq_event_get_type 103 | .Fa "struct devq_event *" 104 | .Fc 105 | .Ft void 106 | .Fo devq_event_monitor_fini 107 | .Fa "struct devq_evmon *" 108 | .Fc 109 | .Ft int 110 | .Fo devq_event_monitor_get_fd 111 | .Fa "struct devq_evmon *" 112 | .Fc 113 | .Ft struct devq_evmon * 114 | .Fo devq_event_monitor_init 115 | .Fa "void" 116 | .Fc 117 | .Ft int 118 | .Fo devq_event_monitor_poll 119 | .Fa "struct devq_evmon *" 120 | .Fc 121 | .Ft struct devq_event * 122 | .Fo devq_event_monitor_read 123 | .Fa "struct devq_evmon *" 124 | .Fc 125 | .Sh REFERENCE 126 | This section documents the functions, types, and variable available via 127 | .In libdevq.h . 128 | .Ss Types 129 | .Bl -ohang 130 | .It Vt "devq_class_t" 131 | A list of event class. Values are: 132 | .Bl -tag -width "DEVQ_CLASS_UNKNOWN" -compact -offset indent 133 | .It Em DEVQ_CLASS_UNKNOWN 134 | Unknown class 135 | .It Em DEVQ_CLASS_INPUT 136 | Input device class 137 | .El 138 | .It Vt "devq_device_t" 139 | A list of device types. Values are: 140 | .Bl -tag -width "DEVQ_DEVICE_TOUCHSCREEN" -compact -offset indent 141 | .It Em DEVQ_DEVICE_UNKNOWN 142 | Unknown device type 143 | .It Em DEVQ_DEVICE_KEYBOARD 144 | Device is a keyboard 145 | .It Em DEVQ_DEVICE_MOUSE 146 | Device is a mouse 147 | .It Em DEVQ_DEVICE_JOYSTICK 148 | Device is a joystick 149 | .It Em DEVQ_DEVICE_TOUCHPAD 150 | Device is a touchpad 151 | .It Em DEVQ_DEVICE_TOUCHSCREEN 152 | Device is a touchscreen 153 | .El 154 | .It Vt "devq_event_t" 155 | A list of event types. Values are: 156 | .Bl -tag -width "DEVQ_ATTACHED" -compact -offset indent 157 | .It Em DEVQ_ATTACHED 158 | A device have been attached 159 | .It Em DEVQ_DETACHED 160 | A device have been detached 161 | .It Em DEVQ_NOTICE 162 | An information is available 163 | .It Em DEVQ_UNKNOWN 164 | An unknown event has occured 165 | .El 166 | .It Vt "struct devq_device" 167 | An opaque structure representing a device 168 | .It Vt "struct devq_event" 169 | An opaque structure representing an event 170 | .It Vt "struct devq_evmon" 171 | An opaque structure representing an event monitor 172 | .El 173 | .Ss Functions 174 | Device query functions. 175 | .Bl -ohang 176 | .It Fn devq_device_get_pcibusaddr 177 | Return the pci bus location: domain, bus, slot and function. 178 | .Sy Currently 179 | only for DRM devices. 180 | .It Fn devq_device_get_devpath_from_fd 181 | Returns the absolute path of the device. 182 | .It Fn devq_device_get_pciid_full_from_fd 183 | Return the vendor_id, device_id, subvendor_id, subdevice_id and revision_id 184 | of the supplied fd. 185 | .Sy Currently 186 | only for DRM devices. 187 | .It Fn devq_device_get_pciid_from_fd 188 | Return the vendor_id and device_id of the supplied fd. 189 | .Sy Currently 190 | only for DRM devices. 191 | .It Fn devq_drm_get_drvname_from_fd 192 | Returns the driver name. 193 | .Pp 194 | Device notification API 195 | .It Fn devq_event_dump 196 | Returns the raw devq_event content. 197 | .It Fn devq_event_free 198 | Frees the devq_event struct. 199 | .It Fn devq_event_monitor_init 200 | function setups the monitoring code. 201 | .It Fn devq_event_monitor_fini 202 | function cleanup the event monitering code. 203 | .It Fn devq_event_monitor_get_fd 204 | Return the fd of the devq_evmon. 205 | .It Fn devq_event_monitor_poll 206 | Returns 1 if there are events waiting, otherwise 0. 207 | .It Fn devq_event_monitor_read 208 | Returns a devq_event struct otherwise NULL. 209 | .It Fn devq_event_get_type 210 | Returns what kind of event this is. 211 | .It Fn devq_event_get_deviced 212 | Returns information about the device on ATTACH or DETACH events. Otherwise NULL. 213 | .It Fn devq_device_get_type 214 | Returns the type of the device the event is about. 215 | .It Fn devq_device_get_class 216 | Return the device class for a given device. 217 | .It Fn devq_device_get_path 218 | Return the absolute path of the device. 219 | .It Fn devq_device_get_product 220 | Return the product of the device the event is about. 221 | .It Fn devq_device_get_vendor 222 | Return the vendor of the device the event is about. 223 | .El 224 | .Sh EXAMPLES 225 | fill me... 226 | .Sh Return values 227 | .Rv -std 228 | .Sh ERRORS 229 | The functions in 230 | .Fn libdevq 231 | may fail with the following errors: 232 | .Bl -tag -width Er 233 | .It Bq Er EBADF 234 | Bad File Descriptor 235 | .It Bq Er ENOMEM 236 | Cannot allocate memory 237 | .It Bq Er ENOENT 238 | No such file or directory 239 | .It Bq Er EINVAL 240 | Invalid argument 241 | .El 242 | .Sh SEE ALSO 243 | .Xr devinfo 3 , 244 | .Xr devctl 4 , 245 | .Xr devclass 9 246 | .Sh AUTHORS 247 | The 248 | .Nm 249 | library was written by: 250 | .Pp 251 | .An Baptiste Daroussin Aq Mt bapt@FreeBSD.org , 252 | .An Jean-S\['e]bastien P\['e]dron Aq Mt dumbbell@FreeBSD.org , 253 | .An Koop Mast Aq Mt kwm@FreeBSD.org 254 | -------------------------------------------------------------------------------- /include/libdevq.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jean-Sebastien Pedron 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef _LIBDEVQ_H_ 28 | #define _LIBDEVQ_H_ 29 | 30 | #define DEVQ_MAX_DEVS 16 31 | 32 | typedef enum { 33 | DEVQ_ATTACHED = 1U, 34 | DEVQ_DETACHED, 35 | DEVQ_NOTICE, 36 | DEVQ_UNKNOWN 37 | } devq_event_t; 38 | 39 | typedef enum { 40 | DEVQ_DEVICE_UNKNOWN = 1U, 41 | DEVQ_DEVICE_KEYBOARD, 42 | DEVQ_DEVICE_MOUSE, 43 | DEVQ_DEVICE_JOYSTICK, 44 | DEVQ_DEVICE_TOUCHPAD, 45 | DEVQ_DEVICE_TOUCHSCREEN 46 | } devq_device_t; 47 | 48 | typedef enum { 49 | DEVQ_CLASS_UNKNOWN = 1U, 50 | DEVQ_CLASS_INPUT 51 | } devq_class_t; 52 | 53 | struct devq_evmon; 54 | struct devq_event; 55 | struct devq_device; 56 | 57 | int devq_device_get_devpath_from_fd(int fd, 58 | char *path, size_t *path_len); 59 | int devq_device_get_pciid_from_fd(int fd, 60 | int *vendor_id, int *device_id); 61 | int devq_device_get_pciid_full_from_fd(int fd, 62 | int *vendor_id, int *device_id, 63 | int *subversion_id, int *subdevice_id, 64 | int *revision_id); 65 | 66 | int devq_device_get_pcibusaddr(int fd, 67 | int *domain, int *bus, 68 | int *slot, int *function); 69 | 70 | int devq_device_drm_get_drvname_from_fd(int fd, 71 | char *driver_name, size_t *driver_name_len); 72 | devq_device_t devq_device_get_type(struct devq_device *); 73 | devq_class_t devq_device_get_class(struct devq_device *); 74 | const char * devq_device_get_path(struct devq_device *); 75 | const char * devq_device_get_product(struct devq_device *); 76 | const char * devq_device_get_vendor(struct devq_device *); 77 | 78 | struct devq_evmon * devq_event_monitor_init(void); 79 | void devq_event_monitor_fini(struct devq_evmon *); 80 | int devq_event_monitor_get_fd(struct devq_evmon *); 81 | int devq_event_monitor_poll(struct devq_evmon *); 82 | struct devq_event * devq_event_monitor_read(struct devq_evmon *); 83 | struct devq_device * devq_event_get_device(struct devq_event *); 84 | devq_event_t devq_event_get_type(struct devq_event *); 85 | const char * devq_event_dump(struct devq_event *); 86 | void devq_event_free(struct devq_event *); 87 | 88 | #endif /* _LIBDEVQ_H_ */ 89 | -------------------------------------------------------------------------------- /src/freebsd/device.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jean-Sebastien Pedron 3 | * Copyright (c) 2016 Koop Mast 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 1. Redistributions of source code must retain the above copyright 10 | * notice, this list of conditions and the following disclaimer 11 | * in this position and unchanged. 12 | * 2. Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #if defined(HAVE_LIBPROCSTAT_H) 39 | # include 40 | # include 41 | # include 42 | # include 43 | # include 44 | #else 45 | # include 46 | # include 47 | #endif 48 | 49 | #include "libdevq.h" 50 | 51 | int 52 | devq_device_get_devpath_from_fd(int fd, 53 | char *path, size_t *path_len) 54 | { 55 | #if defined(HAVE_LIBPROCSTAT_H) 56 | int ret; 57 | struct procstat *procstat; 58 | struct kinfo_proc *kip; 59 | struct filestat_list *head; 60 | struct filestat *fst; 61 | unsigned int count; 62 | size_t len; 63 | 64 | ret = 0; 65 | head = NULL; 66 | 67 | procstat = procstat_open_sysctl(); 68 | if (procstat == NULL) 69 | return (-1); 70 | 71 | count = 0; 72 | kip = procstat_getprocs(procstat, KERN_PROC_PID, getpid(), &count); 73 | if (kip == NULL || count != 1) { 74 | ret = -1; 75 | goto out; 76 | } 77 | 78 | head = procstat_getfiles(procstat, kip, 0); 79 | if (head == NULL) { 80 | ret = -1; 81 | goto out; 82 | } 83 | 84 | STAILQ_FOREACH(fst, head, next) { 85 | if (fst->fs_uflags != 0 || 86 | fst->fs_type != PS_FST_TYPE_VNODE || 87 | fst->fs_fd != fd) 88 | continue; 89 | 90 | if (fst->fs_path == NULL) { 91 | errno = EBADF; 92 | ret = -1; 93 | break; 94 | } 95 | 96 | len = strlen(fst->fs_path); 97 | if (path) { 98 | if (*path_len < len) { 99 | *path_len = len; 100 | errno = ENOMEM; 101 | ret = -1; 102 | break; 103 | } 104 | 105 | memcpy(path, fst->fs_path, len); 106 | } 107 | *path_len = len; 108 | break; 109 | } 110 | 111 | out: 112 | if (head != NULL) 113 | procstat_freefiles(procstat, head); 114 | if (kip != NULL) 115 | procstat_freeprocs(procstat, kip); 116 | procstat_close(procstat); 117 | 118 | return (ret); 119 | #else /* !defined(HAVE_LIBPROCSTAT_H) */ 120 | int ret, found; 121 | DIR *dir; 122 | struct stat st; 123 | struct dirent *dp; 124 | char tmp_path[256]; 125 | size_t tmp_path_len; 126 | 127 | /* 128 | * FIXME: This function is specific to DRM devices. 129 | */ 130 | #define DEVQ_DRIDEV_DIR "/dev/dri" 131 | 132 | ret = fstat(fd, &st); 133 | if (ret != 0) 134 | return (-1); 135 | if (!S_ISCHR(st.st_mode)) { 136 | errno = EBADF; 137 | return (-1); 138 | } 139 | 140 | dir = opendir(DEVQ_DRIDEV_DIR); 141 | if (dir == NULL) 142 | return (-1); 143 | 144 | found = 0; 145 | while ((dp = readdir(dir)) != NULL) { 146 | struct stat tmp_st; 147 | 148 | if (dp->d_name[0] == '.') 149 | continue; 150 | 151 | tmp_path_len = strlen(DEVQ_DRIDEV_DIR); 152 | strcpy(tmp_path, DEVQ_DRIDEV_DIR); 153 | tmp_path[tmp_path_len++] = '/'; 154 | tmp_path[tmp_path_len] = '\0'; 155 | 156 | strcpy(tmp_path + tmp_path_len, dp->d_name); 157 | tmp_path_len += dp->d_namlen; 158 | tmp_path[tmp_path_len] = '\0'; 159 | 160 | ret = stat(tmp_path, &tmp_st); 161 | if (ret != 0) 162 | continue; 163 | 164 | if (st.st_dev == tmp_st.st_dev && 165 | st.st_ino == tmp_st.st_ino) { 166 | found = 1; 167 | break; 168 | } 169 | } 170 | 171 | closedir(dir); 172 | 173 | if (!found) { 174 | errno = EBADF; 175 | return -(1); 176 | } 177 | 178 | if (path) { 179 | if (*path_len < tmp_path_len) { 180 | *path_len = tmp_path_len; 181 | errno = ENOMEM; 182 | return (-1); 183 | } 184 | 185 | memcpy(path, tmp_path, tmp_path_len); 186 | } 187 | if (path_len) 188 | *path_len = tmp_path_len; 189 | 190 | return (0); 191 | #endif /* defined(HAVE_LIBPROCSTAT_H) */ 192 | } 193 | 194 | static int 195 | devq_compare_vgapci_busaddr(int i, int *domain, int *bus, int *slot, 196 | int *function) 197 | { 198 | int ret; 199 | char sysctl_name[32], sysctl_value[128]; 200 | size_t sysctl_value_len; 201 | 202 | sprintf(sysctl_name, "dev.vgapci.%d.%%location", i); 203 | 204 | sysctl_value_len = sizeof(sysctl_value); 205 | memset(sysctl_value, 0, sysctl_value_len); 206 | ret = sysctlbyname(sysctl_name, sysctl_value, 207 | &sysctl_value_len, NULL, 0); 208 | if (ret != 0) 209 | return (-1); 210 | 211 | /* 212 | * dev.vgapci.$m.%location can have two formats: 213 | * o "pci0:2:0:0 handle=\_SB_.PCI0.PEG3.MXM3" (FreeBSD 11+) 214 | * o "slot=1 function=0" (up-to FreeBSD 10) 215 | */ 216 | 217 | ret = sscanf(sysctl_value, "pci%d:%d:%d:%d %*s", 218 | domain, bus, slot, function); 219 | if (ret == 4) 220 | return (0); 221 | 222 | ret = sscanf(sysctl_value, "slot=%d function=%d %*s", 223 | slot, function); 224 | if (ret != 2) 225 | return (-1); 226 | 227 | sprintf(sysctl_name, "dev.vgapci.%d.%%parent", i); 228 | 229 | sysctl_value_len = sizeof(sysctl_value); 230 | memset(sysctl_value, 0, sysctl_value_len); 231 | ret = sysctlbyname(sysctl_name, sysctl_value, 232 | &sysctl_value_len, NULL, 0); 233 | if (ret != 0) 234 | return (-1); 235 | 236 | ret = sscanf(sysctl_value, "pci%d", bus); 237 | if (ret != 1) 238 | return (-1); 239 | 240 | /* FIXME: What domain to assume? */ 241 | *domain = 0; 242 | 243 | return (0); 244 | } 245 | 246 | int 247 | devq_device_get_pcibusaddr(int fd, int *domain, 248 | int *bus, int *slot, int *function) 249 | { 250 | int i, dev, ret; 251 | char sysctl_name[32], sysctl_value[128]; 252 | const char *busid_format; 253 | size_t sysctl_value_len; 254 | 255 | /* 256 | * FIXME: This function is specific to DRM devices. 257 | */ 258 | 259 | /* 260 | * We don't need the driver name, but this function already 261 | * walks the hw.dri.* tree and returns the number in 262 | * hw.dri.$number. 263 | */ 264 | dev = devq_device_drm_get_drvname_from_fd(fd, NULL, NULL); 265 | if (dev < 0) 266 | return (-1); 267 | 268 | /* 269 | * Read the hw.dri.$n.busid sysctl to get the location of the 270 | * device on the PCI bus. We can then use this location to find 271 | * the corresponding dev.vgapci.$m tree. 272 | */ 273 | sprintf(sysctl_name, "hw.dri.%d.busid", dev); 274 | 275 | busid_format = "pci:%d:%d:%d.%d"; 276 | sysctl_value_len = sizeof(sysctl_value); 277 | memset(sysctl_value, 0, sysctl_value_len); 278 | ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, 279 | NULL, 0); 280 | 281 | if (ret != 0) { 282 | /* 283 | * If hw.dri.$n.busid isn't available, fallback on 284 | * hw.dri.$n.name. 285 | */ 286 | busid_format = "%*s %*s pci:%d:%d:%d.%d"; 287 | sysctl_value_len = sizeof(sysctl_value); 288 | memset(sysctl_value, 0, sysctl_value_len); 289 | sprintf(sysctl_name, "hw.dri.%d.name", dev); 290 | ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, 291 | NULL, 0); 292 | } 293 | 294 | if (ret != 0) 295 | return (-1); 296 | 297 | ret = sscanf(sysctl_value, busid_format, 298 | domain, bus, slot, function); 299 | if (ret != 4) { 300 | errno = ENOENT; 301 | return (-1); 302 | } 303 | 304 | return (0); 305 | } 306 | 307 | int 308 | devq_device_get_pciid_full_from_fd(int fd, 309 | int *vendor_id, int *device_id, int *subvendor_id, 310 | int *subdevice_id, int *revision_id) 311 | { 312 | int i, ret, dev, domain, bus, slot, function; 313 | char sysctl_name[32], sysctl_value[128]; 314 | const char *busid_format; 315 | size_t sysctl_value_len; 316 | 317 | /* 318 | * FIXME: This function is specific to DRM devices. 319 | */ 320 | 321 | /* 322 | * We don't need the driver name, but this function already 323 | * walks the hw.dri.* tree and returns the number in 324 | * hw.dri.$number. 325 | */ 326 | dev = devq_device_drm_get_drvname_from_fd(fd, NULL, NULL); 327 | if (dev < 0) 328 | return (-1); 329 | 330 | /* 331 | * Read the hw.dri.$n.busid sysctl to get the location of the 332 | * device on the PCI bus. We can then use this location to find 333 | * the corresponding dev.vgapci.$m tree. 334 | */ 335 | sprintf(sysctl_name, "hw.dri.%d.busid", dev); 336 | 337 | busid_format = "pci:%d:%d:%d.%d"; 338 | sysctl_value_len = sizeof(sysctl_value); 339 | memset(sysctl_value, 0, sysctl_value_len); 340 | ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, 341 | NULL, 0); 342 | 343 | if (ret != 0) { 344 | /* 345 | * If hw.dri.$n.busid isn't available, fallback on 346 | * hw.dri.$n.name. 347 | */ 348 | busid_format = "%*s %*s pci:%d:%d:%d.%d"; 349 | sysctl_value_len = sizeof(sysctl_value); 350 | memset(sysctl_value, 0, sysctl_value_len); 351 | sprintf(sysctl_name, "hw.dri.%d.name", dev); 352 | ret = sysctlbyname(sysctl_name, sysctl_value, &sysctl_value_len, 353 | NULL, 0); 354 | } 355 | 356 | if (ret != 0) 357 | return (-1); 358 | 359 | ret = sscanf(sysctl_value, busid_format, 360 | &domain, &bus, &slot, &function); 361 | if (ret != 4) { 362 | errno = ENOENT; 363 | return (-1); 364 | } 365 | 366 | /* 367 | * Now, look at all dev.vgapci.$m trees until we find the 368 | * correct device. We specifically look at: 369 | * o dev.vgapci.$m.%location 370 | * o dev.vgapci.$m.%parent 371 | */ 372 | for (i = 0; i < DEVQ_MAX_DEVS; ++i) { 373 | int tmp_domain, tmp_bus, tmp_slot, tmp_function; 374 | 375 | ret = devq_compare_vgapci_busaddr(i, &tmp_domain, &tmp_bus, 376 | &tmp_slot, &tmp_function); 377 | 378 | if (ret == 0 && 379 | tmp_domain == domain && 380 | tmp_bus == bus && 381 | tmp_slot == slot && 382 | tmp_function == function) 383 | break; 384 | } 385 | 386 | if (i == DEVQ_MAX_DEVS) { 387 | errno = ENOENT; 388 | return (-1); 389 | } 390 | 391 | /* 392 | * Ok, we have the right tree. Let's read dev.vgapci.$m.%pnpinfo 393 | * to gather the PCI ID. 394 | */ 395 | sprintf(sysctl_name, "dev.vgapci.%d.%%pnpinfo", i); 396 | 397 | sysctl_value_len = sizeof(sysctl_value); 398 | memset(sysctl_value, 0, sysctl_value_len); 399 | ret = sysctlbyname(sysctl_name, sysctl_value, 400 | &sysctl_value_len, NULL, 0); 401 | if (ret != 0) 402 | return (-1); 403 | 404 | ret = sscanf(sysctl_value, "vendor=0x%04x device=0x%04x subvendor=0x%04x subdevice=0x%04x", 405 | vendor_id, device_id, subvendor_id, subdevice_id); 406 | if (ret != 4) { 407 | errno = EINVAL; 408 | return (-1); 409 | } 410 | 411 | /* XXX: add code to find out revision id */ 412 | revision_id = 0; 413 | 414 | return (0); 415 | } 416 | 417 | int 418 | devq_device_get_pciid_from_fd(int fd, 419 | int *vendor_id, int *device_id) 420 | { 421 | int subvendor_id, subdevice_id, revision_id; 422 | 423 | return devq_device_get_pciid_full_from_fd(fd, 424 | vendor_id, device_id, &subvendor_id, 425 | &subdevice_id, &revision_id); 426 | } 427 | 428 | -------------------------------------------------------------------------------- /src/freebsd/device_drm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jean-Sebastien Pedron 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "libdevq.h" 37 | 38 | int 39 | devq_device_drm_get_drvname_from_fd(int fd, 40 | char *driver_name, size_t *driver_name_len) 41 | { 42 | int ret, i; 43 | struct stat st; 44 | char sysctl_name[32], sysctl_value[128]; 45 | size_t sysctl_value_len, name_len; 46 | long dev; 47 | 48 | ret = fstat(fd, &st); 49 | if (ret != 0) 50 | return (-1); 51 | if (!S_ISCHR(st.st_mode)) { 52 | errno = EBADF; 53 | return (-1); 54 | } 55 | 56 | /* 57 | * Walk all the hw.dri.$n tree and compare the number stored at 58 | * the end of hw.dri.$n.name (eg. "radeon 0x9b") to the value in 59 | * stat.st_rdev. 60 | */ 61 | for (i = 0; i < DEVQ_MAX_DEVS; i++) { 62 | sprintf(sysctl_name, "hw.dri.%d.name", i); 63 | 64 | sysctl_value_len = sizeof(sysctl_value); 65 | ret = sysctlbyname(sysctl_name, sysctl_value, 66 | &sysctl_value_len, NULL, 0); 67 | if (ret != 0) 68 | continue; 69 | 70 | for (name_len = 0; 71 | name_len < sysctl_value_len && 72 | sysctl_value[name_len] != ' '; 73 | ++name_len) 74 | ; 75 | if (driver_name != NULL) { 76 | if (*driver_name_len < name_len) { 77 | *driver_name_len = name_len; 78 | errno = ENOMEM; 79 | return (-1); 80 | } 81 | 82 | memcpy(driver_name, sysctl_value, name_len); 83 | } 84 | if (driver_name_len) 85 | *driver_name_len = name_len; 86 | 87 | /* 88 | * Now that we found the correct entry, return its 89 | * number; this could be useful to others. 90 | */ 91 | dev = strtol(sysctl_value + name_len, NULL, 16); 92 | if (dev == (long)st.st_rdev) 93 | return (i); 94 | } 95 | 96 | errno = ENOENT; 97 | return (-1); 98 | } 99 | -------------------------------------------------------------------------------- /src/freebsd/event_monitor_freebsd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Baptiste Daroussin 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #define _WITH_GETLINE 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "libdevq.h" 41 | 42 | static struct hw_type { 43 | const char *driver; 44 | devq_device_t type; 45 | devq_class_t class; 46 | } hw_types[] = { 47 | { "ukbd", DEVQ_DEVICE_KEYBOARD, DEVQ_CLASS_INPUT }, 48 | { "atkbd", DEVQ_DEVICE_KEYBOARD, DEVQ_CLASS_INPUT }, 49 | { "ums", DEVQ_DEVICE_MOUSE, DEVQ_CLASS_INPUT }, 50 | { "psm", DEVQ_DEVICE_MOUSE, DEVQ_CLASS_INPUT }, 51 | { "uhid", DEVQ_DEVICE_MOUSE, DEVQ_CLASS_INPUT }, 52 | { "joy", DEVQ_DEVICE_JOYSTICK, DEVQ_CLASS_INPUT }, 53 | { "atp", DEVQ_DEVICE_TOUCHPAD, DEVQ_CLASS_INPUT }, 54 | { "uep", DEVQ_DEVICE_TOUCHSCREEN, DEVQ_CLASS_INPUT }, 55 | { NULL, DEVQ_DEVICE_UNKNOWN, DEVQ_CLASS_UNKNOWN }, 56 | }; 57 | 58 | #define DEVD_SOCK_PATH "/var/run/devd.pipe" 59 | 60 | #define DEVD_EVENT_ATTACH '+' 61 | #define DEVD_EVENT_DETTACH '-' 62 | #define DEVD_EVENT_NOTICE '!' 63 | #define DEVD_EVENT_UNKNOWN '?' 64 | 65 | struct devq_evmon { 66 | int fd; 67 | int kq; 68 | struct kevent ev; 69 | char *buf; 70 | size_t len; 71 | }; 72 | 73 | struct devq_device { 74 | devq_device_t type; 75 | devq_class_t class; 76 | char *path; 77 | char *driver; 78 | char *vendor; 79 | char *product; 80 | const char *vstr; 81 | const char *pstr; 82 | }; 83 | 84 | struct devq_event { 85 | int type; 86 | struct devq_device *device; 87 | char *raw; 88 | }; 89 | 90 | static ssize_t 91 | socket_getline(struct devq_evmon *evmon) 92 | { 93 | ssize_t ret, sz = 0; 94 | char c; 95 | 96 | for (;;) { 97 | ret = read(evmon->fd, &c, 1); 98 | if (ret < 1) { 99 | return -1; 100 | } 101 | 102 | if (c == '\n') 103 | break; 104 | 105 | if (sz + 1 >= evmon->len) { 106 | evmon->len += 1024; 107 | evmon->buf = reallocf(evmon->buf, evmon->len *sizeof(char)); 108 | } 109 | evmon->buf[sz] = c; 110 | sz++; 111 | } 112 | 113 | evmon->buf[sz] = '\0'; 114 | 115 | return (sz); /* number of bytes in the line, not counting the line break*/ 116 | } 117 | 118 | struct devq_evmon * 119 | devq_event_monitor_init(void) 120 | { 121 | struct devq_evmon *evm; 122 | struct sockaddr_un devd; 123 | struct kevent ev; 124 | 125 | if ((evm = calloc(1, sizeof (struct devq_evmon))) == NULL) 126 | return (NULL); 127 | 128 | evm->fd = socket(AF_UNIX, SOCK_STREAM, 0); 129 | if (evm->fd < 0) { 130 | free(evm); 131 | return (NULL); 132 | } 133 | 134 | devd.sun_family = AF_UNIX; 135 | strlcpy(devd.sun_path, DEVD_SOCK_PATH, sizeof(devd.sun_path)); 136 | 137 | if (connect(evm->fd, (struct sockaddr *) &devd, sizeof(struct sockaddr_un)) < 0) { 138 | close(evm->fd); 139 | free(evm); 140 | return (NULL); 141 | } 142 | 143 | evm->kq = kqueue(); 144 | if (evm->kq == -1) { 145 | close(evm->fd); 146 | free(evm); 147 | evm = NULL; 148 | } else { 149 | EV_SET(&ev, evm->fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); 150 | kevent(evm->kq, &ev, 1, NULL, 0, NULL); 151 | } 152 | 153 | return (evm); 154 | } 155 | 156 | void 157 | devq_event_monitor_fini(struct devq_evmon *evm) 158 | { 159 | if (evm == NULL) 160 | return; 161 | 162 | close(evm->fd); 163 | free(evm->buf); 164 | free(evm); 165 | } 166 | 167 | int 168 | devq_event_monitor_get_fd(struct devq_evmon *evm) 169 | { 170 | if (evm == NULL) 171 | return (-1); 172 | 173 | return (evm->kq); 174 | } 175 | 176 | int 177 | devq_event_monitor_poll(struct devq_evmon *evm) 178 | { 179 | if (evm == NULL) 180 | return (0); 181 | 182 | if (kevent(evm->kq, NULL, 0, &evm->ev, 1, NULL) < 0) 183 | return (0); 184 | 185 | return (1); 186 | } 187 | 188 | struct devq_event * 189 | devq_event_monitor_read(struct devq_evmon *evm) 190 | { 191 | struct devq_event *e; 192 | 193 | if (socket_getline(evm) < 0) 194 | return (NULL); 195 | 196 | /* XXX here may apply filters */ 197 | e = calloc(1, sizeof(struct devq_event)); 198 | if (e == NULL) 199 | return (NULL); 200 | 201 | e->raw = strdup(evm->buf); 202 | 203 | switch (*e->raw) { 204 | case DEVD_EVENT_ATTACH: 205 | e->type = DEVQ_ATTACHED; 206 | break; 207 | case DEVD_EVENT_DETTACH: 208 | e->type = DEVQ_DETACHED; 209 | break; 210 | case DEVD_EVENT_NOTICE: 211 | e->type = DEVQ_NOTICE; 212 | break; 213 | default: 214 | e->type = DEVQ_UNKNOWN; 215 | break; 216 | } 217 | 218 | return (e); 219 | } 220 | 221 | devq_event_t 222 | devq_event_get_type(struct devq_event *e) 223 | { 224 | 225 | if (e == NULL) 226 | return (DEVQ_UNKNOWN); 227 | 228 | return (e->type); 229 | } 230 | 231 | static void 232 | vendor_product(struct devq_device *d, const char *ids) 233 | { 234 | FILE *f; 235 | char *line = NULL; 236 | const char *walk; 237 | size_t linecap = 0; 238 | ssize_t linelen; 239 | 240 | if ((f = fopen(ids, "r")) == NULL) 241 | return; 242 | 243 | while ((linelen = getline(&line, &linecap, f)) > 0) { 244 | if (d->vendor == NULL) { 245 | if (strncmp(line, d->vstr + 2, 4) == 0) { 246 | walk = line + 4; 247 | 248 | while (isspace(*walk)) 249 | walk++; 250 | 251 | if (line[linelen -1] == '\n') 252 | line[linelen - 1 ] = '\0'; 253 | 254 | d->vendor = strndup(walk, strlen(walk)); 255 | } 256 | } else { 257 | walk = line; 258 | while (isspace(*walk)) 259 | walk++; 260 | 261 | if (strncmp(walk, d->pstr + 2, 4) == 0) { 262 | walk += 4; 263 | 264 | while (isspace(*walk)) 265 | walk++; 266 | 267 | if (line[linelen -1] == '\n') 268 | line[linelen - 1 ] = '\0'; 269 | 270 | d->product = strndup(walk, strlen(walk)); 271 | } 272 | } 273 | 274 | } 275 | fclose(f); 276 | free(line); 277 | 278 | } 279 | 280 | static void 281 | device_vendor_product(struct devq_event *e) 282 | { 283 | const char *usbids = PREFIX "/share/usbids/usb.ids"; 284 | const char *pciids = PREFIX "/share/pciids/pci.ids"; 285 | 286 | e->device->vstr = strstr(e->raw, "vendor="); 287 | if (e->device->vstr == NULL) 288 | return; 289 | 290 | e->device->vstr += 7; 291 | e->device->pstr = strstr(e->raw, "product="); 292 | e->device->pstr += 8; 293 | 294 | if (*e->device->driver == 'u') 295 | vendor_product(e->device, usbids); 296 | 297 | if (e->device->vendor == NULL) 298 | vendor_product(e->device, pciids); 299 | } 300 | 301 | struct devq_device * 302 | devq_event_get_device(struct devq_event *e) 303 | { 304 | const char *line, *walk; 305 | int i; 306 | 307 | if (e == NULL) 308 | return (NULL); 309 | 310 | if (e->type != DEVQ_ATTACHED && e->type != DEVQ_DETACHED) 311 | return (NULL); 312 | 313 | if (e->device != NULL) 314 | return (e->device); 315 | 316 | e->device = calloc(1, sizeof(struct devq_device)); 317 | if (e->device == NULL) 318 | return (NULL); 319 | 320 | e->device->type = DEVQ_DEVICE_UNKNOWN; 321 | e->device->class = DEVQ_CLASS_UNKNOWN; 322 | 323 | line = e->raw + 1; 324 | walk = line; 325 | while (!isspace(*walk)) 326 | walk++; 327 | 328 | asprintf(&e->device->path, "/dev/%.*s", (int)(walk - line), line); 329 | 330 | for (i = 0; hw_types[i].driver != NULL; i++) { 331 | if (strncmp(line, hw_types[i].driver, 332 | strlen(hw_types[i].driver)) == 0 && 333 | isdigit(*(line + strlen(hw_types[i].driver)))) { 334 | e->device->type = hw_types[i].type; 335 | e->device->class = hw_types[i].class; 336 | e->device->driver = strdup(hw_types[i].driver); 337 | break; 338 | } 339 | } 340 | 341 | if (e->device->driver == NULL) { 342 | walk--; 343 | while (isdigit(*walk)) 344 | walk--; 345 | e->device->driver = strndup(line, walk - line); 346 | } 347 | 348 | device_vendor_product(e); 349 | 350 | return (e->device); 351 | } 352 | 353 | const char * 354 | devq_event_dump(struct devq_event *e) 355 | { 356 | return (e->raw); 357 | } 358 | 359 | void 360 | devq_event_free(struct devq_event *e) 361 | { 362 | if (e->device != NULL) { 363 | free(e->device->path); 364 | free(e->device->driver); 365 | free(e->device); 366 | } 367 | 368 | free(e->raw); 369 | free(e); 370 | } 371 | 372 | devq_device_t 373 | devq_device_get_type(struct devq_device *d) 374 | { 375 | 376 | if (d == NULL) 377 | return (DEVQ_DEVICE_UNKNOWN); 378 | 379 | return (d->type); 380 | } 381 | 382 | devq_class_t 383 | devq_device_get_class(struct devq_device *d) 384 | { 385 | 386 | if (d == NULL) 387 | return (DEVQ_CLASS_UNKNOWN); 388 | 389 | return (d->class); 390 | } 391 | 392 | const char * 393 | devq_device_get_path(struct devq_device *d) 394 | { 395 | 396 | if (d == NULL) 397 | return (NULL); 398 | 399 | return (d->path); 400 | } 401 | 402 | const char * 403 | devq_device_get_product(struct devq_device *d) 404 | { 405 | 406 | if (d == NULL) 407 | return (NULL); 408 | 409 | return (d->product); 410 | } 411 | 412 | const char * 413 | devq_device_get_vendor(struct devq_device *d) 414 | { 415 | 416 | if (d == NULL) 417 | return (NULL); 418 | 419 | return (d->vendor); 420 | } 421 | -------------------------------------------------------------------------------- /src/libdevq-1.0.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=${prefix} 3 | includedir=${prefix}/include 4 | libdir=${exec_prefix}/lib 5 | 6 | Name: @PACKAGE_NAME@ 7 | Description: Generic device query and monitor interface 8 | Version: @PACKAGE_VERSION@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -ldevq 11 | -------------------------------------------------------------------------------- /tools/devq_evwatch/devq_evwatch.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Baptiste Daroussin 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | 35 | int 36 | main(int argc, char **argv) 37 | { 38 | struct devq_evmon *e; 39 | struct devq_event *ev; 40 | struct devq_device *dev; 41 | const char *vendor, *product; 42 | bool verbose = false; 43 | 44 | if (argc == 2 && strcmp(argv[1], "-v") == 0) 45 | verbose = true; 46 | 47 | e = devq_event_monitor_init(); 48 | 49 | while (devq_event_monitor_poll(e)) { 50 | ev = devq_event_monitor_read(e); 51 | if (ev == NULL) 52 | break; 53 | 54 | switch (devq_event_get_type(ev)) { 55 | case DEVQ_ATTACHED: 56 | dev = devq_event_get_device(ev); 57 | switch (devq_device_get_type(dev)) { 58 | case DEVQ_DEVICE_JOYSTICK: 59 | printf("Joystick attached\n"); 60 | break; 61 | case DEVQ_DEVICE_TOUCHSCREEN: 62 | printf("Touchscreen attached\n"); 63 | break; 64 | case DEVQ_DEVICE_TOUCHPAD: 65 | printf("Touchpad attached\n"); 66 | break; 67 | case DEVQ_DEVICE_KEYBOARD: 68 | printf("Keyboard attached\n"); 69 | break; 70 | case DEVQ_DEVICE_MOUSE: 71 | printf("Mouse attached\n"); 72 | break; 73 | case DEVQ_DEVICE_UNKNOWN: 74 | printf("Unknown device attached\n"); 75 | break; 76 | } 77 | vendor = devq_device_get_vendor(dev); 78 | product = devq_device_get_product(dev); 79 | printf("Device path: %s; vendor: %s; product: %s\n", 80 | devq_device_get_path(dev), 81 | vendor ? vendor : "unknown", 82 | product ? product : "unknown"); 83 | break; 84 | case DEVQ_DETACHED: 85 | dev = devq_event_get_device(ev); 86 | switch (devq_device_get_type(dev)) { 87 | case DEVQ_DEVICE_JOYSTICK: 88 | printf("Joystick detached\n"); 89 | break; 90 | case DEVQ_DEVICE_TOUCHSCREEN: 91 | printf("Touchscreen detached\n"); 92 | break; 93 | case DEVQ_DEVICE_TOUCHPAD: 94 | printf("Touchpad detached\n"); 95 | break; 96 | case DEVQ_DEVICE_KEYBOARD: 97 | printf("Keyboard detached\n"); 98 | break; 99 | case DEVQ_DEVICE_MOUSE: 100 | printf("Mouse detached\n"); 101 | break; 102 | case DEVQ_DEVICE_UNKNOWN: 103 | printf("Unknown device detached\n"); 104 | break; 105 | } 106 | printf("Device path: %s\n", devq_device_get_path(dev)); 107 | break; 108 | case DEVQ_NOTICE: 109 | printf("Notice received\n"); 110 | break; 111 | case DEVQ_UNKNOWN: 112 | printf("Unknown event\n"); 113 | break; 114 | } 115 | 116 | if (verbose) 117 | printf("%s\n", devq_event_dump(ev)); 118 | devq_event_free(ev); 119 | } 120 | 121 | devq_event_monitor_fini(e); 122 | 123 | return (EXIT_SUCCESS); 124 | } 125 | -------------------------------------------------------------------------------- /tools/lsdri/lsdri.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014 Jean-Sebastien Pedron 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer 10 | * in this position and unchanged. 11 | * 2. Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #define DRIDEV_DIR "/dev/dri" 39 | 40 | int 41 | print_drm_info(int fd) 42 | { 43 | int ret; 44 | int vendor_id, device_id, subvendor_id, subdevice_id, revision_id; 45 | char *device_path, *driver_name; 46 | size_t device_path_len, driver_name_len; 47 | 48 | ret = devq_device_get_devpath_from_fd(fd, 49 | NULL, &device_path_len); 50 | if (ret < 0) { 51 | fprintf(stderr, "Warning: unable to device path\n"); 52 | return (-1); 53 | } 54 | 55 | device_path = malloc(device_path_len); 56 | ret = devq_device_get_devpath_from_fd(fd, 57 | device_path, &device_path_len); 58 | if (ret < 0) { 59 | fprintf(stderr, "Warning: Unable to device path\n"); 60 | return (-1); 61 | } 62 | 63 | printf("%.*s:\n", (int)device_path_len, device_path); 64 | free(device_path); 65 | device_path = NULL; 66 | 67 | ret = devq_device_drm_get_drvname_from_fd(fd, NULL, &driver_name_len); 68 | if (ret < 0) { 69 | printf(" Driver name: Unknown\n"); 70 | return (-1); 71 | } 72 | 73 | driver_name = malloc(driver_name_len); 74 | ret = devq_device_drm_get_drvname_from_fd(fd, 75 | driver_name, &driver_name_len); 76 | if (ret < 0) { 77 | fprintf(stderr, "Warning: Unable to determine driver name\n"); 78 | return (-1); 79 | } 80 | 81 | printf(" Driver name: %.*s\n", (int)driver_name_len, driver_name); 82 | free(driver_name); 83 | driver_name = NULL; 84 | 85 | ret = devq_device_get_pciid_full_from_fd(fd, &vendor_id, &device_id, 86 | &subvendor_id, &subdevice_id, &revision_id); 87 | if (ret < 0) { 88 | fprintf(stderr, "Warning: Unable to determine vendor and device ID\n"); 89 | return (-1); 90 | } 91 | 92 | printf(" PCI vendor ID: 0x%04x subvendor ID: 0x%04x\n", vendor_id, subvendor_id); 93 | printf(" PCI device ID: 0x%04x subdevice ID: 0x%04x\n", device_id, subdevice_id); 94 | printf(" PCI revision ID: 0x%04x\n", revision_id); 95 | 96 | return (0); 97 | } 98 | 99 | int 100 | main(int argc, char *argv[]) 101 | { 102 | int fd; 103 | 104 | if (argc >= 2) { 105 | for (int i = 1; i < argc; ++i) { 106 | fd = open(argv[i], O_RDWR); 107 | if (fd < 0) { 108 | fprintf(stderr, "%s\n", argv[i]); 109 | continue; 110 | } 111 | 112 | print_drm_info(fd); 113 | close(fd); 114 | } 115 | } else { 116 | DIR *dir; 117 | struct dirent *dp; 118 | char path[256]; 119 | 120 | dir = opendir(DRIDEV_DIR); 121 | if (dir == NULL) 122 | return (-1); 123 | 124 | while ((dp = readdir(dir)) != NULL) { 125 | if (dp->d_name[0] == '.') 126 | continue; 127 | 128 | path[0] = '\0'; 129 | strcpy(path, DRIDEV_DIR); 130 | strcat(path, "/"); 131 | strcat(path, dp->d_name); 132 | 133 | fd = open(path, O_RDWR); 134 | if (fd < 0) { 135 | fprintf(stderr, "%s\n", path); 136 | continue; 137 | } 138 | 139 | print_drm_info(fd); 140 | close(fd); 141 | } 142 | 143 | closedir(dir); 144 | } 145 | 146 | return (0); 147 | } 148 | --------------------------------------------------------------------------------