/** * @file hidapi_dummy.c * @brief Stub implementation of HIDAPI 0.15.0 to prevent crashes when HID access fails. * * This library provides a complete no-op implementation of the HIDAPI interface. * All device enumeration returns empty lists, all device operations fail gracefully. * * Purpose: Linphone's liblinphone SDK crashes when it cannot access /dev/hidraw* devices * (for USB headset button support). This stub library prevents those crashes by * intercepting all HID calls and returning safe, predictable values. * * Build: gcc -shared -fPIC -O2 -Wall -Wextra -o libhidapi-hidraw.so.0 hidapi_dummy.c * Usage: LD_PRELOAD=/path/to/libhidapi-hidraw.so.0 ./application * * @author Generated for Linphone crash workaround * @version 0.15.0 (matching HIDAPI version) * @see https://github.com/libusb/hidapi */ #define _GNU_SOURCE #include #include /* ============================================================================ * Type Definitions (matching hidapi.h) * ============================================================================ */ /** Opaque device handle - we never actually allocate these */ struct hid_device_; typedef struct hid_device_ hid_device; /** HID bus types */ typedef enum { HID_API_BUS_UNKNOWN = 0x00, HID_API_BUS_USB = 0x01, HID_API_BUS_BLUETOOTH = 0x02, HID_API_BUS_I2C = 0x03, HID_API_BUS_SPI = 0x04, } hid_bus_type; /** Device information structure */ struct hid_device_info { char *path; unsigned short vendor_id; unsigned short product_id; wchar_t *serial_number; unsigned short release_number; wchar_t *manufacturer_string; wchar_t *product_string; unsigned short usage_page; unsigned short usage; int interface_number; struct hid_device_info *next; hid_bus_type bus_type; }; /** Version information structure */ struct hid_api_version { int major; int minor; int patch; }; /* ============================================================================ * Static Data * ============================================================================ */ /** Version info matching HIDAPI 0.15.0 */ static const struct hid_api_version g_version = { .major = 0, .minor = 15, .patch = 0 }; /** Version string */ static const char g_version_str[] = "0.15.0-stub"; /** Error message for NULL device operations */ static const wchar_t g_error_no_device[] = L"No HID devices available (stub library)"; /** Error message for successful operations */ static const wchar_t g_error_none[] = L"Success"; /** Global initialization state */ static int g_initialized = 0; /* ============================================================================ * Library Initialization / Cleanup * ============================================================================ */ /** * @brief Initialize the HIDAPI library. * @return 0 on success (always succeeds) */ int hid_init(void) { g_initialized = 1; return 0; } /** * @brief Finalize the HIDAPI library. * @return 0 on success (always succeeds) */ int hid_exit(void) { g_initialized = 0; return 0; } /* ============================================================================ * Device Enumeration * ============================================================================ */ /** * @brief Enumerate HID devices. * @param vendor_id Vendor ID filter (0 = any) * @param product_id Product ID filter (0 = any) * @return NULL (no devices available in stub) */ struct hid_device_info* hid_enumerate(unsigned short vendor_id, unsigned short product_id) { (void)vendor_id; (void)product_id; /* Ensure library is initialized */ if (!g_initialized) { hid_init(); } /* Return empty list - no devices */ return NULL; } /** * @brief Free an enumeration linked list. * @param devs Pointer to device list (ignored, nothing to free) */ void hid_free_enumeration(struct hid_device_info *devs) { (void)devs; /* Nothing to free - we never allocate device info */ } /* ============================================================================ * Device Open / Close * ============================================================================ */ /** * @brief Open a HID device by VID/PID. * @param vendor_id Vendor ID * @param product_id Product ID * @param serial_number Serial number (optional) * @return NULL (device not found) */ hid_device* hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) { (void)vendor_id; (void)product_id; (void)serial_number; if (!g_initialized) { hid_init(); } return NULL; } /** * @brief Open a HID device by path. * @param path Device path (e.g., /dev/hidraw0) * @return NULL (device not found) */ hid_device* hid_open_path(const char *path) { (void)path; if (!g_initialized) { hid_init(); } return NULL; } /** * @brief Close a HID device. * @param dev Device handle (ignored) */ void hid_close(hid_device *dev) { (void)dev; /* Nothing to close */ } /* ============================================================================ * Device I/O Operations * ============================================================================ */ /** * @brief Write an output report to a HID device. * @param dev Device handle * @param data Data buffer * @param length Buffer length * @return -1 (error - no device) */ int hid_write(hid_device *dev, const unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return -1; } /** * @brief Read an input report with timeout. * @param dev Device handle * @param data Buffer for data * @param length Buffer size * @param milliseconds Timeout (-1 for blocking) * @return 0 (no data available) */ int hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) { (void)dev; (void)data; (void)length; (void)milliseconds; return 0; } /** * @brief Read an input report. * @param dev Device handle * @param data Buffer for data * @param length Buffer size * @return 0 (no data available) */ int hid_read(hid_device *dev, unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return 0; } /** * @brief Set non-blocking mode. * @param dev Device handle * @param nonblock 1 for non-blocking, 0 for blocking * @return -1 (error - no device) */ int hid_set_nonblocking(hid_device *dev, int nonblock) { (void)dev; (void)nonblock; return -1; } /* ============================================================================ * Feature / Output / Input Reports * ============================================================================ */ /** * @brief Send a feature report. * @param dev Device handle * @param data Report data * @param length Data length * @return -1 (error - no device) */ int hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return -1; } /** * @brief Get a feature report. * @param dev Device handle * @param data Buffer for report * @param length Buffer size * @return -1 (error - no device) */ int hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return -1; } /** * @brief Send an output report (since 0.15.0). * @param dev Device handle * @param data Report data * @param length Data length * @return -1 (error - no device) */ int hid_send_output_report(hid_device *dev, const unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return -1; } /** * @brief Get an input report. * @param dev Device handle * @param data Buffer for report * @param length Buffer size * @return -1 (error - no device) */ int hid_get_input_report(hid_device *dev, unsigned char *data, size_t length) { (void)dev; (void)data; (void)length; return -1; } /** * @brief Get a report descriptor (since 0.14.0). * @param dev Device handle * @param buf Buffer for descriptor * @param buf_size Buffer size * @return -1 (error - no device) */ int hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size) { (void)dev; (void)buf; (void)buf_size; return -1; } /* ============================================================================ * Device Information Retrieval * ============================================================================ */ /** * @brief Get manufacturer string. * @param dev Device handle * @param string Buffer for string * @param maxlen Buffer size in wchar_t units * @return -1 (error - no device) */ int hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) { (void)dev; (void)string; (void)maxlen; return -1; } /** * @brief Get product string. * @param dev Device handle * @param string Buffer for string * @param maxlen Buffer size in wchar_t units * @return -1 (error - no device) */ int hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) { (void)dev; (void)string; (void)maxlen; return -1; } /** * @brief Get serial number string. * @param dev Device handle * @param string Buffer for string * @param maxlen Buffer size in wchar_t units * @return -1 (error - no device) */ int hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) { (void)dev; (void)string; (void)maxlen; return -1; } /** * @brief Get device info structure (since 0.13.0). * @param dev Device handle * @return NULL (no device info available) */ struct hid_device_info* hid_get_device_info(hid_device *dev) { (void)dev; return NULL; } /** * @brief Get indexed string. * @param dev Device handle * @param string_index String index * @param string Buffer for string * @param maxlen Buffer size in wchar_t units * @return -1 (error - no device) */ int hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) { (void)dev; (void)string_index; (void)string; (void)maxlen; return -1; } /* ============================================================================ * Error Handling * ============================================================================ */ /** * @brief Get last error string. * @param dev Device handle (NULL for global error) * @return Error description (never NULL) */ const wchar_t* hid_error(hid_device *dev) { if (dev == NULL) { return g_error_no_device; } return g_error_none; } /** * @brief Get last read error string (since 0.15.0). * @param dev Device handle * @return Error description (never NULL) */ const wchar_t* hid_read_error(hid_device *dev) { (void)dev; return g_error_none; } /* ============================================================================ * Version Information * ============================================================================ */ /** * @brief Get library version structure. * @return Pointer to static version info */ const struct hid_api_version* hid_version(void) { return &g_version; } /** * @brief Get library version string. * @return Version string */ const char* hid_version_str(void) { return g_version_str; }