Files
usb-drivers/upscat-gen-usb.sh
p 74af8e884c
Alpine 3.23 Success
Update README.adoc, upscat touch-ups
The tool only works on Windows with my CyberPower UPS.
2026-07-07 13:49:26 +02:00

154 lines
4.2 KiB
Bash
Executable File

#!/bin/sh -e
# upscat-gen-usb.sh: convert tables from the USB HID specification to C code
#
# Copyright (c) 2026, Přemysl Eric Janouch <p@janouch.name>
# SPDX-License-Identifier: 0BSD
if [ ! -e hut1_7.pdf ]
then curl -LO https://www.usb.org/sites/default/files/hut1_7.pdf
fi
# Our program doesn't need all of them, so we're filtering them here.
process() (qpdf --show-attachment=HidUsageTables.json hut1_7.pdf \
| jq -r '.UsagePages[] | select(.Name | IN("Battery System", "Power")) |
'"$1"' | @tsv' | sort -n -k 1,1 -k 2,2 | awk -F'\t' '
function ident(s) { gsub(/[^[:alnum:]]/, "_", s); return s } '"{ $2 }")
pages='[.Id, .Name]'
usages='. as $page | $page.UsageIds[] |
[$page.Id, .Id, $page.Name, (.Name | gsub("\\\\_"; "_")),
(.Kinds | join("/"))]'
generated='. as $page | .UsageIdGenerator | select(.) |
[$page.Id, .StartUsageId, .EndUsageId, $page.Name, .NamePrefix,
(.Kinds | join("/"))]'
cat <<EOF >upscat-usb.h
// Code generated by $0. DO NOT EDIT.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
enum {
USB_HID_COLLECTION_PHYSICAL = 0x00,
USB_HID_COLLECTION_APPLICATION = 0x01,
USB_HID_COLLECTION_LOGICAL = 0x02,
USB_HID_COLLECTION_REPORT = 0x03,
USB_HID_COLLECTION_NAMED_ARRAY = 0x04,
USB_HID_COLLECTION_USAGE_SWITCH = 0x05,
USB_HID_COLLECTION_USAGE_MODIFIER = 0x06,
};
enum {
$(process "$pages" '
printf("\t/// %s\n", $2)
printf("\tUSB_HID_USAGE_PAGE__%s = 0x%04x,\n", toupper(ident($2)), $1)
')
};
static const struct usb_hid_usage_page_info {
uint16_t usage_page;
const char *name;
} usb_hid_usage_pages[] = {
$(process "$pages" 'printf("\t{0x%04x, \"%s\"},\n", $1, $2)')
};
$(process "$usages" '
printf("/// %s: %s (%s)\n", $3, $4, $5)
printf("#define USB_HID_USAGE__%s__%s 0x%04x%04x\n",
toupper(ident($3)), toupper(ident($4)), $1, $2)
')
static const struct usb_hid_usage_info {
uint32_t usage;
const char *name;
} usb_hid_usages[] = {
$(process "$usages" 'printf("\t{0x%04x%04x, \"%s\"},\n", $1, $2, $4)')
};
static const struct usb_hid_usage_range_info {
uint32_t usage_start;
uint32_t usage_end;
const char *name_prefix;
} usb_hid_usages_ranged[] = {
$(process "$generated" '
printf("\t// %s (%s)\n", $4, $6)
printf("\t{0x%04x%04x, 0x%04x%04x, \"%s\"},\n", $1, $2, $1, $3, $5)
')
};
static int
usb_hid_usage_pages_cmp(const void *a, const void *b)
{
const uint16_t *key = a;
const struct usb_hid_usage_page_info *entry = b;
return (*key > entry->usage_page) - (*key < entry->usage_page);
}
static int
usb_hid_usages_cmp(const void *a, const void *b)
{
const uint32_t *key = a;
const struct usb_hid_usage_info *entry = b;
return (*key > entry->usage) - (*key < entry->usage);
}
static int
usb_hid_usages_ranged_cmp(const void *a, const void *b)
{
const uint32_t *key = a;
const struct usb_hid_usage_range_info *entry = b;
return (*key > entry->usage_end) - (*key < entry->usage_start);
}
static const char *
usb_hid_usage_page_to_string(uint16_t usage_page)
{
const struct usb_hid_usage_page_info *entry = bsearch(
&usage_page, usb_hid_usage_pages,
sizeof usb_hid_usage_pages / sizeof usb_hid_usage_pages[0],
sizeof usb_hid_usage_pages[0], usb_hid_usage_pages_cmp);
if (entry)
return entry->name;
static char buffer[32];
snprintf(buffer, sizeof buffer, "%04x", usage_page);
return buffer;
}
static const char *
usb_hid_usage_to_string(uint32_t usage)
{
const struct usb_hid_usage_info *info = bsearch(
&usage, usb_hid_usages,
sizeof usb_hid_usages / sizeof usb_hid_usages[0],
sizeof usb_hid_usages[0], usb_hid_usages_cmp);
if (info)
return info->name;
static char buffer[64];
const struct usb_hid_usage_range_info *range = bsearch(
&usage, usb_hid_usages_ranged,
sizeof usb_hid_usages_ranged / sizeof usb_hid_usages_ranged[0],
sizeof usb_hid_usages_ranged[0], usb_hid_usages_ranged_cmp);
if (range) {
snprintf(buffer, sizeof buffer,
"%s %u", range->name_prefix, (unsigned) (usage & 0xffff));
return buffer;
}
snprintf(buffer, sizeof buffer, "%04x", (unsigned) (usage & 0xffff));
return buffer;
}
static const char *
usb_hid_usage_to_string_full(uint32_t usage)
{
static char buffer[128];
snprintf(buffer, sizeof buffer, "%s: %s",
usb_hid_usage_page_to_string(usage >> 16),
usb_hid_usage_to_string(usage));
return buffer;
}
EOF