From b97771b229ad9e5b73a4aa8a0c546928965f33c6 Mon Sep 17 00:00:00 2001 From: Danny Lloyd Date: Mon, 25 Nov 2024 07:17:25 -0600 Subject: [PATCH 1/4] res_usbradio: Add ability to specify allowed vid:pid 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. --- configs/rpt/res_usbradio.conf | 7 ++ configs/samples/res_usbradio.conf.sample | 7 ++ res/res_usbradio.c | 139 ++++++++++++++++++++++- 3 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 configs/rpt/res_usbradio.conf create mode 100644 configs/samples/res_usbradio.conf.sample diff --git a/configs/rpt/res_usbradio.conf b/configs/rpt/res_usbradio.conf new file mode 100644 index 0000000..5f0c988 --- /dev/null +++ b/configs/rpt/res_usbradio.conf @@ -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) diff --git a/configs/samples/res_usbradio.conf.sample b/configs/samples/res_usbradio.conf.sample new file mode 100644 index 0000000..5f0c988 --- /dev/null +++ b/configs/samples/res_usbradio.conf.sample @@ -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) diff --git a/res/res_usbradio.c b/res/res_usbradio.c index c7f9175..e99082d 100644 --- a/res/res_usbradio.c +++ b/res/res_usbradio.c @@ -47,6 +47,7 @@ #include #include #include +#include "asterisk/config.h" #include "asterisk/res_usbradio.h" @@ -68,6 +69,8 @@ #include "asterisk/cli.h" #include "asterisk/poll-compat.h" /* Used for polling */ +#define CONFIG_FILE "res_usbradio.conf" + AST_MUTEX_DEFINE_STATIC(usb_list_lock); /*! @@ -78,6 +81,17 @@ AST_MUTEX_DEFINE_STATIC(usb_list_lock); static char *usb_device_list = NULL; static int usb_device_list_size = 0; +/*! + * \brief Structure for user defined usb devices. + */ +struct user_usb_device { + ushort idVendor; + ushort idProduct; + AST_LIST_ENTRY(user_usb_device) entry; +}; + +static AST_RWLIST_HEAD_STATIC(user_devices, user_usb_device); + long ast_radio_lround(double x) { @@ -294,6 +308,30 @@ void ast_radio_put_eeprom(struct usb_dev_handle *handle, unsigned short *buf) buf[EEPROM_USER_CS_ADDR] = (65535 - cs) + 1; write_eeprom(handle, i, buf[EEPROM_USER_CS_ADDR]); } +/*! + * \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 user_usb_device *device; + int match_found = 0; + + AST_RWLIST_RDLOCK(&user_devices); + AST_LIST_TRAVERSE(&user_devices, device, entry) { + if(dev->descriptor.idVendor == device->idVendor && + dev->descriptor.idProduct == device->idProduct) { + match_found = 1; + break; + }; + } + AST_RWLIST_UNLOCK(&user_devices); + + return match_found; +} int ast_radio_hid_device_mklist(void) { @@ -319,15 +357,15 @@ 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) && + 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))) { + (dev->descriptor.idProduct == C119_PRODUCT_ID))) || + 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); @@ -421,15 +459,15 @@ 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) && + 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))) { + (dev->descriptor.idProduct == C119_PRODUCT_ID))) || + 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); @@ -820,13 +858,101 @@ 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 user_usb_device *device; + /* Remove all existing devices */ + AST_RWLIST_WRLOCK(&user_devices); + AST_LIST_TRAVERSE_SAFE_BEGIN(&user_devices, device, entry) { + AST_LIST_REMOVE_CURRENT(entry); + ast_free(device); + } + AST_LIST_TRAVERSE_SAFE_END; + 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 user_usb_device *device; + char *item; + char *value; + int idVendor; + int idProduct; + + value = ast_strdupa(varval); + + /* process the delimited list */ + while ((item = ast_strsep(&value, ',', AST_STRSEP_STRIP))) { + + 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; + /*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; } @@ -834,5 +960,6 @@ AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ .support_level = AST_MODULE_SUPPORT_EXTENDED, .load = load_module, .unload = unload_module, + .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, ); From 34fd2e83d4a50cea77808c90c5d304b253296086 Mon Sep 17 00:00:00 2001 From: Danny Lloyd Date: Wed, 27 Nov 2024 06:50:41 -0600 Subject: [PATCH 2/4] res_usbradio: Add ability to specify allowed vid:pid 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 added. Reworked the supported/known USB devices lookup. The supported devices are now in an array. This closes #359. --- configs/rpt/res_usbradio.conf | 12 ++-- configs/samples/res_usbradio.conf.sample | 12 ++-- res/res_usbradio.c | 92 +++++++++++++++--------- 3 files changed, 69 insertions(+), 47 deletions(-) diff --git a/configs/rpt/res_usbradio.conf b/configs/rpt/res_usbradio.conf index 5f0c988..d4d8030 100644 --- a/configs/rpt/res_usbradio.conf +++ b/configs/rpt/res_usbradio.conf @@ -1,7 +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) +;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) diff --git a/configs/samples/res_usbradio.conf.sample b/configs/samples/res_usbradio.conf.sample index 5f0c988..d4d8030 100644 --- a/configs/samples/res_usbradio.conf.sample +++ b/configs/samples/res_usbradio.conf.sample @@ -1,7 +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) +;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) diff --git a/res/res_usbradio.c b/res/res_usbradio.c index e99082d..afa79c3 100644 --- a/res/res_usbradio.c +++ b/res/res_usbradio.c @@ -82,16 +82,32 @@ static char *usb_device_list = NULL; static int usb_device_list_size = 0; /*! - * \brief Structure for user defined usb devices. + * \brief Structure for defined usb devices. */ -struct user_usb_device { +struct usb_device_entry { ushort idVendor; ushort idProduct; - AST_LIST_ENTRY(user_usb_device) entry; + ushort idMask; + AST_LIST_ENTRY(usb_device_entry) entry; }; -static AST_RWLIST_HEAD_STATIC(user_devices, user_usb_device); +/*! + * \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) { @@ -308,6 +324,31 @@ void ast_radio_put_eeprom(struct usb_dev_handle *handle, unsigned short *buf) buf[EEPROM_USER_CS_ADDR] = (65535 - cs) + 1; 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 max_entries = sizeof(known_devices) / sizeof(known_devices[0]); + int matched_entry = 0; + + for (index = 0; index < max_entries; 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. * @@ -317,20 +358,18 @@ void ast_radio_put_eeprom(struct usb_dev_handle *handle, unsigned short *buf) */ static int is_user_device(struct usb_device *dev) { - struct user_usb_device *device; - int match_found = 0; + struct usb_device_entry *device; AST_RWLIST_RDLOCK(&user_devices); AST_LIST_TRAVERSE(&user_devices, device, entry) { - if(dev->descriptor.idVendor == device->idVendor && + if (dev->descriptor.idVendor == device->idVendor && dev->descriptor.idProduct == device->idProduct) { - match_found = 1; break; }; } AST_RWLIST_UNLOCK(&user_devices); - return match_found; + return device ? 1 : 0; } int ast_radio_hid_device_mklist(void) @@ -357,15 +396,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))) || - is_user_device(dev)) { + 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); @@ -459,15 +490,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))) || - is_user_device(dev)) { + 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); @@ -863,14 +886,12 @@ void ast_radio_print_rx_audio_stats(int fd, struct rxaudiostatistics *o) */ static void cleanup_user_devices(void) { - struct user_usb_device *device; + struct usb_device_entry *device; /* Remove all existing devices */ AST_RWLIST_WRLOCK(&user_devices); - AST_LIST_TRAVERSE_SAFE_BEGIN(&user_devices, device, entry) { - AST_LIST_REMOVE_CURRENT(entry); + while ((device = AST_LIST_REMOVE_HEAD(&user_devices, entry))) { ast_free(device); } - AST_LIST_TRAVERSE_SAFE_END; AST_RWLIST_UNLOCK(&user_devices); } @@ -900,7 +921,7 @@ static int load_config(int reload) * 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 user_usb_device *device; + struct usb_device_entry *device; char *item; char *value; int idVendor; @@ -909,16 +930,17 @@ static int load_config(int reload) value = ast_strdupa(varval); /* process the delimited list */ - while ((item = ast_strsep(&value, ',', AST_STRSEP_STRIP))) { + while ((item = strsep(&value, ","))) { - if(sscanf(item, "%04x:%04x", &idVendor, &idProduct) == 2) { + 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; - /*Add it to our list */ + device->idMask = 0xfff; + /* Add it to our list */ AST_RWLIST_WRLOCK(&user_devices); AST_LIST_INSERT_HEAD(&user_devices, device, entry); AST_RWLIST_UNLOCK(&user_devices); From 2aefa31c2c950028ea9cdc009ce77a3e74112863 Mon Sep 17 00:00:00 2001 From: Danny Lloyd Date: Wed, 27 Nov 2024 08:15:41 -0600 Subject: [PATCH 3/4] res_usbradio: Add ability to specify allowed vid:pid 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 added. Reworked the supported/known USB devices lookup. The supported devices are now in an array. This closes #359. --- res/res_usbradio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/res_usbradio.c b/res/res_usbradio.c index afa79c3..ea6c7da 100644 --- a/res/res_usbradio.c +++ b/res/res_usbradio.c @@ -939,7 +939,7 @@ static int load_config(int reload) } device->idVendor = idVendor; device->idProduct = idProduct; - device->idMask = 0xfff; + device->idMask = 0xffff; /* Add it to our list */ AST_RWLIST_WRLOCK(&user_devices); AST_LIST_INSERT_HEAD(&user_devices, device, entry); From 57fca49eb795d69becca77b28fb884ce7c645668 Mon Sep 17 00:00:00 2001 From: Danny Lloyd Date: Fri, 6 Dec 2024 06:31:58 -0600 Subject: [PATCH 4/4] res_usbradio: Add ability to specify allowed vid:pid 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 added. Reworked the supported/known USB devices lookup. The supported devices are now in an array. This closes #359. --- res/res_usbradio.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/res/res_usbradio.c b/res/res_usbradio.c index ea6c7da..ea49fac 100644 --- a/res/res_usbradio.c +++ b/res/res_usbradio.c @@ -47,7 +47,6 @@ #include #include #include -#include "asterisk/config.h" #include "asterisk/res_usbradio.h" @@ -68,6 +67,7 @@ #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" @@ -85,9 +85,9 @@ static int usb_device_list_size = 0; * \brief Structure for defined usb devices. */ struct usb_device_entry { - ushort idVendor; - ushort idProduct; - ushort idMask; + unsigned short idVendor; + unsigned short idProduct; + unsigned short idMask; AST_LIST_ENTRY(usb_device_entry) entry; }; @@ -335,10 +335,9 @@ void ast_radio_put_eeprom(struct usb_dev_handle *handle, unsigned short *buf) static int is_known_device(struct usb_device *dev) { int index; - int max_entries = sizeof(known_devices) / sizeof(known_devices[0]); int matched_entry = 0; - for (index = 0; index < max_entries; index++) { + 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;