From 6dceaff02ec2e2e4474eca58e94316b6101edfb0 Mon Sep 17 00:00:00 2001 From: chopin1998 Date: Wed, 18 Jun 2025 00:05:44 +0800 Subject: [PATCH 1/4] add auto refresh when usb device plug/unplug --- .vscode/settings.json | 3 ++ Makefile.am | 4 +- configure.ac | 1 + main.c | 114 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cb504b3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "stm32-for-vscode.openOCDPath": false +} \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index 96fdef6..9c4f460 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,8 +3,8 @@ # ## Process this file with automake to produce Makefile.in -AM_CPPFLAGS = $(GTK_CFLAGS) -usbview_LDADD = $(GTK_LIBS) +AM_CPPFLAGS = $(GTK_CFLAGS) $(LIBUDEV_CFLAGS) +usbview_LDADD = $(GTK_LIBS) $(LIBUDEV_LIBS) bin_PROGRAMS = usbview diff --git a/configure.ac b/configure.ac index 4903aac..f5bf4c6 100644 --- a/configure.ac +++ b/configure.ac @@ -48,6 +48,7 @@ AM_CONDITIONAL(ICONS,[test x${icons} = xyes]) AC_SEARCH_LIBS([strerror],[cposix]) PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.0]) +PKG_CHECK_MODULES([LIBUDEV], [libudev]) AC_SUBST([GTK_FLAGS]) AC_SUBST([GTK_LIBS]) diff --git a/main.c b/main.c index 222cfb0..1fe5325 100644 --- a/main.c +++ b/main.c @@ -4,7 +4,7 @@ * Copyright (c) 1999, 2000 by Greg Kroah-Hartman, */ #ifdef HAVE_CONFIG_H - #include +#include #endif #include @@ -13,24 +13,108 @@ #include "usbtree.h" -int main (int argc, char *argv[]) +#include +#include + +static struct udev *udev = NULL; +static struct udev_monitor *mon = NULL; +static guint udev_source_id = 0; + +static gboolean udev_mon_cb(gint fd, GIOCondition condition, gpointer user_data) { - GtkWidget *window1; + struct udev_device *dev; + struct udev_device *parent_dev; + const char *action; + const char *dev_id_str; + + dev = udev_monitor_receive_device(mon); + if (!dev) + { + g_warning("failed to receive device from udev monitor"); + return TRUE; + } + + action = udev_device_get_action(dev); + if (action) + { + parent_dev = udev_device_get_parent(dev); + dev_id_str = udev_device_get_property_value(dev, "ID_MODEL"); + + const char *devtype = udev_device_get_devtype(dev); + if (devtype && strcmp(devtype, "usb_device") != 0) + { + udev_device_unref(dev); + return TRUE; + } + + if (strncmp(action, "remove", 7) == 0) + { + g_message("a device was removed (from %s)", udev_device_get_property_value(parent_dev, "ID_MODEL")); + } + else if (strncmp(action, "add", 3) == 0) + { + g_message("add a device: > %s < (from %s)", + dev_id_str ? dev_id_str : "unknown", + udev_device_get_property_value(parent_dev, "ID_MODEL")); + } + else + { + g_debug("udev action: %s for device: %s (%s)", + action, + udev_device_get_property_value(dev, "ID_MODEL"), + parent_dev ? udev_device_get_property_value(parent_dev, "ID_MODEL") : ""); + } + + LoadUSBTree(666); + } + + udev_device_unref(dev); + return TRUE; +} - gtk_init (&argc, &argv); +static void init_udev_mon(void) +{ + udev = udev_new(); + if (!udev) + { + g_warning("failed to create udev context"); + return; + } - initialize_stuff(); + mon = udev_monitor_new_from_netlink(udev, "udev"); + if (!mon) + { + g_warning("failed to create udev monitor"); + udev_unref(udev); + return; + } - /* - * The following code was added by Glade to create one of each component - * (except popup menus), just so that you see something after building - * the project. Delete any components that you don't want shown initially. - */ - window1 = create_windowMain (); - gtk_widget_show (window1); + udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL); + udev_monitor_enable_receiving(mon); - LoadUSBTree(0); - gtk_main (); - return 0; + udev_source_id = g_unix_fd_add(udev_monitor_get_fd(mon), G_IO_IN | G_IO_ERR | G_IO_HUP, + udev_mon_cb, NULL); } +int main(int argc, char *argv[]) +{ + GtkWidget *window1; + + gtk_init(&argc, &argv); + // Initialize udev monitor + init_udev_mon(); + + initialize_stuff(); + + /* + * The following code was added by Glade to create one of each component + * (except popup menus), just so that you see something after building + * the project. Delete any components that you don't want shown initially. + */ + window1 = create_windowMain(); + gtk_widget_show(window1); + + LoadUSBTree(0); + gtk_main(); + return 0; +} From 3b46f5da31ae41ce95c43d239b5b8a39d9ab04ac Mon Sep 17 00:00:00 2001 From: chopin1998 Date: Sat, 21 Jun 2025 22:34:31 +0800 Subject: [PATCH 2/4] using inotyfy (instead of udev) --- .vscode/settings.json | 6 +- Makefile.am | 4 +- configure.ac | 1 - main.c | 143 +++++++++++++++--------------------------- 4 files changed, 58 insertions(+), 96 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index cb504b3..2d999ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,7 @@ { - "stm32-for-vscode.openOCDPath": false + "stm32-for-vscode.openOCDPath": false, + "files.associations": { + ".fantomasignore": "ignore", + "usbtree.h": "c" + } } \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index 9c4f460..96fdef6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,8 +3,8 @@ # ## Process this file with automake to produce Makefile.in -AM_CPPFLAGS = $(GTK_CFLAGS) $(LIBUDEV_CFLAGS) -usbview_LDADD = $(GTK_LIBS) $(LIBUDEV_LIBS) +AM_CPPFLAGS = $(GTK_CFLAGS) +usbview_LDADD = $(GTK_LIBS) bin_PROGRAMS = usbview diff --git a/configure.ac b/configure.ac index f5bf4c6..4903aac 100644 --- a/configure.ac +++ b/configure.ac @@ -48,7 +48,6 @@ AM_CONDITIONAL(ICONS,[test x${icons} = xyes]) AC_SEARCH_LIBS([strerror],[cposix]) PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.0]) -PKG_CHECK_MODULES([LIBUDEV], [libudev]) AC_SUBST([GTK_FLAGS]) AC_SUBST([GTK_LIBS]) diff --git a/main.c b/main.c index 1fe5325..f20617a 100644 --- a/main.c +++ b/main.c @@ -4,117 +4,76 @@ * Copyright (c) 1999, 2000 by Greg Kroah-Hartman, */ #ifdef HAVE_CONFIG_H -#include + #include #endif #include #include +#include + #include "usbtree.h" -#include -#include -static struct udev *udev = NULL; -static struct udev_monitor *mon = NULL; -static guint udev_source_id = 0; +static int inotify_fd; -static gboolean udev_mon_cb(gint fd, GIOCondition condition, gpointer user_data) +static gboolean inotify_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - struct udev_device *dev; - struct udev_device *parent_dev; - const char *action; - const char *dev_id_str; - - dev = udev_monitor_receive_device(mon); - if (!dev) - { - g_warning("failed to receive device from udev monitor"); - return TRUE; - } - - action = udev_device_get_action(dev); - if (action) - { - parent_dev = udev_device_get_parent(dev); - dev_id_str = udev_device_get_property_value(dev, "ID_MODEL"); - - const char *devtype = udev_device_get_devtype(dev); - if (devtype && strcmp(devtype, "usb_device") != 0) - { - udev_device_unref(dev); - return TRUE; - } - - if (strncmp(action, "remove", 7) == 0) - { - g_message("a device was removed (from %s)", udev_device_get_property_value(parent_dev, "ID_MODEL")); - } - else if (strncmp(action, "add", 3) == 0) - { - g_message("add a device: > %s < (from %s)", - dev_id_str ? dev_id_str : "unknown", - udev_device_get_property_value(parent_dev, "ID_MODEL")); - } - else - { - g_debug("udev action: %s for device: %s (%s)", - action, - udev_device_get_property_value(dev, "ID_MODEL"), - parent_dev ? udev_device_get_property_value(parent_dev, "ID_MODEL") : ""); - } - - LoadUSBTree(666); - } - - udev_device_unref(dev); - return TRUE; + char buf[4096]; + ssize_t len; + struct inotify_event *event; + + while ((len = read(inotify_fd, buf, sizeof(buf))) > 0) { + } + + LoadUSBTree(666); + + return TRUE; } -static void init_udev_mon(void) +static void init_inotify(void) { - udev = udev_new(); - if (!udev) - { - g_warning("failed to create udev context"); - return; - } - - mon = udev_monitor_new_from_netlink(udev, "udev"); - if (!mon) - { - g_warning("failed to create udev monitor"); - udev_unref(udev); - return; - } - - udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", NULL); - udev_monitor_enable_receiving(mon); - - udev_source_id = g_unix_fd_add(udev_monitor_get_fd(mon), G_IO_IN | G_IO_ERR | G_IO_HUP, - udev_mon_cb, NULL); + const char *path = "/sys/bus/usb/devices"; + inotify_fd = inotify_init1(IN_NONBLOCK); + if (inotify_fd < 0) { + perror("inotify_init1"); + return; + } + + if (inotify_add_watch(inotify_fd, path, IN_ALL_EVENTS) < 0) { + perror("inotify_add_watch"); + close(inotify_fd); + inotify_fd = -1; + return; + } + + GIOChannel *ch = g_io_channel_unix_new(inotify_fd); + g_io_add_watch(ch, G_IO_IN, inotify_cb, NULL); + g_io_channel_unref(ch); } -int main(int argc, char *argv[]) + +int main (int argc, char *argv[]) { - GtkWidget *window1; + GtkWidget *window1; + + gtk_init (&argc, &argv); - gtk_init(&argc, &argv); - // Initialize udev monitor - init_udev_mon(); + initialize_stuff(); - initialize_stuff(); + init_inotify(); - /* - * The following code was added by Glade to create one of each component - * (except popup menus), just so that you see something after building - * the project. Delete any components that you don't want shown initially. - */ - window1 = create_windowMain(); - gtk_widget_show(window1); + /* + * The following code was added by Glade to create one of each component + * (except popup menus), just so that you see something after building + * the project. Delete any components that you don't want shown initially. + */ + window1 = create_windowMain (); + gtk_widget_show (window1); - LoadUSBTree(0); - gtk_main(); - return 0; + LoadUSBTree(0); + gtk_main (); + return 0; } + From 06772b4a765755dd86e92b3beb527806a21a367a Mon Sep 17 00:00:00 2001 From: Marco Date: Thu, 26 Jun 2025 15:52:56 +0800 Subject: [PATCH 3/4] intel usb controller or udev in ubuntu24.04 not function under inotify, using netlink instead... --- .vscode/settings.json | 2 +- main.c | 113 +++++++++++++++++++++++++++++++++--------- 2 files changed, 91 insertions(+), 24 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2d999ae..aa07f6e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "stm32-for-vscode.openOCDPath": false, + "stm32-for-vscode.openOCDPath": "/usr/bin/openocd", "files.associations": { ".fantomasignore": "ignore", "usbtree.h": "c" diff --git a/main.c b/main.c index f20617a..8eab098 100644 --- a/main.c +++ b/main.c @@ -8,48 +8,115 @@ #endif #include +#include +#include +#include +#include +#include +#include +#include #include -#include - #include "usbtree.h" -static int inotify_fd; +static int netlink_fd; +static struct timespec last_refresh_time = {0, 0}; + +static int should_refresh(void) +{ + struct timespec now; + + if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) + return 1; + + if (last_refresh_time.tv_sec == 0) { + last_refresh_time = now; + return 1; + } + + double elapsed = (now.tv_sec - last_refresh_time.tv_sec) + + (now.tv_nsec - last_refresh_time.tv_nsec) / 1e9; + + if (elapsed < 0.2) + return 0; + + last_refresh_time = now; + return 1; +} -static gboolean inotify_cb(GIOChannel *source, GIOCondition condition, gpointer data) +static gboolean netlink_cb(GIOChannel *source, GIOCondition condition, gpointer data) { char buf[4096]; ssize_t len; - struct inotify_event *event; - - while ((len = read(inotify_fd, buf, sizeof(buf))) > 0) { + int need_refresh = 0; + + len = recv(netlink_fd, buf, sizeof(buf) - 1, 0); + if (len > 0) { + buf[len] = '\0'; + + if (strstr(buf, "usb") || strstr(buf, "USB")) { + char *action = NULL; + char *subsystem = NULL; + char *devpath = NULL; + + char *line = buf; + while (*line) { + if (strncmp(line, "ACTION=", 7) == 0) { + action = line + 7; + } else if (strncmp(line, "SUBSYSTEM=", 10) == 0) { + subsystem = line + 10; + } else if (strncmp(line, "DEVPATH=", 8) == 0) { + devpath = line + 8; + } + + while (*line && *line != '\0') line++; + if (*line == '\0') line++; + } + + if (action && (strcmp(action, "add") == 0 || strcmp(action, "remove") == 0)) { + // printf("USB device %s: %s\n", action, devpath ? devpath : "unknown"); + need_refresh = 1; + } + } + + if (need_refresh) { + if (should_refresh()) { + LoadUSBTree(666); + } + } } - LoadUSBTree(666); - return TRUE; } -static void init_inotify(void) +static void init_netlink(void) { - const char *path = "/sys/bus/usb/devices"; - inotify_fd = inotify_init1(IN_NONBLOCK); - if (inotify_fd < 0) { - perror("inotify_init1"); + struct sockaddr_nl addr; + + printf("init netlink USB monitoring...\n"); + + netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT); + if (netlink_fd < 0) { + perror("netlink socket"); return; } - - if (inotify_add_watch(inotify_fd, path, IN_ALL_EVENTS) < 0) { - perror("inotify_add_watch"); - close(inotify_fd); - inotify_fd = -1; + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = getpid(); + addr.nl_groups = 1; + + if (bind(netlink_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + perror("netlink bind"); + close(netlink_fd); + netlink_fd = -1; return; } - - GIOChannel *ch = g_io_channel_unix_new(inotify_fd); - g_io_add_watch(ch, G_IO_IN, inotify_cb, NULL); + + GIOChannel *ch = g_io_channel_unix_new(netlink_fd); + g_io_add_watch(ch, G_IO_IN, netlink_cb, NULL); g_io_channel_unref(ch); } @@ -62,7 +129,7 @@ int main (int argc, char *argv[]) initialize_stuff(); - init_inotify(); + init_netlink(); /* * The following code was added by Glade to create one of each component From 8985f8312c5492b37e46f67e9ca5baf2032952a6 Mon Sep 17 00:00:00 2001 From: chopin1998 Date: Sat, 13 Sep 2025 18:01:13 +0800 Subject: [PATCH 4/4] Remove .vscode directory from git tracking --- .vscode/settings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index aa07f6e..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "stm32-for-vscode.openOCDPath": "/usr/bin/openocd", - "files.associations": { - ".fantomasignore": "ignore", - "usbtree.h": "c" - } -} \ No newline at end of file