Initial commit.

This commit is contained in:
2026-02-19 17:45:10 +00:00
commit c44292b744
4 changed files with 527 additions and 0 deletions

229
desk_reminder.c Normal file
View File

@@ -0,0 +1,229 @@
// Simple listener for Alcor AU9540 smartcard reader using libusb-1.0
// Device: Bus 001 Device 002: ID 058f:9540 Alcor Micro Corp. AU9540 Smartcard Reader
//
// This program opens the USB device by VID/PID, finds the first
// interrupt IN endpoint, and listens for slot change / card events.
// It does not implement full CCID or smartcard protocols; it just
// prints raw bytes received from the interrupt endpoint.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <libusb-1.0/libusb.h>
// Target USB device: IC Reader (Bus 001 Device 011: ID ffff:0035)
#define VENDOR_ID 0xffff
#define PRODUCT_ID 0x0035
static volatile int keep_running = 1;
static void handle_signal(int signum)
{
(void)signum;
keep_running = 0;
}
struct listener_context {
libusb_device_handle *handle;
unsigned char endpoint_addr;
};
static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
{
struct listener_context *ctx = (struct listener_context *)transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
printf("[event] %d bytes: ", transfer->actual_length);
for (int i = 0; i < transfer->actual_length; ++i) {
printf("%02x ", transfer->buffer[i]);
}
printf("\n");
fflush(stdout);
if (keep_running) {
int rc = libusb_submit_transfer(transfer);
if (rc != 0) {
fprintf(stderr, "Failed to resubmit transfer: %s\n", libusb_error_name(rc));
libusb_free_transfer(transfer);
}
} else {
libusb_free_transfer(transfer);
}
} else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
libusb_free_transfer(transfer);
} else {
fprintf(stderr, "Transfer error: status=%d (%s)\n",
transfer->status, libusb_error_name(transfer->status));
libusb_free_transfer(transfer);
}
(void)ctx; // currently unused, kept for future extensions
}
static int find_interrupt_in_endpoint(libusb_device_handle *handle,
unsigned char *endpoint_addr_out)
{
libusb_device *dev = libusb_get_device(handle);
struct libusb_config_descriptor *config = NULL;
int rc = libusb_get_active_config_descriptor(dev, &config);
if (rc != 0) {
fprintf(stderr, "Failed to get config descriptor: %s\n", libusb_error_name(rc));
return -1;
}
int found = 0;
for (int i = 0; i < config->bNumInterfaces && !found; ++i) {
const struct libusb_interface *interface = &config->interface[i];
for (int j = 0; j < interface->num_altsetting && !found; ++j) {
const struct libusb_interface_descriptor *alt = &interface->altsetting[j];
for (int k = 0; k < alt->bNumEndpoints && !found; ++k) {
const struct libusb_endpoint_descriptor *ep = &alt->endpoint[k];
if ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) {
*endpoint_addr_out = ep->bEndpointAddress;
found = 1;
}
}
}
}
libusb_free_config_descriptor(config);
if (!found) {
fprintf(stderr, "No interrupt IN endpoint found on device.\n");
return -1;
}
return 0;
}
int main(void)
{
libusb_context *ctx = NULL;
libusb_device_handle *handle = NULL;
int rc;
signal(SIGINT, handle_signal);
signal(SIGTERM, handle_signal);
rc = libusb_init(&ctx);
if (rc != 0) {
fprintf(stderr, "libusb_init failed: %s\n", libusb_error_name(rc));
return EXIT_FAILURE;
}
libusb_set_option(ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
handle = libusb_open_device_with_vid_pid(ctx, VENDOR_ID, PRODUCT_ID);
if (!handle) {
fprintf(stderr, "Unable to open device %04x:%04x. Are you running as root or with correct udev rules?\n",
VENDOR_ID, PRODUCT_ID);
libusb_exit(ctx);
return EXIT_FAILURE;
}
libusb_device *dev = libusb_get_device(handle);
uint8_t bus = libusb_get_bus_number(dev);
uint8_t addr = libusb_get_device_address(dev);
printf("Opened device on bus %03u device %03u (VID:PID %04x:%04x)\n",
bus, addr, VENDOR_ID, PRODUCT_ID);
// Try to claim interface 0 (most CCID readers use it). Detach kernel driver if needed.
int iface = 0;
if (libusb_kernel_driver_active(handle, iface) == 1) {
printf("Kernel driver active on interface %d, detaching...\n", iface);
rc = libusb_detach_kernel_driver(handle, iface);
if (rc != 0) {
fprintf(stderr, "Failed to detach kernel driver: %s\n", libusb_error_name(rc));
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
}
rc = libusb_claim_interface(handle, iface);
if (rc != 0) {
fprintf(stderr, "Failed to claim interface %d: %s\n", iface, libusb_error_name(rc));
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
unsigned char endpoint_addr = 0;
if (find_interrupt_in_endpoint(handle, &endpoint_addr) != 0) {
libusb_release_interface(handle, iface);
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
printf("Listening on interrupt IN endpoint 0x%02x. Press Ctrl+C to stop.\n",
endpoint_addr);
const int buf_size = 64; // typical interrupt packet size
unsigned char *buffer = (unsigned char *)malloc(buf_size);
if (!buffer) {
fprintf(stderr, "Failed to allocate buffer.\n");
libusb_release_interface(handle, iface);
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
if (!transfer) {
fprintf(stderr, "Failed to allocate transfer.\n");
free(buffer);
libusb_release_interface(handle, iface);
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
struct listener_context listener_ctx;
listener_ctx.handle = handle;
listener_ctx.endpoint_addr = endpoint_addr;
libusb_fill_interrupt_transfer(transfer,
handle,
endpoint_addr,
buffer,
buf_size,
transfer_callback,
&listener_ctx,
0); // timeout 0 = infinite
rc = libusb_submit_transfer(transfer);
if (rc != 0) {
fprintf(stderr, "Failed to submit transfer: %s\n", libusb_error_name(rc));
libusb_free_transfer(transfer);
free(buffer);
libusb_release_interface(handle, iface);
libusb_close(handle);
libusb_exit(ctx);
return EXIT_FAILURE;
}
while (keep_running) {
rc = libusb_handle_events(ctx);
if (rc != 0) {
fprintf(stderr, "libusb_handle_events error: %s\n", libusb_error_name(rc));
break;
}
}
// Clean up: ask libusb to cancel the transfer; the callback is
// responsible for freeing the transfer and buffer when cancellation
// completes or if an error occurred.
libusb_cancel_transfer(transfer);
libusb_release_interface(handle, iface);
libusb_close(handle);
libusb_exit(ctx);
printf("Exiting.\n");
return EXIT_SUCCESS;
}