Retrieve and store the device serial number
This commit is contained in:
142
src/alsa.c
142
src/alsa.c
@@ -523,6 +523,7 @@ static void card_destroy_callback(void *data) {
|
|||||||
|
|
||||||
// TODO: there is more to free
|
// TODO: there is more to free
|
||||||
free(card->device);
|
free(card->device);
|
||||||
|
free(card->serial);
|
||||||
free(card->name);
|
free(card->name);
|
||||||
free(card);
|
free(card);
|
||||||
|
|
||||||
@@ -555,6 +556,146 @@ static void alsa_subscribe(struct alsa_card *card) {
|
|||||||
snd_ctl_poll_descriptors(card->handle, &card->pfd, 1);
|
snd_ctl_poll_descriptors(card->handle, &card->pfd, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// get the bus and device numbers from /proc/asound/cardxx/usbbus
|
||||||
|
// format is XXX/YYY
|
||||||
|
static int alsa_get_usbbus(struct alsa_card *card, int *bus, int *dev) {
|
||||||
|
char path[256];
|
||||||
|
snprintf(path, 256, "/proc/asound/card%d/usbbus", card->num);
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "can't open %s\n", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = fscanf(f, "%d/%d", bus, dev);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (result != 2) {
|
||||||
|
fprintf(stderr, "can't read %s\n", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the devnum file in bus_path
|
||||||
|
// /sys/bus/usb/devices/usbBUS/BUS-PORT/devnum
|
||||||
|
// and return the value within
|
||||||
|
static int usb_get_devnum(const char *bus_path) {
|
||||||
|
char devnum_path[512];
|
||||||
|
snprintf(devnum_path, 512, "%s/devnum", bus_path);
|
||||||
|
|
||||||
|
FILE *f = fopen(devnum_path, "r");
|
||||||
|
if (!f) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fprintf(stderr, "can't open %s: %s\n", devnum_path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int devnum;
|
||||||
|
int result = fscanf(f, "%d", &devnum);
|
||||||
|
int err = errno;
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (result != 1) {
|
||||||
|
fprintf(stderr, "can't read %s: %s\n", devnum_path, strerror(err));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return devnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursively search for the device with the given dev number
|
||||||
|
// in the /sys/bus/usb/devices/usbX/Y-Z hierarchy
|
||||||
|
// and return the path to the port
|
||||||
|
static int usb_find_device_port(
|
||||||
|
const char *bus_path,
|
||||||
|
int bus,
|
||||||
|
int dev,
|
||||||
|
char *port_path,
|
||||||
|
size_t port_path_size
|
||||||
|
) {
|
||||||
|
if (usb_get_devnum(bus_path) == dev) {
|
||||||
|
snprintf(port_path, port_path_size, "%s", bus_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIR *dir = opendir(bus_path);
|
||||||
|
if (!dir) {
|
||||||
|
fprintf(stderr, "can't open %s: %s\n", bus_path, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// looking for d_name beginning with the bus number followed by a "-"
|
||||||
|
char prefix[20];
|
||||||
|
snprintf(prefix, 20, "%d-", bus);
|
||||||
|
|
||||||
|
struct dirent *entry;
|
||||||
|
while ((entry = readdir(dir))) {
|
||||||
|
if (entry->d_type != DT_DIR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(entry->d_name, prefix, strlen(prefix)) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char next_path[512];
|
||||||
|
snprintf(next_path, 512, "%s/%s", bus_path, entry->d_name);
|
||||||
|
|
||||||
|
if (usb_find_device_port(next_path, bus, dev, port_path, port_path_size)) {
|
||||||
|
closedir(dir);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alsa_get_serial_number(struct alsa_card *card) {
|
||||||
|
|
||||||
|
int result, bus, dev;
|
||||||
|
if (!alsa_get_usbbus(card, &bus, &dev))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// recurse through /sys/bus/usb/devices/usbBUS/BUS-.../devnum
|
||||||
|
// to find the device with the matching dev number
|
||||||
|
char bus_path[80];
|
||||||
|
snprintf(bus_path, 80, "/sys/bus/usb/devices/usb%d", bus);
|
||||||
|
|
||||||
|
char port_path[512];
|
||||||
|
|
||||||
|
if (!usb_find_device_port(bus_path, bus, dev, port_path, sizeof(port_path))) {
|
||||||
|
fprintf(
|
||||||
|
stderr,
|
||||||
|
"can't find port name in %s for dev %d (%s)\n",
|
||||||
|
bus_path, dev, card->name
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read the serial number
|
||||||
|
char serial_path[520];
|
||||||
|
snprintf(serial_path, 520, "%s/serial", port_path);
|
||||||
|
FILE *f = fopen(serial_path, "r");
|
||||||
|
if (!f) {
|
||||||
|
fprintf(stderr, "can't open %s\n", serial_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char serial[40];
|
||||||
|
result = fscanf(f, "%39s", serial);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (result != 1) {
|
||||||
|
fprintf(stderr, "can't read %s\n", serial_path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
card->serial = strdup(serial);
|
||||||
|
}
|
||||||
|
|
||||||
void alsa_scan_cards(void) {
|
void alsa_scan_cards(void) {
|
||||||
snd_ctl_card_info_t *info;
|
snd_ctl_card_info_t *info;
|
||||||
snd_ctl_t *ctl;
|
snd_ctl_t *ctl;
|
||||||
@@ -599,6 +740,7 @@ void alsa_scan_cards(void) {
|
|||||||
|
|
||||||
alsa_get_elem_list(card);
|
alsa_get_elem_list(card);
|
||||||
alsa_subscribe(card);
|
alsa_subscribe(card);
|
||||||
|
alsa_get_serial_number(card);
|
||||||
|
|
||||||
create_card_window(card);
|
create_card_window(card);
|
||||||
alsa_add_card_callback(card);
|
alsa_add_card_callback(card);
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ struct alsa_elem {
|
|||||||
struct alsa_card {
|
struct alsa_card {
|
||||||
int num;
|
int num;
|
||||||
char *device;
|
char *device;
|
||||||
|
char *serial;
|
||||||
char *name;
|
char *name;
|
||||||
snd_ctl_t *handle;
|
snd_ctl_t *handle;
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
|
|||||||
Reference in New Issue
Block a user