/*
 * SPDX-FileCopyrightText: 2023 CERN (home.cern)
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

/**
 * @file usb-enum.c
 * @brief OASIS USB Attenuator driver library interface
 */

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libudev.h>

#include "usb-enum.h"

#define	MAX_OUA		16

void oattnusb_display_devarray(struct oattnusb_devarray *ls)
{
	int i;
	for (i = 0; i < ls->ndevs; i++) {
		struct oattnusb_usb_dev *entry = &ls->devs[i];

		printf("%d: busdev:%s:%s bus-port:%s devno:%s serial:%s devpath:%s\n",
			i, entry->busnum, entry->devnum,
			entry->busport, entry->devno, entry->serial, entry->path);
	}
}

static struct oattnusb_usb_dev usb_dev[MAX_OUA];
static struct oattnusb_devarray devarray = { -1, usb_dev, };

struct oattnusb_devarray *oattnusb_get_devarray(unsigned int vendor_id, unsigned int device_id)
{
	struct udev *udev = udev_new();
	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
	struct udev_list_entry *devs, *ptr;
	int found_devs = 0;
	char vid[6], did[6];

	sprintf(vid, "%04x", vendor_id);
	sprintf(did, "%04x", device_id);
	udev_enumerate_add_match_property(enumerate, "ID_VENDOR_ID", vid);
	udev_enumerate_add_match_property(enumerate, "ID_MODEL_ID", did);
	udev_enumerate_scan_devices(enumerate);

	devs = udev_enumerate_get_list_entry(enumerate);
	udev_list_entry_foreach(ptr, devs) {
		if (found_devs >= MAX_OUA)
			goto out;
		const char *path = udev_list_entry_get_name(ptr);
		struct udev_device *dev = udev_device_new_from_syspath(udev, path);
		const char *busnum = udev_device_get_sysattr_value(dev, "busnum");
		const char *devnum = udev_device_get_sysattr_value(dev, "devnum");

		if (busnum && devnum) {
			const char *devno = udev_device_get_sysattr_value(dev, "dev");
			const char *serial = udev_device_get_sysattr_value(dev, "serial");
			struct oattnusb_usb_dev *entry = &usb_dev[found_devs];
			strcpy(entry->path, path);
			strcpy(entry->busnum, busnum);
			strcpy(entry->devnum, devnum);
			strcpy(entry->devno, devno);
			if (serial) {
				strcpy(entry->serial, serial);
			}
			else {
				strcpy(entry->serial, "EMPTY");
			}
			strcpy(entry->busport, rindex(entry->path, '/') + 1);

			found_devs += 1;
		}
		udev_device_unref(dev);
	}
out:
	udev_enumerate_unref(enumerate);
	devarray.ndevs = found_devs;
	return &devarray;
}
