mirror of https://github.com/nirenjan/libx52.git
125 lines
3.8 KiB
C
125 lines
3.8 KiB
C
/*
|
|
* LibUSB stub driver for hotplug APIs
|
|
*
|
|
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <pthread.h>
|
|
|
|
#include <libusb.h>
|
|
#include "libusbx52.h"
|
|
|
|
#define CB_HANDLE_MAGIC 0xca11bacc
|
|
|
|
static void *service_hotplug_events(void *args)
|
|
{
|
|
libusb_context *ctx = args;
|
|
int parsed;
|
|
int vid;
|
|
int pid;
|
|
char action;
|
|
char *dev_fifo_file;
|
|
FILE *fifo;
|
|
libusb_device *dev;
|
|
|
|
// Get the filename of the FIFO
|
|
dev_fifo_file = getenv(INPUT_DEVICE_FIFO_ENV);
|
|
if (dev_fifo_file == NULL || dev_fifo_file[0] == '\0') {
|
|
dev_fifo_file = DEFAULT_INPUT_DEVICE_FIFO_FILE;
|
|
}
|
|
|
|
// Remove the FIFO if it exists
|
|
unlink(dev_fifo_file);
|
|
|
|
// Create the FIFO
|
|
mkfifo(dev_fifo_file, 0777);
|
|
|
|
fifo = fopen(dev_fifo_file, "r");
|
|
if (fifo == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
while (!ctx->stop_thread) {
|
|
parsed = fscanf(fifo, "%c %x %x", &action, &vid, &pid);
|
|
if (parsed == 3) {
|
|
switch (action) {
|
|
case '+':
|
|
dev = vector_push(ctx, vid, pid);
|
|
if ((ctx->events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) &&
|
|
(ctx->hotplug_vid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_vid == vid) &&
|
|
(ctx->hotplug_pid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_pid == pid)) {
|
|
(ctx->callback)(ctx, dev,
|
|
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
|
|
ctx->cb_user_data);
|
|
}
|
|
break;
|
|
|
|
case '-':
|
|
dev = vector_pop(ctx, vid, pid);
|
|
if ((ctx->events & LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) &&
|
|
(ctx->hotplug_vid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_vid == vid) &&
|
|
(ctx->hotplug_pid == LIBUSB_HOTPLUG_MATCH_ANY || ctx->hotplug_pid == pid)) {
|
|
(ctx->callback)(ctx, dev,
|
|
LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
|
|
ctx->cb_user_data);
|
|
}
|
|
break;
|
|
|
|
case 'x':
|
|
/* Terminate the loop */
|
|
ctx->stop_thread = 1;
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Close the FIFO
|
|
fclose(fifo);
|
|
return NULL;
|
|
}
|
|
|
|
int libusb_hotplug_register_callback(libusb_context *ctx,
|
|
libusb_hotplug_event events,
|
|
libusb_hotplug_flag flags,
|
|
int vendor_id,
|
|
int product_id,
|
|
int dev_class,
|
|
libusb_hotplug_callback_fn cb_fn,
|
|
void *user_data,
|
|
libusb_hotplug_callback_handle *cb_handle)
|
|
{
|
|
// Save the events, flags, etc in the context.
|
|
ctx->hotplug_vid = vendor_id;
|
|
ctx->hotplug_pid = product_id;
|
|
ctx->events = events;
|
|
|
|
ctx->callback = cb_fn;
|
|
ctx->cb_user_data = user_data;
|
|
|
|
// Spawn the thread
|
|
pthread_create(&(ctx->hotplug_pthread), NULL, service_hotplug_events, ctx);
|
|
|
|
// Since the stub library only accepts a single callback function,
|
|
// we will return a static value that will be used to check when
|
|
// deregistering. Only if the value matches will we terminate the thread.
|
|
*cb_handle = CB_HANDLE_MAGIC;
|
|
return LIBUSB_SUCCESS;
|
|
}
|
|
|
|
void libusb_hotplug_deregister_callback(libusb_context *ctx,
|
|
libusb_hotplug_callback_handle cb_handle)
|
|
{
|
|
if (cb_handle == CB_HANDLE_MAGIC) {
|
|
ctx->stop_thread = 1;
|
|
pthread_join(ctx->hotplug_pthread, NULL);
|
|
}
|
|
}
|