+ struct dev_context *devc;
+ struct sr_dev_inst *sdi;
+ struct sr_scpi_hw_info *hw_info;
+ struct sr_channel_group *cg;
+ struct sr_channel *ch;
+ const struct scpi_pps *device;
+ struct pps_channel *pch;
+ struct channel_spec *channels;
+ struct channel_group_spec *channel_groups, *cgs;
+ struct pps_channel_group *pcg;
+ GRegex *model_re;
+ GMatchInfo *model_mi;
+ GSList *l;
+ uint64_t mask;
+ unsigned int num_channels, num_channel_groups, ch_num, ch_idx, i, j;
+ int ret;
+ const char *vendor;
+ char ch_name[16];
+
+ if (get_hw_id(scpi, &hw_info) != SR_OK) {
+ sr_info("Couldn't get IDN response.");
+ return NULL;
+ }
+
+ device = NULL;
+ for (i = 0; i < num_pps_profiles; i++) {
+ vendor = sr_vendor_alias(hw_info->manufacturer);
+ if (g_ascii_strcasecmp(vendor, pps_profiles[i].vendor))
+ continue;
+ model_re = g_regex_new(pps_profiles[i].model, 0, 0, NULL);
+ if (g_regex_match(model_re, hw_info->model, 0, &model_mi))
+ device = &pps_profiles[i];
+ g_match_info_unref(model_mi);
+ g_regex_unref(model_re);
+ if (device)
+ break;
+ }
+ if (!device) {
+ sr_scpi_hw_info_free(hw_info);
+ return NULL;
+ }
+
+ sdi = g_malloc0(sizeof(struct sr_dev_inst));
+ sdi->vendor = g_strdup(vendor);
+ sdi->model = g_strdup(hw_info->model);
+ sdi->version = g_strdup(hw_info->firmware_version);
+ sdi->conn = scpi;
+ sdi->driver = &scpi_pps_driver_info;
+ sdi->inst_type = SR_INST_SCPI;
+ sdi->serial_num = g_strdup(hw_info->serial_number);
+
+ devc = g_malloc0(sizeof(struct dev_context));
+ devc->device = device;
+ sr_sw_limits_init(&devc->limits);
+ sdi->priv = devc;
+
+ if (device->num_channels) {
+ /* Static channels and groups. */
+ channels = (struct channel_spec *)device->channels;
+ num_channels = device->num_channels;
+ channel_groups = (struct channel_group_spec *)device->channel_groups;
+ num_channel_groups = device->num_channel_groups;
+ } else {
+ /* Channels and groups need to be probed. */
+ ret = device->probe_channels(sdi, hw_info, &channels, &num_channels,
+ &channel_groups, &num_channel_groups);
+ if (ret != SR_OK) {
+ sr_err("Failed to probe for channels.");
+ return NULL;
+ }
+ /*
+ * Since these were dynamically allocated, we'll need to free them
+ * later.
+ */
+ devc->channels = channels;
+ devc->channel_groups = channel_groups;
+ }
+
+ ch_idx = 0;
+ for (ch_num = 0; ch_num < num_channels; ch_num++) {
+ /* Create one channel per measurable output unit. */
+ for (i = 0; i < ARRAY_SIZE(pci); i++) {
+ if (!sr_scpi_cmd_get(devc->device->commands, pci[i].command))
+ continue;
+ g_snprintf(ch_name, 16, "%s%s", pci[i].prefix,
+ channels[ch_num].name);
+ ch = sr_channel_new(sdi, ch_idx++, SR_CHANNEL_ANALOG, TRUE,
+ ch_name);
+ pch = g_malloc0(sizeof(struct pps_channel));
+ pch->hw_output_idx = ch_num;
+ pch->hwname = channels[ch_num].name;
+ pch->mq = pci[i].mq;
+ ch->priv = pch;
+ }
+ }
+
+ for (i = 0; i < num_channel_groups; i++) {
+ cgs = &channel_groups[i];
+ cg = g_malloc0(sizeof(struct sr_channel_group));
+ cg->name = g_strdup(cgs->name);
+ for (j = 0, mask = 1; j < 64; j++, mask <<= 1) {
+ if (cgs->channel_index_mask & mask) {
+ for (l = sdi->channels; l; l = l->next) {
+ ch = l->data;
+ pch = ch->priv;
+ /* Add mqflags from channel_group_spec only to voltage
+ * and current channels.
+ */
+ if (pch->mq == SR_MQ_VOLTAGE || pch->mq == SR_MQ_CURRENT)
+ pch->mqflags = cgs->mqflags;
+ else
+ pch->mqflags = 0;
+ if (pch->hw_output_idx == j)
+ cg->channels = g_slist_append(cg->channels, ch);
+ }
+ }
+ }
+ pcg = g_malloc0(sizeof(struct pps_channel_group));
+ pcg->features = cgs->features;
+ cg->priv = pcg;
+ sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+ }
+
+ sr_scpi_hw_info_free(hw_info);
+ hw_info = NULL;
+
+ /* Don't send SCPI_CMD_LOCAL for HP 66xxB using SCPI over GPIB. */
+ if (!(devc->device->dialect == SCPI_DIALECT_HP_66XXB &&
+ scpi->transport == SCPI_TRANSPORT_LIBGPIB))
+ sr_scpi_cmd(sdi, devc->device->commands, 0, NULL, SCPI_CMD_LOCAL);
+
+ return sdi;