Skip to content

Commit

Permalink
res_usbradio: Add ability to specify allowed vid:pid (#428)
Browse files Browse the repository at this point in the history
This updates res_usbradio to allow users to specify USB device descriptor(s) that can be used for interface devices.  There are compatible chips that are not supported in the code.  This will allow users to easily add the compatible chip(s).

This adds res_usbradio.conf for configuration.  A sample configuration file was also added.

This closes #359.
  • Loading branch information
KB4MDD authored Dec 16, 2024
1 parent 7c4d46e commit c048cb2
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 18 deletions.
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);
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)))) {
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,
);

0 comments on commit c048cb2

Please sign in to comment.