Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

res_usbradio: Add ability to specify allowed vid:pid #428

Merged
merged 4 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions configs/rpt/res_usbradio.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[general]
;usb_devices = 1209:7388 ;comma delimited list of usb
;descriptors to allow.
;format vvvv:pppp in hexadecimal
;vvvv=vendor id, pppp=product id
;
;1209:7388 = AIOC (all in one cable)
7 changes: 7 additions & 0 deletions configs/samples/res_usbradio.conf.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[general]
;usb_devices = 1209:7388 ;comma delimited list of usb
;descriptors to allow.
;format vvvv:pppp in hexadecimal
;vvvv=vendor id, pppp=product id
;
;1209:7388 = AIOC (all in one cable)
184 changes: 166 additions & 18 deletions res/res_usbradio.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/poll-compat.h" /* Used for polling */
#include "asterisk/config.h"

#define CONFIG_FILE "res_usbradio.conf"

AST_MUTEX_DEFINE_STATIC(usb_list_lock);

Expand All @@ -78,6 +81,33 @@ AST_MUTEX_DEFINE_STATIC(usb_list_lock);
static char *usb_device_list = NULL;
static int usb_device_list_size = 0;

/*!
* \brief Structure for defined usb devices.
*/
struct usb_device_entry {
unsigned short idVendor;
unsigned short idProduct;
unsigned short idMask;
AST_LIST_ENTRY(usb_device_entry) entry;
};

/*!
* \brief Array of known compatible usb devices.
*/
const struct usb_device_entry known_devices[] = {
{ C108_VENDOR_ID, C108_PRODUCT_ID, 0xfffc, {NULL} },
{ C108_VENDOR_ID, C108B_PRODUCT_ID, 0xffff, {NULL} },
{ C108_VENDOR_ID, C108AH_PRODUCT_ID, 0xffff, {NULL} },
{ C108_VENDOR_ID, C119A_PRODUCT_ID, 0xffff, {NULL} },
{ C108_VENDOR_ID, C119B_PRODUCT_ID, 0xffff, {NULL} },
{ C108_VENDOR_ID, N1KDO_PRODUCT_ID, 0xff00, {NULL} },
{ C108_VENDOR_ID, C119_PRODUCT_ID, 0xffff, {NULL} },
};

/*!
* \brief Linked list of user defined usb devices.
*/
static AST_RWLIST_HEAD_STATIC(user_devices, usb_device_entry);

long ast_radio_lround(double x)
{
Expand Down Expand Up @@ -295,6 +325,52 @@ void ast_radio_put_eeprom(struct usb_dev_handle *handle, unsigned short *buf)
write_eeprom(handle, i, buf[EEPROM_USER_CS_ADDR]);
}

/*!
* \brief See if the passed device matches one of our known devices.
*
* \param dev usb device
* \return 0 does not matches
* \return 1 matches
*/
static int is_known_device(struct usb_device *dev)
{
int index;
int matched_entry = 0;

for (index = 0; index < ARRAY_LEN(known_devices); index++) {
if (dev->descriptor.idVendor == known_devices[index].idVendor &&
dev->descriptor.idProduct == (known_devices[index].idProduct & known_devices[index].idMask)) {
matched_entry = 1;
break;
};
}

return matched_entry;
}

/*!
* \brief See if the passed device matches one of our user defined devices.
*
* \param dev usb device
* \return 0 does not matches
* \return 1 matches
*/
static int is_user_device(struct usb_device *dev)
{
struct usb_device_entry *device;

AST_RWLIST_RDLOCK(&user_devices);
AST_LIST_TRAVERSE(&user_devices, device, entry) {
if (dev->descriptor.idVendor == device->idVendor &&
dev->descriptor.idProduct == device->idProduct) {
break;
};
}
AST_RWLIST_UNLOCK(&user_devices);

return device ? 1 : 0;
}

int ast_radio_hid_device_mklist(void)
{
struct usb_bus *usb_bus;
Expand All @@ -319,15 +395,7 @@ int ast_radio_hid_device_mklist(void)
usb_find_devices();
for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next) {
for (dev = usb_bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idVendor
== C108_VENDOR_ID) &&
(((dev->descriptor.idProduct & 0xfffc) == C108_PRODUCT_ID) ||
(dev->descriptor.idProduct == C108B_PRODUCT_ID) ||
(dev->descriptor.idProduct == C108AH_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119A_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119B_PRODUCT_ID) ||
((dev->descriptor.idProduct & 0xff00) == N1KDO_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119_PRODUCT_ID))) {
if (is_known_device(dev) || is_user_device(dev)) {
sprintf(devstr, "%s/%s", usb_bus->dirname, dev->filename);
for (i = 0; i < 32; i++) {
sprintf(str, "/proc/asound/card%d/usbbus", i);
Expand Down Expand Up @@ -421,15 +489,7 @@ struct usb_device *ast_radio_hid_device_init(const char *desired_device)
usb_find_devices();
for (usb_bus = usb_busses; usb_bus; usb_bus = usb_bus->next) {
for (dev = usb_bus->devices; dev; dev = dev->next) {
if ((dev->descriptor.idVendor
== C108_VENDOR_ID) &&
(((dev->descriptor.idProduct & 0xfffc) == C108_PRODUCT_ID) ||
(dev->descriptor.idProduct == C108B_PRODUCT_ID) ||
(dev->descriptor.idProduct == C108AH_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119A_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119B_PRODUCT_ID) ||
((dev->descriptor.idProduct & 0xff00) == N1KDO_PRODUCT_ID) ||
(dev->descriptor.idProduct == C119_PRODUCT_ID))) {
if (is_known_device(dev) || is_user_device(dev)) {
sprintf(devstr, "%s/%s", usb_bus->dirname, dev->filename);
for (i = 0; i < 32; i++) {
sprintf(str, "/proc/asound/card%d/usbbus", i);
Expand Down Expand Up @@ -820,19 +880,107 @@ void ast_radio_print_rx_audio_stats(int fd, struct rxaudiostatistics *o)
}
}

/*!
* \brief Remove and free up all user devices.
*/
static void cleanup_user_devices(void)
{
struct usb_device_entry *device;
/* Remove all existing devices */
AST_RWLIST_WRLOCK(&user_devices);
KB4MDD marked this conversation as resolved.
Show resolved Hide resolved
while ((device = AST_LIST_REMOVE_HEAD(&user_devices, entry))) {
ast_free(device);
}
AST_RWLIST_UNLOCK(&user_devices);
}

/* Load our configuration */
static int load_config(int reload)
{
struct ast_config *cfg;
struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
const char *varval;

if (!(cfg = ast_config_load(CONFIG_FILE, config_flags))) {
ast_log(LOG_WARNING, "Config file %s not found\n", CONFIG_FILE);
return 0;
} else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
ast_debug(1, "Config file %s unchanged, skipping\n", CONFIG_FILE);
return 0;
} else if (cfg == CONFIG_STATUS_FILEINVALID) {
ast_log(LOG_ERROR, "Config file %s is in an invalid format. Aborting.\n", CONFIG_FILE);
return -1;
}

if (reload) {
cleanup_user_devices();
}

/* general section
* usb_devices format vvvv:pppp,vvvv:pppp where vvvv is usb vendor id and pppp is usb product id
*/
if ((varval = ast_variable_retrieve(cfg, "general", "usb_devices")) && !ast_strlen_zero(varval)) {
struct usb_device_entry *device;
char *item;
char *value;
int idVendor;
int idProduct;

value = ast_strdupa(varval);

/* process the delimited list */
while ((item = strsep(&value, ","))) {

if (sscanf(item, "%04x:%04x", &idVendor, &idProduct) == 2) {
/* allocate space for our device */
if(!(device = ast_calloc(1, sizeof(*device)))) {
KB4MDD marked this conversation as resolved.
Show resolved Hide resolved
break;
}
device->idVendor = idVendor;
device->idProduct = idProduct;
device->idMask = 0xffff;
/* Add it to our list */
AST_RWLIST_WRLOCK(&user_devices);
AST_LIST_INSERT_HEAD(&user_devices, device, entry);
AST_RWLIST_UNLOCK(&user_devices);

ast_debug(1, "Loaded user defined usb device %s", item);
} else {
ast_log(LOG_WARNING,"USB Device descriptor '%s' is in the wrong format", item);
}
}
}

ast_config_destroy(cfg);

return 0;
}

static int reload_module(void)
{
return load_config(1);
}

static int load_module(void)
{
if (load_config(0)) {
return AST_MODULE_LOAD_DECLINE;
}

return 0;
}

static int unload_module(void)
{
cleanup_user_devices();

return 0;
}

AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "USB Radio Resource",
.support_level = AST_MODULE_SUPPORT_EXTENDED,
.load = load_module,
.unload = unload_module,
.reload = reload_module,
.load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
);
Loading