note that sr_usb_find_serial() is copied from the hameg-hmo driver
---
 hardware/common/scpi.c        |  68 +++++++++++++++++
 hardware/common/scpi_serial.c | 167 ++++++++++++++++++++++++++++++++++++++++++
 hardware/common/scpi_usbtmc.c |  24 ++++++
 libsigrok-internal.h          |   3 +
 4 files changed, 262 insertions(+)

diff --git a/hardware/common/scpi.c b/hardware/common/scpi.c
index 2307a8b..21ff178 100644
--- a/hardware/common/scpi.c
+++ b/hardware/common/scpi.c
@@ -87,6 +87,74 @@ static const struct sr_scpi_dev_inst *scpi_devs[] = {
 #endif
 };
 
+static GSList *sr_scpi_scan_resource(struct drv_context *drvc,
+               const char *resource, const char *serialcomm,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst 
*scpi))
+{
+       struct sr_scpi_dev_inst *scpi;
+       struct sr_dev_inst *sdi;
+
+       if (!(scpi = scpi_dev_inst_new(drvc, resource, serialcomm)))
+               return NULL;
+
+       if (sr_scpi_open(scpi) != SR_OK) {
+               sr_info("Couldn't open SCPI device.");
+               sr_scpi_free(scpi);
+               return NULL;
+       };
+
+       if ((sdi = probe_device(scpi)))
+               return g_slist_append(NULL, sdi); //FIXME list_new !!!
+
+       sr_scpi_close(scpi);
+       sr_scpi_free(scpi);
+       return NULL;
+}
+
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst 
*scpi))
+{
+       GSList *resources, *l, *d, *devices = NULL;
+       const char *resource = NULL;
+       const char *serialcomm = NULL;
+       unsigned i;
+
+       for (l = options; l; l = l->next) {
+               struct sr_config *src = l->data;
+               switch (src->key) {
+               case SR_CONF_CONN:
+                       resource = g_variant_get_string(src->data, NULL);
+                       break;
+               case SR_CONF_SERIALCOMM:
+                       serialcomm = g_variant_get_string(src->data, NULL);
+                       break;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
+               if ((resource && strcmp(resource, scpi_devs[i]->prefix))
+                   || !scpi_devs[i]->scan)
+                       continue;
+               resources = scpi_devs[i]->scan(drvc);
+               for (l = resources; l; l = l->next)
+                       if ((d = sr_scpi_scan_resource(drvc, l->data, 
serialcomm,
+                                                      probe_device)))
+                               devices = g_slist_concat(devices, d);
+               g_slist_free_full(resources, g_free);
+       }
+
+       if (!devices && resource)
+               devices = sr_scpi_scan_resource(drvc, resource, serialcomm,
+                                               probe_device);
+
+       /* Tack a copy of the newly found devices onto the driver list. */
+       if (devices)
+               drvc->instances = g_slist_concat(drvc->instances,
+                                                g_slist_copy(devices));
+
+       return devices;
+}
+
 SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
                const char *resource, const char *serialcomm)
 {
diff --git a/hardware/common/scpi_serial.c b/hardware/common/scpi_serial.c
index 6e73c89..9ab9e16 100644
--- a/hardware/common/scpi_serial.c
+++ b/hardware/common/scpi_serial.c
@@ -22,6 +22,8 @@
 #include "libsigrok-internal.h"
 
 #include <glib.h>
+#include <glib/gstdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #define LOG_PREFIX "scpi_serial"
@@ -35,6 +37,170 @@ struct scpi_serial {
        size_t read;
 };
 
+static struct {
+       uint16_t vendor_id;
+       uint16_t product_id;
+} scpi_serial_usb_ids[] = {
+       { 0x0403, 0xed72 }, /* Hameg HO720 */
+       { 0x0403, 0xed73 }, /* Hameg HO730 */
+};
+
+/**
+ * Find USB serial devices via the USB vendor ID and product ID.
+ *
+ * @param vendor_id Vendor ID of the USB device.
+ * @param product_id Product ID of the USB device.
+ *
+ * @return A GSList of strings containing the path of the serial device or
+ *         NULL if no serial device is found. The returned list must be freed
+ *         by the caller.
+ */
+static GSList *sr_usb_find_serial(uint16_t vendor_id, uint16_t product_id)
+{
+#ifdef __linux__
+       const gchar *usb_dev;
+       const char device_tree[] = "/sys/bus/usb/devices/";
+       GDir *devices_dir, *device_dir;
+       GSList *l = NULL;
+       GSList *tty_devs;
+       GSList *matched_paths;
+       FILE *fd;
+       char tmp[5];
+       gchar *vendor_path, *product_path, *path_copy;
+       gchar *prefix, *subdir_path, *device_path, *tty_path;
+       unsigned long read_vendor_id, read_product_id;
+       const char *file;
+
+       l = NULL;
+       tty_devs = NULL;
+       matched_paths = NULL;
+
+       if (!(devices_dir = g_dir_open(device_tree, 0, NULL)))
+               return NULL;
+
+       /*
+        * Find potential candidates using the vendor ID and product ID
+        * and store them in matched_paths.
+        */
+       while ((usb_dev = g_dir_read_name(devices_dir))) {
+               vendor_path = g_strconcat(device_tree,
+                                         usb_dev, "/idVendor", NULL);
+               product_path = g_strconcat(device_tree,
+                                          usb_dev, "/idProduct", NULL);
+
+               if (!g_file_test(vendor_path, G_FILE_TEST_EXISTS) ||
+                   !g_file_test(product_path, G_FILE_TEST_EXISTS))
+                       goto skip_device;
+
+               if ((fd = g_fopen(vendor_path, "r")) == NULL)
+                       goto skip_device;
+
+               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+                       fclose(fd);
+                       goto skip_device;
+               }
+               read_vendor_id = strtoul(tmp, NULL, 16);
+
+               fclose(fd);
+
+               if ((fd = g_fopen(product_path, "r")) == NULL)
+                       goto skip_device;
+
+               if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+                       fclose(fd);
+                       goto skip_device;
+               }
+               read_product_id = strtoul(tmp, NULL, 16);
+
+               fclose(fd);
+
+               if (vendor_id == read_vendor_id &&
+                   product_id == read_product_id) {
+                       path_copy = g_strdup(usb_dev);
+                       matched_paths = g_slist_prepend(matched_paths,
+                                                       path_copy);
+               }
+
+skip_device:
+               g_free(vendor_path);
+               g_free(product_path);
+       }
+       g_dir_close(devices_dir);
+
+       /* For every matched device try to find a ttyUSBX subfolder. */
+       for (l = matched_paths; l; l = l->next) {
+               subdir_path = NULL;
+
+               device_path = g_strconcat(device_tree, l->data, NULL);
+
+               if (!(device_dir = g_dir_open(device_path, 0, NULL))) {
+                       g_free(device_path);
+                       continue;
+               }
+
+               prefix = g_strconcat(l->data, ":", NULL);
+
+               while ((file = g_dir_read_name(device_dir))) {
+                       if (g_str_has_prefix(file, prefix)) {
+                               subdir_path = g_strconcat(device_path,
+                                               "/", file, NULL);
+                               break;
+                       }
+               }
+               g_dir_close(device_dir);
+
+               g_free(prefix);
+               g_free(device_path);
+
+               if (subdir_path) {
+                       if (!(device_dir = g_dir_open(subdir_path, 0, NULL))) {
+                               g_free(subdir_path);
+                               continue;
+                       }
+                       g_free(subdir_path);
+
+                       while ((file = g_dir_read_name(device_dir))) {
+                               if (g_str_has_prefix(file, "ttyUSB")) {
+                                       tty_path = g_strconcat("/dev/",
+                                                              file, NULL);
+                                       sr_dbg("Found USB device %04x:%04x 
attached to %s.",
+                                              vendor_id, product_id, tty_path);
+                                       tty_devs = g_slist_prepend(tty_devs,
+                                                       tty_path);
+                                       break;
+                               }
+                       }
+                       g_dir_close(device_dir);
+               }
+       }
+       g_slist_free_full(matched_paths, g_free);
+
+       return tty_devs;
+#else
+       (void)vendor_id;
+       (void)product_id;
+
+       return NULL;
+#endif
+}
+
+static GSList *scpi_serial_scan(struct drv_context *drvc)
+{
+       GSList *l, *resources = NULL;
+       unsigned i;
+
+       (void)drvc;
+
+       for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) {
+               if ((l = sr_usb_find_serial(scpi_serial_usb_ids[i].vendor_id,
+                                           scpi_serial_usb_ids[i].product_id)) 
== NULL)
+                       continue;
+               resources = g_slist_concat(resources, l);
+       }
+
+       return resources;
+}
+
 static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
                const char *resource, char **params, const char *serialcomm)
 {
@@ -190,6 +356,7 @@ SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
        .name          = "serial",
        .prefix        = "",
        .priv_size     = sizeof(struct scpi_serial),
+       .scan          = scpi_serial_scan,
        .dev_inst_new  = scpi_serial_dev_inst_new,
        .open          = scpi_serial_open,
        .source_add    = scpi_serial_source_add,
diff --git a/hardware/common/scpi_usbtmc.c b/hardware/common/scpi_usbtmc.c
index 6cd7964..1ffc34a 100644
--- a/hardware/common/scpi_usbtmc.c
+++ b/hardware/common/scpi_usbtmc.c
@@ -37,6 +37,29 @@ struct usbtmc_scpi {
        int response_bytes_read;
 };
 
+static GSList *scpi_usbtmc_scan(struct drv_context *drvc)
+{
+       GSList *resources = NULL;
+       GDir *dir;
+       const char *dev_name;
+       char *resource;
+
+       (void)drvc;
+
+       if (!(dir = g_dir_open("/sys/class/usbmisc/", 0, NULL)))
+               if (!(dir = g_dir_open("/sys/class/usb/", 0, NULL)))
+                       return NULL;
+       while ((dev_name = g_dir_read_name(dir))) {
+               if (strncmp(dev_name, "usbtmc", 6))
+                       continue;
+               resource = g_strconcat("/dev/", dev_name, NULL);
+               resources = g_slist_append(resources, resource);
+       }
+       g_dir_close(dir);
+
+       return resources;
+}
+
 static int scpi_usbtmc_dev_inst_new(void *priv, struct drv_context *drvc,
                const char *resource, char **params, const char *serialcomm)
 {
@@ -190,6 +213,7 @@ SR_PRIV const struct sr_scpi_dev_inst scpi_usbtmc_dev = {
        .name          = "USBTMC",
        .prefix        = "/dev/usbtmc",
        .priv_size     = sizeof(struct usbtmc_scpi),
+       .scan          = scpi_usbtmc_scan,
        .dev_inst_new  = scpi_usbtmc_dev_inst_new,
        .open          = scpi_usbtmc_open,
        .source_add    = scpi_usbtmc_source_add,
diff --git a/libsigrok-internal.h b/libsigrok-internal.h
index 951d91d..c84403a 100644
--- a/libsigrok-internal.h
+++ b/libsigrok-internal.h
@@ -438,6 +438,7 @@ struct sr_scpi_dev_inst {
        const char *name;
        const char *prefix;
        int priv_size;
+       GSList *(*scan)(struct drv_context *drvc);
        int (*dev_inst_new)(void *priv, struct drv_context *drvc,
                const char *resource, char **params, const char *serialcomm);
        int (*open)(void *priv);
@@ -453,6 +454,8 @@ struct sr_scpi_dev_inst {
        void *priv;
 };
 
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+               struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst 
*scpi));
 SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
                const char *resource, const char *serialcomm);
 SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
-- 
1.9.rc1


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121051231&iu=/4140/ostg.clktrk
_______________________________________________
sigrok-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sigrok-devel

Reply via email to