Implementing USB Hotplug Detection with QT and Embedded Linux

Click the “Embedded Application Research Institute” above, and select “Pin/Star the Public Account

Valuable Resources Delivered Instantly!

Source | CSDN

Author | Job Seeker First

Supplement | Embedded Application Research Institute

Recently, I have been working on some projects related to Linux and QT, which involve the interaction between USB hotplugging and the QT interface. I referred to the methods recommended by Google and many excellent bloggers – using netlink to listen for events; of course, this requires that Linux itself is configured with a hotplug mechanism. The specific implementation method is as follows:

In embedded development, especially on gateways, routers, or other terminals that support USB devices, to enhance user experience, we often need to support the automatic recognition and mounting of USB devices. The application of USB hotplugging is widespread, such as for USB drives, mobile phones, USB network cards, etc.

Some applications, during the use of USB devices, also hope to detect USB disconnection events, so that certain tasks are not wasted because the USB no longer exists, or they need to display an icon indicating whether the USB drive is plugged in. In Linux, there are mainly two methods to detect USB hotplugging.

1. Folder Detection Method

The first method is to periodically check the files in the /proc/scsi/ directory, where the current device’s mounted storage media basic information is stored in a standard format. On the PC side, apart from the hard drive (ATA) and optical drive (CD-ROM), it is the USB device (Direct-Access). By polling this scsi file, we can check whether there is new or reduced data to achieve automatic detection of USB hotplugging.

However, this method is not ideal for hotplug devices like USB drives, as we do not know when the device is plugged in or unplugged; we can only verify whether it is currently plugged in or unplugged. Applications can generally use timer processing functions to continuously query, thereby updating the USB plug-in and unplugging status.

To address this issue, we have another method. We use a special class of file descriptors (sockets) specifically for asynchronous communication between the Linux kernel and user space, a technique commonly referred to as NETLINK.

Display when USB drive is inserted: (In my device, it is the usb-storage folder)

Implementing USB Hotplug Detection with QT and Embedded Linux

Display when USB drive is unplugged:

Implementing USB Hotplug Detection with QT and Embedded Linux

2. Netlink Capture USB Plugging and Unplugging Events

In Linux, udev is used to manage hotplugging, and using netlink to listen to udev messages can provide management strategies for user space. By parsing the strings in the messages, control logic can be completed. After capturing the messages with netlink, parsing the strings can further identify what type of device it is, thus completing logical control in user space.

Since NETLINK is a built-in feature of Linux, it is very simple to use:

1. Create a special file descriptor (socket) of type NETLINK_KOBJECT_UEVENT under the AF_NETLINK protocol family.

2. Then use setsocketopt to allow this file descriptor (socket) to reuse other ports, and then use the band function to bind the process to the special file descriptor (socket).

3. Finally, use select within a while loop to listen to whether the file descriptor (socket) is readable. If it is readable, call recv to receive the data passed from the Linux system kernel and print it out. These outputs are the USB hotplugging information; of course, you can also customize how to handle the hotplugging information from the kernel to make the program more intelligent and user-friendly.

The C language implementation code for detecting USB hotplugging using NETLINK is as follows:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define UEVENT_BUFFER_SIZE 2048

int main(void)
{
    struct sockaddr_nl client;
    struct timeval tv;
    int CppLive, rcvlen, ret;
    fd_set fds;
    int buffersize = 1024;
    CppLive = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    memset(&client, 0, sizeof(client));
    client.nl_family = AF_NETLINK;
    client.nl_pid = getpid();
    client.nl_groups = 1; /* receive broadcast message*/
    setsockopt(CppLive, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
    bind(CppLive, (struct sockaddr*)&client, sizeof(client));
    while (1) {
        char buf[UEVENT_BUFFER_SIZE] = { 0 };
        FD_ZERO(&fds);
        FD_SET(CppLive, &fds);
        tv.tv_sec = 0;
        tv.tv_usec = 100 * 1000;
        ret = select(CppLive + 1, &fds, NULL, NULL, &tv);
        if(ret < 0)
            continue;
        if(!(ret > 0 && FD_ISSET(CppLive, &fds)))
            continue;
        /* receive data */
        rcvlen = recv(CppLive, &buf, sizeof(buf), 0);
        if (rcvlen > 0) {
            printf("%s\n", buf);
            /*You can do something here to make the program more perfect!!!*/
        }
    }
    close(CppLive);
    return 0;
}

We can add our interaction handling logic with the application in the following area:

if (rcvlen > 0) {
  printf("%s\n", buf);
  /*You can do something here to make the program more perfect!!!*/
}

When the USB drive is inserted, use the strstr function to check if the buf contains a certain substring and write the insertion status to a file. When the USB drive is unplugged, use the strstr function to check if buf contains a certain substring and write the unplugging status to a file. The QT program only needs to implement the corresponding logic (such as starting a timer) to read the status indicated in this file, which can be used for UI-related status display and interaction. Of course, other methods can also be used to achieve this.

We can also integrate the relevant logic directly into QT. However, I personally do not advocate this approach, as it can be difficult to locate issues. The best practice is to decouple the handling logic from the UI display, ensuring the simplicity and maintainability of the UI interface.

With this functionality, many small modules can be expanded later, such as USB drive upgrades, file reading, USB encryption and decryption, loading scripts, etc. If interested, stay tuned!

References

[1]https://blog.csdn.net/weixin_42887343/article/details/119388302

Previous Highlights

Inter-process Communication in Linux (Part 1) – Pipe, Message Queue Practice

Inter-process Communication in Linux (Part 2) – Signal, Semaphore Practice

Inter-process Communication in Linux (Part 3) – Shared Memory Practice

Debugging Linux Screen Backlight Based on Rockchip RV1109

Embedded Linux QT Application Development Thoughts on WIFI Search, Display, and Connection

Embedded Linux MIPI Interface LCD Debugging – Concentrated Insights on DRM Display and Application Debugging

If you find this article helpful, please click<span>[Looking]</span> and share, it is also a support for me.

Leave a Comment